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"
16 #include "afs/sysincludes.h" /* Standard vendor system headers */
18 #include "h/syscallargs.h"
21 #include "h/sysproto.h"
23 #include "afsincludes.h" /* Afs-based standard headers */
24 #include "afs/afs_stats.h" /* afs statistics */
26 #include "afs/afs_bypasscache.h"
27 #include "rx/rx_globals.h"
29 struct VenusFid afs_rootFid;
30 afs_int32 afs_waitForever = 0;
31 short afs_waitForeverCount = 0;
32 afs_int32 afs_showflags = GAGUSER | GAGCONSOLE; /* show all messages */
35 afs_int32 afs_is_disconnected;
36 afs_int32 afs_is_discon_rw;
37 /* On reconnection, turn this knob on until it finishes,
40 afs_int32 afs_in_sync = 0;
44 * \defgroup pioctl Path IOCTL functions
46 * DECL_PIOCTL is a macro defined to contain the following parameters for functions:
48 * \param[in] avc the AFS vcache structure in use by pioctl
49 * \param[in] afun not in use
50 * \param[in] areq the AFS vrequest structure
51 * \param[in] ain as defined by the function
52 * \param[in] aout as defined by the function
53 * \param[in] ainSize size of ain
54 * \param[in] aoutSize size of aout
55 * \param[in] acred UNIX credentials structure underlying the operation
58 #define DECL_PIOCTL(x) static int x(struct vcache *avc, int afun, struct vrequest *areq, \
59 char *ain, char *aout, afs_int32 ainSize, afs_int32 *aoutSize, \
60 struct AFS_UCRED **acred)
62 /* Prototypes for pioctl routines */
65 DECL_PIOCTL(PStoreBehind);
70 DECL_PIOCTL(PGetFileCell);
71 DECL_PIOCTL(PGetWSCell);
72 DECL_PIOCTL(PGetUserCell);
73 DECL_PIOCTL(PSetTokens);
74 DECL_PIOCTL(PGetVolumeStatus);
75 DECL_PIOCTL(PSetVolumeStatus);
77 DECL_PIOCTL(PNewStatMount);
78 DECL_PIOCTL(PGetTokens);
80 DECL_PIOCTL(PMariner);
81 DECL_PIOCTL(PCheckServers);
82 DECL_PIOCTL(PCheckVolNames);
83 DECL_PIOCTL(PCheckAuth);
84 DECL_PIOCTL(PFindVolume);
85 DECL_PIOCTL(PViceAccess);
86 DECL_PIOCTL(PSetCacheSize);
87 DECL_PIOCTL(PGetCacheSize);
88 DECL_PIOCTL(PRemoveCallBack);
89 DECL_PIOCTL(PNewCell);
90 DECL_PIOCTL(PNewAlias);
91 DECL_PIOCTL(PListCells);
92 DECL_PIOCTL(PListAliases);
93 DECL_PIOCTL(PRemoveMount);
94 DECL_PIOCTL(PVenusLogging);
95 DECL_PIOCTL(PGetCellStatus);
96 DECL_PIOCTL(PSetCellStatus);
97 DECL_PIOCTL(PFlushVolumeData);
98 DECL_PIOCTL(PGetVnodeXStatus);
99 DECL_PIOCTL(PGetVnodeXStatus2);
100 DECL_PIOCTL(PSetSysName);
101 DECL_PIOCTL(PSetSPrefs);
102 DECL_PIOCTL(PSetSPrefs33);
103 DECL_PIOCTL(PGetSPrefs);
104 DECL_PIOCTL(PExportAfs);
106 DECL_PIOCTL(PTwiddleRx);
107 DECL_PIOCTL(PGetInitParams);
108 DECL_PIOCTL(PGetRxkcrypt);
109 DECL_PIOCTL(PSetRxkcrypt);
110 DECL_PIOCTL(PGetCPrefs);
111 DECL_PIOCTL(PSetCPrefs);
112 DECL_PIOCTL(PFlushMount);
113 DECL_PIOCTL(PRxStatProc);
114 DECL_PIOCTL(PRxStatPeer);
115 DECL_PIOCTL(PPrefetchFromTape);
116 DECL_PIOCTL(PResidencyCmd);
117 DECL_PIOCTL(PCallBackAddr);
118 DECL_PIOCTL(PDiscon);
119 DECL_PIOCTL(PNFSNukeCreds);
120 DECL_PIOCTL(PNewUuid);
121 DECL_PIOCTL(PPrecache);
122 #if defined(AFS_CACHE_BYPASS)
123 DECL_PIOCTL(PSetCachingThreshold);
124 DECL_PIOCTL(PSetCachingBlkSize);
128 * A macro that says whether we're going to need HandleClientContext().
129 * This is currently used only by the nfs translator.
131 #if !defined(AFS_NONFSTRANS) || defined(AFS_AIX_IAUTH_ENV)
132 #define AFS_NEED_CLIENTCONTEXT
135 /* Prototypes for private routines */
136 #ifdef AFS_NEED_CLIENTCONTEXT
137 static int HandleClientContext(struct afs_ioctl *ablob, int *com,
138 struct AFS_UCRED **acred,
139 struct AFS_UCRED *credp);
141 int HandleIoctl(register struct vcache *avc, register afs_int32 acom,
142 struct afs_ioctl *adata);
143 int afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
144 register struct afs_ioctl *ablob, int afollow,
145 struct AFS_UCRED **acred);
146 static int Prefetch(char *apath, struct afs_ioctl *adata, int afollow,
147 struct AFS_UCRED *acred);
149 typedef int (*pioctlFunction) (struct vcache *, int, struct vrequest *,
150 char *, char *, afs_int32, afs_int32 *,
151 struct AFS_UCRED **);
153 static pioctlFunction VpioctlSw[] = {
158 PGetVolumeStatus, /* 4 */
159 PSetVolumeStatus, /* 5 */
164 PCheckServers, /* 10 */
165 PCheckVolNames, /* 11 */
167 PBogus, /* 13 -- used to be quick check time */
168 PFindVolume, /* 14 */
169 PBogus, /* 15 -- prefetch is now special-cased; see pioctl code! */
170 PBogus, /* 16 -- used to be testing code */
171 PNoop, /* 17 -- used to be enable group */
172 PNoop, /* 18 -- used to be disable group */
173 PBogus, /* 19 -- used to be list group */
174 PViceAccess, /* 20 */
175 PUnlog, /* 21 -- unlog *is* unpag in this system */
176 PGetFID, /* 22 -- get file ID */
177 PBogus, /* 23 -- used to be waitforever */
178 PSetCacheSize, /* 24 */
179 PRemoveCallBack, /* 25 -- flush only the callback */
182 PRemoveMount, /* 28 -- delete mount point */
183 PNewStatMount, /* 29 -- new style mount point stat */
184 PGetFileCell, /* 30 -- get cell name for input file */
185 PGetWSCell, /* 31 -- get cell name for workstation */
186 PMariner, /* 32 - set/get mariner host */
187 PGetUserCell, /* 33 -- get cell name for user */
188 PVenusLogging, /* 34 -- Enable/Disable logging */
189 PGetCellStatus, /* 35 */
190 PSetCellStatus, /* 36 */
191 PFlushVolumeData, /* 37 -- flush all data from a volume */
192 PSetSysName, /* 38 - Set system name */
193 PExportAfs, /* 39 - Export Afs to remote nfs clients */
194 PGetCacheSize, /* 40 - get cache size and usage */
195 PGetVnodeXStatus, /* 41 - get vcache's special status */
196 PSetSPrefs33, /* 42 - Set CM Server preferences... */
197 PGetSPrefs, /* 43 - Get CM Server preferences... */
198 PGag, /* 44 - turn off/on all CM messages */
199 PTwiddleRx, /* 45 - adjust some RX params */
200 PSetSPrefs, /* 46 - Set CM Server preferences... */
201 PStoreBehind, /* 47 - set degree of store behind to be done */
202 PGCPAGs, /* 48 - disable automatic pag gc-ing */
203 PGetInitParams, /* 49 - get initial cm params */
204 PGetCPrefs, /* 50 - get client interface addresses */
205 PSetCPrefs, /* 51 - set client interface addresses */
206 PFlushMount, /* 52 - flush mount symlink data */
207 PRxStatProc, /* 53 - control process RX statistics */
208 PRxStatPeer, /* 54 - control peer RX statistics */
209 PGetRxkcrypt, /* 55 -- Get rxkad encryption flag */
210 PSetRxkcrypt, /* 56 -- Set rxkad encryption flag */
211 PBogus, /* 57 -- arla: set file prio */
212 PBogus, /* 58 -- arla: fallback getfh */
213 PBogus, /* 59 -- arla: fallback fhopen */
214 PBogus, /* 60 -- arla: controls xfsdebug */
215 PBogus, /* 61 -- arla: controls arla debug */
216 PBogus, /* 62 -- arla: debug interface */
217 PBogus, /* 63 -- arla: print xfs status */
218 PBogus, /* 64 -- arla: force cache check */
219 PBogus, /* 65 -- arla: break callback */
220 PPrefetchFromTape, /* 66 -- MR-AFS: prefetch file from tape */
221 PResidencyCmd, /* 67 -- MR-AFS: generic commnd interface */
222 PBogus, /* 68 -- arla: fetch stats */
223 PGetVnodeXStatus2, /* 69 - get caller access and some vcache status */
226 static pioctlFunction CpioctlSw[] = {
228 PNewAlias, /* 1 -- create new cell alias */
229 PListAliases, /* 2 -- list cell aliases */
230 PCallBackAddr, /* 3 -- request addr for callback rxcon */
232 PDiscon, /* 5 -- get/set discon mode */
242 static int (*(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->states |= CSafeStore;
270 /* case 2 used to be abort store, but this is no longer provided,
271 * since it is impossible to implement under normal Unix.
275 /* return the name of the cell this file is open on */
276 register struct cell *tcell;
277 register afs_int32 i;
279 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
281 i = strlen(tcell->cellName) + 1; /* bytes to copy out */
283 if (i > adata->out_size) {
284 /* 0 means we're not interested in the output */
285 if (adata->out_size != 0)
289 AFS_COPYOUT(tcell->cellName, adata->out, i, code);
291 afs_PutCell(tcell, READ_LOCK);
297 case 49: /* VIOC_GETINITPARAMS */
298 if (adata->out_size < sizeof(struct cm_initparams)) {
301 AFS_COPYOUT(&cm_initParams, adata->out,
302 sizeof(struct cm_initparams), code);
314 return code; /* so far, none implemented */
319 /* For aix we don't temporarily bypass ioctl(2) but rather do our
320 * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
321 * is now called from afs_gn_ioctl.
324 afs_ioctl(struct vcache *tvc, int cmd, int arg)
326 struct afs_ioctl data;
329 AFS_STATCNT(afs_ioctl);
330 if (((cmd >> 8) & 0xff) == 'V') {
331 /* This is a VICEIOCTL call */
332 AFS_COPYIN(arg, (caddr_t) & data, sizeof(data), error);
335 error = HandleIoctl(tvc, cmd, &data);
338 /* No-op call; just return. */
342 #endif /* AFS_AIX_ENV */
344 #if defined(AFS_SGI_ENV)
345 afs_ioctl(OSI_VN_DECL(tvc), int cmd, void *arg, int flag, cred_t * cr,
348 , struct vopbd * vbds
352 struct afs_ioctl data;
358 AFS_STATCNT(afs_ioctl);
359 if (((cmd >> 8) & 0xff) == 'V') {
360 /* This is a VICEIOCTL call */
361 error = copyin_afs_ioctl(arg, &data);
364 locked = ISAFS_GLOCK();
367 error = HandleIoctl(tvc, cmd, &data);
372 /* No-op call; just return. */
376 #endif /* AFS_SGI_ENV */
378 /* unlike most calls here, this one uses u.u_error to return error conditions,
379 since this is really an intercepted chapter 2 call, rather than a vnode
382 /* AFS_HPUX102 and up uses VNODE ioctl instead */
383 #if !defined(AFS_HPUX102_ENV) && !defined(AFS_DARWIN80_ENV)
384 #if !defined(AFS_SGI_ENV)
389 kioctl(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
391 #else /* __64BIT__ */
393 kioctl32(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
395 #endif /* __64BIT__ */
398 kioctl(int fdes, int com, caddr_t arg, caddr_t ext)
407 } u_uap, *uap = &u_uap;
409 #if defined(AFS_SUN5_ENV)
411 struct afs_ioctl_sys {
418 afs_xioctl(struct afs_ioctl_sys *uap, rval_t *rvp)
420 #elif defined(AFS_OSF_ENV)
422 afs_xioctl(struct proc *p, void *args, long *retval)
428 } *uap = (struct a *)args;
429 #elif defined(AFS_FBSD50_ENV)
432 afs_xioctl(struct thread *td, register struct ioctl_args *uap,
435 struct proc *p = td->td_proc;
436 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
444 afs_xioctl(struct proc *p, register struct ioctl_args *uap, register_t *retval)
446 #elif defined(AFS_LINUX22_ENV)
447 struct afs_ioctl_sys {
452 afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
455 struct afs_ioctl_sys ua, *uap = &ua;
464 } *uap = (struct a *)u.u_ap;
465 #endif /* AFS_SUN5_ENV */
467 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
469 #elif !defined(AFS_LINUX22_ENV)
470 register struct file *fd;
472 #if defined(AFS_XBSD_ENV)
473 register struct filedesc *fdp;
475 register struct vcache *tvc;
476 register int ioctlDone = 0, code = 0;
478 AFS_STATCNT(afs_xioctl);
479 #if defined(AFS_DARWIN_ENV)
480 if ((code = fdgetf(p, uap->fd, &fd)))
482 #elif defined(AFS_XBSD_ENV)
484 if ((u_int) uap->fd >= fdp->fd_nfiles
485 || (fd = fdp->fd_ofiles[uap->fd]) == NULL)
487 if ((fd->f_flag & (FREAD | FWRITE)) == 0)
489 #elif defined(AFS_LINUX22_ENV)
492 #elif defined(AFS_AIX32_ENV)
500 if (setuerror(getf(uap->fd, &fd))) {
503 #elif defined(AFS_OSF_ENV)
505 if (code = getf(&fd, uap->fd, FILE_FLAGS_NULL, &u.u_file_state))
507 #elif defined(AFS_SUN5_ENV)
508 # if defined(AFS_SUN57_ENV)
512 # elif defined(AFS_SUN54_ENV)
517 if (code = getf(uap->fd, &fd)) {
520 # endif /* AFS_SUN57_ENV */
526 /* first determine whether this is any sort of vnode */
527 #if defined(AFS_LINUX22_ENV)
532 if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
534 if (fd->f_type == DTYPE_VNODE) {
536 /* good, this is a vnode; next see if it is an AFS vnode */
537 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
538 tvc = VTOAFS(fd->f_vnode); /* valid, given a vnode */
539 #elif defined(AFS_OBSD_ENV)
541 IsAfsVnode((struct vnode *)fd->
542 f_data) ? VTOAFS((struct vnode *)fd->f_data) : NULL;
544 tvc = VTOAFS((struct vnode *)fd->f_data); /* valid, given a vnode */
546 #endif /* AFS_LINUX22_ENV */
547 if (tvc && IsAfsVnode(AFSTOV(tvc))) {
548 /* This is an AFS vnode */
549 if (((uap->com >> 8) & 0xff) == 'V') {
550 register struct afs_ioctl *datap;
553 (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
554 code=copyin_afs_ioctl((char *)uap->arg, datap);
556 osi_FreeSmallSpace(datap);
558 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
561 #if defined(AFS_SUN5_ENV)
576 #else /* AFS_OSF_ENV */
580 #ifdef AFS_LINUX22_ENV
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)
685 #endif /* AFS_SGI_ENV */
686 #endif /* AFS_HPUX102_ENV */
688 #if defined(AFS_SGI_ENV)
689 /* "pioctl" system call entry point; just pass argument to the parameterized
698 afs_pioctl(struct pioctlargs *uap, rval_t * rvp)
702 AFS_STATCNT(afs_pioctl);
704 code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
713 #elif defined(AFS_OSF_ENV)
714 afs_pioctl(struct proc *p, void *args, int *retval)
721 } *uap = (struct a *)args;
723 AFS_STATCNT(afs_pioctl);
724 return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow));
727 #elif defined(AFS_FBSD50_ENV)
729 afs_pioctl(struct thread *td, void *args, int *retval)
736 } *uap = (struct a *)args;
738 AFS_STATCNT(afs_pioctl);
739 return (afs_syscall_pioctl
740 (uap->path, uap->cmd, uap->cmarg, uap->follow, td->td_ucred));
743 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
745 afs_pioctl(struct proc *p, void *args, int *retval)
752 } *uap = (struct a *)args;
754 AFS_STATCNT(afs_pioctl);
755 #ifdef AFS_DARWIN80_ENV
756 return (afs_syscall_pioctl
757 (uap->path, uap->cmd, uap->cmarg, uap->follow,
760 return (afs_syscall_pioctl
761 (uap->path, uap->cmd, uap->cmarg, uap->follow,
762 p->p_cred->pc_ucred));
768 /* macro to avoid adding any more #ifdef's to pioctl code. */
769 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
770 #define PIOCTL_FREE_CRED() crfree(credp)
772 #define PIOCTL_FREE_CRED()
777 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
778 rval_t *vvp, struct AFS_UCRED *credp)
780 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
781 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
782 struct AFS_UCRED *credp)
784 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
788 struct afs_ioctl data;
789 #ifdef AFS_NEED_CLIENTCONTEXT
790 struct AFS_UCRED *tmpcred = NULL;
792 struct AFS_UCRED *foreigncreds = NULL;
793 register afs_int32 code = 0;
794 struct vnode *vp = NULL;
796 struct ucred *credp = crref(); /* don't free until done! */
798 #ifdef AFS_LINUX22_ENV
799 cred_t *credp = crref(); /* don't free until done! */
803 AFS_STATCNT(afs_syscall_pioctl);
805 follow = 1; /* compat. with old venus */
806 code = copyin_afs_ioctl(cmarg, &data);
809 #if defined(KERNEL_HAVE_UERROR)
814 if ((com & 0xff) == PSetClientContext) {
815 #ifdef AFS_NEED_CLIENTCONTEXT
816 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
817 code = HandleClientContext(&data, &com, &foreigncreds, credp);
819 code = HandleClientContext(&data, &com, &foreigncreds, osi_curcred());
823 crfree(foreigncreds);
826 #if defined(KERNEL_HAVE_UERROR)
827 return (setuerror(code), code);
832 #else /* AFS_NEED_CLIENTCONTEXT */
834 #endif /* AFS_NEED_CLIENTCONTEXT */
836 #ifdef AFS_NEED_CLIENTCONTEXT
839 * We could have done without temporary setting the u.u_cred below
840 * (foreigncreds could be passed as param the pioctl modules)
841 * but calls such as afs_osi_suser() doesn't allow that since it
842 * references u.u_cred directly. We could, of course, do something
843 * like afs_osi_suser(cred) which, I think, is better since it
844 * generalizes and supports multi cred environments...
846 #if defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
848 credp = foreigncreds;
849 #elif defined(AFS_AIX41_ENV)
850 tmpcred = crref(); /* XXX */
852 #elif defined(AFS_HPUX101_ENV)
853 tmpcred = p_cred(u.u_procp);
854 set_p_cred(u.u_procp, foreigncreds);
855 #elif defined(AFS_SGI_ENV)
856 tmpcred = OSI_GET_CURRENT_CRED();
857 OSI_SET_CURRENT_CRED(foreigncreds);
860 u.u_cred = foreigncreds;
863 #endif /* AFS_NEED_CLIENTCONTEXT */
864 if ((com & 0xff) == 15) {
865 /* special case prefetch so entire pathname eval occurs in helper process.
866 * otherwise, the pioctl call is essentially useless */
867 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
869 Prefetch(path, &data, follow,
870 foreigncreds ? foreigncreds : credp);
872 code = Prefetch(path, &data, follow, osi_curcred());
875 #if defined(KERNEL_HAVE_UERROR)
884 lookupname(path, USR, follow, NULL, &vp,
885 foreigncreds ? foreigncreds : credp);
887 #ifdef AFS_LINUX22_ENV
888 code = gop_lookupname(path, AFS_UIOUSER, follow, &dp);
890 vp = (struct vnode *)dp->d_inode;
892 code = gop_lookupname(path, AFS_UIOUSER, follow, &vp);
893 #endif /* AFS_LINUX22_ENV */
894 #endif /* AFS_AIX41_ENV */
898 #if defined(KERNEL_HAVE_UERROR)
906 #if defined(AFS_SUN510_ENV)
907 if (vp && !IsAfsVnode(vp)) {
908 struct vnode *realvp;
910 #ifdef AFS_SUN511_ENV
911 (VOP_REALVP(vp, &realvp, NULL) == 0)
913 (VOP_REALVP(vp, &realvp) == 0)
916 struct vnode *oldvp = vp;
924 /* now make the call if we were passed no file, or were passed an AFS file */
925 if (!vp || IsAfsVnode(vp)) {
926 #if defined(AFS_SUN5_ENV)
927 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
928 #elif defined(AFS_AIX41_ENV)
930 struct ucred *cred1, *cred2;
933 cred1 = cred2 = foreigncreds;
935 cred1 = cred2 = credp;
937 code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
938 if (cred1 != cred2) {
939 /* something changed the creds */
943 #elif defined(AFS_HPUX101_ENV)
945 struct ucred *cred = p_cred(u.u_procp);
946 code = afs_HandlePioctl(vp, com, &data, follow, &cred);
948 #elif defined(AFS_SGI_ENV)
951 credp = OSI_GET_CURRENT_CRED();
952 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
954 #elif defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
955 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
957 code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
960 #if defined(KERNEL_HAVE_UERROR)
963 code = EINVAL; /* not in /afs */
968 #if defined(AFS_NEED_CLIENTCONTEXT)
971 crset(tmpcred); /* restore original credentials */
973 #if defined(AFS_HPUX101_ENV)
974 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
975 #elif defined(AFS_SGI_ENV)
976 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
977 #elif defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
978 credp = tmpcred; /* restore original credentials */
980 osi_curcred() = tmpcred; /* restore original credentials */
981 #endif /* AFS_HPUX101_ENV */
982 crfree(foreigncreds);
985 #endif /* AFS_NEED_CLIENTCONTEXT */
987 #ifdef AFS_LINUX22_ENV
990 AFS_RELE(vp); /* put vnode back */
994 #if defined(KERNEL_HAVE_UERROR)
997 return (getuerror());
1003 #define MAXPIOCTLTOKENLEN \
1004 (3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
1007 afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
1008 register struct afs_ioctl *ablob, int afollow,
1009 struct AFS_UCRED **acred)
1012 struct vrequest treq;
1013 register afs_int32 code;
1014 register afs_int32 function, device;
1015 afs_int32 inSize, outSize, outSizeMax;
1016 char *inData, *outData;
1017 pioctlFunction *pioctlSw;
1019 struct afs_fakestat_state fakestate;
1021 avc = avp ? VTOAFS(avp) : NULL;
1022 afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
1023 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
1024 AFS_STATCNT(HandlePioctl);
1025 if ((code = afs_InitReq(&treq, *acred)))
1027 afs_InitFakeStat(&fakestate);
1029 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
1031 afs_PutFakeStat(&fakestate);
1035 device = (acom & 0xff00) >> 8;
1037 case 'V': /* Original pioctls */
1038 pioctlSw = VpioctlSw;
1039 pioctlSwSize = sizeof(VpioctlSw);
1041 case 'C': /* Coordinated/common pioctls */
1042 pioctlSw = CpioctlSw;
1043 pioctlSwSize = sizeof(CpioctlSw);
1045 case 'O': /* Coordinated/common pioctls */
1046 pioctlSw = OpioctlSw;
1047 pioctlSwSize = sizeof(OpioctlSw);
1050 afs_PutFakeStat(&fakestate);
1053 function = acom & 0xff;
1054 if (function >= (pioctlSwSize / sizeof(char *))) {
1055 afs_PutFakeStat(&fakestate);
1056 return EINVAL; /* out of range */
1058 inSize = ablob->in_size;
1060 /* Do all range checking before continuing */
1061 if (inSize > MAXPIOCTLTOKENLEN || inSize < 0 || ablob->out_size < 0)
1064 /* Note that we use osi_Alloc for large allocs and osi_AllocLargeSpace for small ones */
1065 if (inSize > AFS_LRALLOCSIZ) {
1066 inData = osi_Alloc(inSize + 1);
1068 inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1073 AFS_COPYIN(ablob->in, inData, inSize, code);
1074 inData[inSize] = '\0';
1078 if (inSize > AFS_LRALLOCSIZ) {
1079 osi_Free(inData, inSize + 1);
1081 osi_FreeLargeSpace(inData);
1083 afs_PutFakeStat(&fakestate);
1086 if (function == 8 && device == 'V') { /* PGetTokens */
1087 outSizeMax = MAXPIOCTLTOKENLEN;
1088 outData = osi_Alloc(outSizeMax);
1090 outSizeMax = AFS_LRALLOCSIZ;
1091 outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1094 if (inSize > AFS_LRALLOCSIZ) {
1095 osi_Free(inData, inSize + 1);
1097 osi_FreeLargeSpace(inData);
1099 afs_PutFakeStat(&fakestate);
1104 (*pioctlSw[function]) (avc, function, &treq, inData, outData, inSize,
1106 if (inSize > AFS_LRALLOCSIZ) {
1107 osi_Free(inData, inSize + 1);
1109 osi_FreeLargeSpace(inData);
1111 if (code == 0 && ablob->out_size > 0) {
1112 if (outSize > ablob->out_size) {
1113 code = E2BIG; /* data wont fit in user buffer */
1114 } else if (outSize) {
1115 AFS_COPYOUT(outData, ablob->out, outSize, code);
1118 if (outSizeMax > AFS_LRALLOCSIZ) {
1119 osi_Free(outData, outSizeMax);
1121 osi_FreeLargeSpace(outData);
1123 afs_PutFakeStat(&fakestate);
1124 return afs_CheckCode(code, &treq, 41);
1128 * VIOCGETFID (22) - Get file ID quickly
1132 * \param[in] ain not in use
1133 * \param[out] aout fid of requested file
1135 * \retval EINVAL Error if some of the initial arguments aren't set
1137 * \post get the file id of some file
1139 DECL_PIOCTL(PGetFID)
1141 AFS_STATCNT(PGetFID);
1144 memcpy(aout, (char *)&avc->fid, sizeof(struct VenusFid));
1145 *aoutSize = sizeof(struct VenusFid);
1150 * VIOCSETAL (1) - Set access control list
1154 * \param[in] ain the ACL being set
1155 * \param[out] aout the ACL being set returned
1157 * \retval EINVAL Error if some of the standard args aren't set
1159 * \post Changed ACL, via direct writing to the wire
1161 int dummy_PSetAcl(char *ain, char *aout)
1166 DECL_PIOCTL(PSetAcl)
1168 register afs_int32 code;
1169 struct afs_conn *tconn;
1170 struct AFSOpaque acl;
1171 struct AFSVolSync tsync;
1172 struct AFSFetchStatus OutStatus;
1175 AFS_STATCNT(PSetAcl);
1178 if ((acl.AFSOpaque_len = strlen(ain) + 1) > 1024 /* AFSOPAQUEMAX */)
1181 acl.AFSOpaque_val = ain;
1183 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1185 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1188 RXAFS_StoreACL(tconn->id, (struct AFSFid *)&avc->fid.Fid,
1189 &acl, &OutStatus, &tsync);
1194 } while (afs_Analyze
1195 (tconn, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_STOREACL,
1196 SHARED_LOCK, NULL));
1198 /* now we've forgotten all of the access info */
1199 ObtainWriteLock(&afs_xcbhash, 455);
1201 afs_DequeueCallback(avc);
1202 avc->states &= ~(CStatd | CUnique);
1203 ReleaseWriteLock(&afs_xcbhash);
1204 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1205 osi_dnlc_purgedp(avc);
1209 int afs_defaultAsynchrony = 0;
1212 * VIOC_STOREBEHIND (47) Adjust store asynchrony
1216 * \param[in] ain sbstruct (store behind structure) input
1217 * \param[out] aout resulting sbstruct
1219 * \retval EPERM Error if the user doesn't have super-user credentials
1220 * \retval EACCES Error if there isn't enough access to not check the mode bits
1222 * \post sets asynchrony based on a file, from a struct sbstruct "I THINK"
1224 DECL_PIOCTL(PStoreBehind)
1227 struct sbstruct *sbr;
1229 sbr = (struct sbstruct *)ain;
1230 if (sbr->sb_default != -1) {
1231 if (afs_osi_suser(*acred))
1232 afs_defaultAsynchrony = sbr->sb_default;
1237 if (avc && (sbr->sb_thisfile != -1)) {
1239 (avc, PRSFS_WRITE | PRSFS_ADMINISTER, areq, DONT_CHECK_MODE_BITS))
1240 avc->asynchrony = sbr->sb_thisfile;
1245 *aoutSize = sizeof(struct sbstruct);
1246 sbr = (struct sbstruct *)aout;
1247 sbr->sb_default = afs_defaultAsynchrony;
1249 sbr->sb_thisfile = avc->asynchrony;
1256 * VIOC_GCPAGS (48) - Disable automatic PAG gc'ing
1260 * \param[in] ain not in use
1261 * \param[out] aout not in use
1263 * \retval EACCES Error if the user doesn't have super-user credentials
1265 * \post set the gcpags to GCPAGS_USERDISABLED
1267 DECL_PIOCTL(PGCPAGs)
1269 if (!afs_osi_suser(*acred)) {
1272 afs_gcpags = AFS_GCPAGS_USERDISABLED;
1277 * VIOCGETAL (2) - Get access control list
1281 * \param[in] ain not in use
1282 * \param[out] aout the ACL
1284 * \retval EINVAL Error if some of the standard args aren't set
1285 * \retval ERANGE Error if the vnode of the file id is too large
1286 * \retval -1 Error if getting the ACL failed
1288 * \post Obtain the ACL, based on file ID
1290 * \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
1292 DECL_PIOCTL(PGetAcl)
1294 struct AFSOpaque acl;
1295 struct AFSVolSync tsync;
1296 struct AFSFetchStatus OutStatus;
1298 struct afs_conn *tconn;
1302 AFS_STATCNT(PGetAcl);
1305 Fid.Volume = avc->fid.Fid.Volume;
1306 Fid.Vnode = avc->fid.Fid.Vnode;
1307 Fid.Unique = avc->fid.Fid.Unique;
1308 if (avc->states & CForeign) {
1310 * For a dfs xlator acl we have a special hack so that the
1311 * xlator will distinguish which type of acl will return. So
1312 * we currently use the top 2-bytes (vals 0-4) to tell which
1313 * type of acl to bring back. Horrible hack but this will
1314 * cause the least number of changes to code size and interfaces.
1316 if (Fid.Vnode & 0xc0000000)
1318 Fid.Vnode |= (ainSize << 30);
1320 acl.AFSOpaque_val = aout;
1322 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1325 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1327 code = RXAFS_FetchACL(tconn->id, &Fid, &acl, &OutStatus, &tsync);
1332 } while (afs_Analyze
1333 (tconn, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_FETCHACL,
1334 SHARED_LOCK, NULL));
1337 *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1343 * PNoop returns success. Used for functions which are not implemented or are no longer in use.
1347 * \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
1356 * PBogus returns fail. Used for functions which are not implemented or are no longer in use.
1360 * \retval EINVAL Error if some of the standard args aren't set
1362 * \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;
1366 AFS_STATCNT(PBogus);
1371 * VIOC_FILE_CELL_NAME (30) - Get cell in which file lives
1375 * \param[in] ain not in use (avc used to pass in file id)
1376 * \param[out] aout cell name
1378 * \retval EINVAL Error if some of the standard args aren't set
1379 * \retval ESRCH Error if the file isn't part of a cell
1381 * \post Get a cell based on a passed in file id
1383 DECL_PIOCTL(PGetFileCell)
1385 register struct cell *tcell;
1387 AFS_STATCNT(PGetFileCell);
1390 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
1393 strcpy(aout, tcell->cellName);
1394 afs_PutCell(tcell, READ_LOCK);
1395 *aoutSize = strlen(aout) + 1;
1400 * VIOC_GET_WS_CELL (31) - Get cell in which workstation lives
1404 * \param[in] ain not in use
1405 * \param[out] aout cell name
1407 * \retval EIO Error if the afs daemon hasn't started yet
1408 * \retval ESRCH Error if the machine isn't part of a cell, for whatever reason
1410 * \post Get the primary cell that the machine is a part of.
1412 DECL_PIOCTL(PGetWSCell)
1414 struct cell *tcell = NULL;
1416 AFS_STATCNT(PGetWSCell);
1417 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1418 return EIO; /* Inappropriate ioctl for device */
1420 tcell = afs_GetPrimaryCell(READ_LOCK);
1421 if (!tcell) /* no primary cell? */
1423 strcpy(aout, tcell->cellName);
1424 *aoutSize = strlen(aout) + 1;
1425 afs_PutCell(tcell, READ_LOCK);
1430 * VIOC_GET_PRIMARY_CELL (33) - Get primary cell for caller
1434 * \param[in] ain not in use (user id found via areq)
1435 * \param[out] aout cell name
1437 * \retval ESRCH Error if the user id doesn't have a primary cell specified
1439 * \post Get the primary cell for a certain user, based on the user's uid
1441 DECL_PIOCTL(PGetUserCell)
1443 register afs_int32 i;
1444 register struct unixuser *tu;
1445 register struct cell *tcell;
1447 AFS_STATCNT(PGetUserCell);
1448 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1449 return EIO; /* Inappropriate ioctl for device */
1451 /* return the cell name of the primary cell for this user */
1452 i = UHash(areq->uid);
1453 ObtainWriteLock(&afs_xuser, 224);
1454 for (tu = afs_users[i]; tu; tu = tu->next) {
1455 if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1457 ReleaseWriteLock(&afs_xuser);
1462 tcell = afs_GetCell(tu->cell, READ_LOCK);
1463 afs_PutUser(tu, WRITE_LOCK);
1467 strcpy(aout, tcell->cellName);
1468 afs_PutCell(tcell, READ_LOCK);
1469 *aoutSize = strlen(aout) + 1; /* 1 for the null */
1472 ReleaseWriteLock(&afs_xuser);
1480 * VIOCSETTOK (3) - Set authentication tokens
1484 * \param[in] ain the krb tickets from which to set the afs tokens
1485 * \param[out] aout not in use
1487 * \retval EINVAL Error if the ticket is either too long or too short
1488 * \retval EIO Error if the AFS initState is below 101
1489 * \retval ESRCH Error if the cell for which the Token is being set can't be found
1491 * \post Set the Tokens for a specific cell name, unless there is none set, then default to primary
1494 DECL_PIOCTL(PSetTokens)
1497 register struct unixuser *tu;
1498 struct ClearToken clear;
1499 register struct cell *tcell;
1502 struct vrequest treq;
1503 afs_int32 flag, set_parent_pag = 0;
1505 AFS_STATCNT(PSetTokens);
1506 if (!afs_resourceinit_flag) {
1509 memcpy((char *)&i, ain, sizeof(afs_int32));
1510 ain += sizeof(afs_int32);
1511 stp = ain; /* remember where the ticket is */
1512 if (i < 0 || i > MAXKTCTICKETLEN)
1513 return EINVAL; /* malloc may fail */
1515 ain += i; /* skip over ticket */
1516 memcpy((char *)&i, ain, sizeof(afs_int32));
1517 ain += sizeof(afs_int32);
1518 if (i != sizeof(struct ClearToken)) {
1521 memcpy((char *)&clear, ain, sizeof(struct ClearToken));
1522 if (clear.AuthHandle == -1)
1523 clear.AuthHandle = 999; /* more rxvab compat stuff */
1524 ain += sizeof(struct ClearToken);
1525 if (ainSize != 2 * sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1526 /* still stuff left? we've got primary flag and cell name. Set these */
1527 memcpy((char *)&flag, ain, sizeof(afs_int32)); /* primary id flag */
1528 ain += sizeof(afs_int32); /* skip id field */
1529 /* rest is cell name, look it up */
1530 /* some versions of gcc appear to need != 0 in order to get this right */
1531 if ((flag & 0x8000) != 0) { /* XXX Use Constant XXX */
1535 tcell = afs_GetCellByName(ain, READ_LOCK);
1539 /* default to primary cell, primary id */
1540 flag = 1; /* primary id */
1541 tcell = afs_GetPrimaryCell(READ_LOCK);
1546 afs_PutCell(tcell, READ_LOCK);
1547 if (set_parent_pag) {
1549 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1550 #if defined(AFS_DARWIN_ENV)
1551 struct proc *p = current_proc(); /* XXX */
1553 struct proc *p = curproc; /* XXX */
1555 #ifndef AFS_DARWIN80_ENV
1556 uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1557 p->p_pid, p->p_comm);
1559 if (!setpag(p, acred, -1, &pag, 1)) {
1562 if (!setpag(u.u_procp, acred, -1, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
1564 if (!setpag(acred, -1, &pag, 1)) {
1567 afs_InitReq(&treq, *acred);
1571 /* now we just set the tokens */
1572 tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1573 tu->vid = clear.ViceId;
1574 if (tu->stp != NULL) {
1575 afs_osi_Free(tu->stp, tu->stLen);
1577 tu->stp = (char *)afs_osi_Alloc(stLen);
1578 if (tu->stp == NULL) {
1582 memcpy(tu->stp, stp, stLen);
1585 afs_stats_cmfullperf.authent.TicketUpdates++;
1586 afs_ComputePAGStats();
1587 #endif /* AFS_NOSTATS */
1588 tu->states |= UHasTokens;
1589 tu->states &= ~UTokensBad;
1590 afs_SetPrimary(tu, flag);
1591 tu->tokenTime = osi_Time();
1592 afs_ResetUserConns(tu);
1593 afs_PutUser(tu, WRITE_LOCK);
1609 * VIOCGETVOLSTAT (4) - Get volume status
1613 * \param[in] ain not in use
1614 * \param[out] aout status of the volume
1616 * \retval EINVAL Error if some of the standard args aren't set
1618 * \post The status of a volume (based on the FID of the volume), or an offline message /motd
1620 DECL_PIOCTL(PGetVolumeStatus)
1623 char *offLineMsg = afs_osi_Alloc(256);
1624 char *motd = afs_osi_Alloc(256);
1625 register struct afs_conn *tc;
1626 register afs_int32 code = 0;
1627 struct AFSFetchVolumeStatus volstat;
1629 char *Name, *OfflineMsg, *MOTD;
1632 AFS_STATCNT(PGetVolumeStatus);
1638 OfflineMsg = offLineMsg;
1641 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1643 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1646 RXAFS_GetVolumeStatus(tc->id, avc->fid.Fid.Volume, &volstat,
1647 &Name, &OfflineMsg, &MOTD);
1652 } while (afs_Analyze
1653 (tc, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1654 SHARED_LOCK, NULL));
1658 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1660 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1661 cp += sizeof(VolumeStatus);
1662 strcpy(cp, volName);
1663 cp += strlen(volName) + 1;
1664 strcpy(cp, offLineMsg);
1665 cp += strlen(offLineMsg) + 1;
1667 cp += strlen(motd) + 1;
1668 *aoutSize = (cp - aout);
1670 afs_osi_Free(offLineMsg, 256);
1671 afs_osi_Free(motd, 256);
1676 * VIOCSETVOLSTAT (5) - Set volume status
1680 * \param[in] ain values to set the status at, offline message, message of the day, volume name, minimum quota, maximum quota
1681 * \param[out] aout status of a volume, offlines messages, minimum quota, maximumm quota
1683 * \retval EINVAL Error if some of the standard args aren't set
1684 * \retval EROFS Error if the volume is read only, or a backup volume
1685 * \retval ENODEV Error if the volume can't be accessed
1686 * \retval E2BIG Error if the volume name, offline message, and motd are too big
1688 * \post Set the status of a volume, including any offline messages, a minimum quota, and a maximum quota
1690 DECL_PIOCTL(PSetVolumeStatus)
1693 char *offLineMsg = afs_osi_Alloc(256);
1694 char *motd = afs_osi_Alloc(256);
1695 register struct afs_conn *tc;
1696 register afs_int32 code = 0;
1697 struct AFSFetchVolumeStatus volstat;
1698 struct AFSStoreVolumeStatus storeStat;
1699 register struct volume *tvp;
1703 AFS_STATCNT(PSetVolumeStatus);
1709 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
1711 if (tvp->states & (VRO | VBackup)) {
1712 afs_PutVolume(tvp, READ_LOCK);
1716 afs_PutVolume(tvp, READ_LOCK);
1721 /* Copy the junk out, using cp as a roving pointer. */
1723 memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
1724 cp += sizeof(AFSFetchVolumeStatus);
1725 if (strlen(cp) >= sizeof(volName)) {
1729 strcpy(volName, cp);
1730 cp += strlen(volName) + 1;
1731 if (strlen(cp) >= sizeof(offLineMsg)) {
1735 strcpy(offLineMsg, cp);
1736 cp += strlen(offLineMsg) + 1;
1737 if (strlen(cp) >= sizeof(motd)) {
1743 if (volstat.MinQuota != -1) {
1744 storeStat.MinQuota = volstat.MinQuota;
1745 storeStat.Mask |= AFS_SETMINQUOTA;
1747 if (volstat.MaxQuota != -1) {
1748 storeStat.MaxQuota = volstat.MaxQuota;
1749 storeStat.Mask |= AFS_SETMAXQUOTA;
1752 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1754 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1757 RXAFS_SetVolumeStatus(tc->id, avc->fid.Fid.Volume, &storeStat,
1758 volName, offLineMsg, motd);
1763 } while (afs_Analyze
1764 (tc, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1765 SHARED_LOCK, NULL));
1769 /* we are sending parms back to make compat. with prev system. should
1770 * change interface later to not ask for current status, just set new status */
1772 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1773 cp += sizeof(VolumeStatus);
1774 strcpy(cp, volName);
1775 cp += strlen(volName) + 1;
1776 strcpy(cp, offLineMsg);
1777 cp += strlen(offLineMsg) + 1;
1779 cp += strlen(motd) + 1;
1780 *aoutSize = cp - aout;
1782 afs_osi_Free(offLineMsg, 256);
1783 afs_osi_Free(motd, 256);
1788 * VIOCFLUSH (6) - Invalidate cache entry
1792 * \param[in] ain not in use
1793 * \param[out] aout not in use
1795 * \retval EINVAL Error if some of the standard args aren't set
1797 * \post Flush any information the cache manager has on an entry
1801 AFS_STATCNT(PFlush);
1804 #ifdef AFS_BOZONLOCK_ENV
1805 afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
1807 ObtainWriteLock(&avc->lock, 225);
1808 afs_ResetVCache(avc, *acred);
1809 ReleaseWriteLock(&avc->lock);
1810 #ifdef AFS_BOZONLOCK_ENV
1811 afs_BozonUnlock(&avc->pvnLock, avc);
1817 * VIOC_AFS_STAT_MT_PT (29) - Stat mount point
1821 * \param[in] ain the last component in a path, related to mountpoint that we're looking for information about
1822 * \param[out] aout volume, cell, link data
1824 * \retval EINVAL Error if some of the standard args aren't set
1825 * \retval ENOTDIR Error if the 'mount point' argument isn't a directory
1826 * \retval EIO Error if the link data can't be accessed
1828 * \post Get the volume, and cell, as well as the link data for a mount point
1830 DECL_PIOCTL(PNewStatMount)
1832 register afs_int32 code;
1833 register struct vcache *tvc;
1834 register struct dcache *tdc;
1835 struct VenusFid tfid;
1837 struct sysname_info sysState;
1838 afs_size_t offset, len;
1840 AFS_STATCNT(PNewStatMount);
1843 code = afs_VerifyVCache(avc, areq);
1846 if (vType(avc) != VDIR) {
1849 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
1852 Check_AtSys(avc, ain, &sysState, areq);
1853 ObtainReadLock(&tdc->lock);
1855 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
1856 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1857 ReleaseReadLock(&tdc->lock);
1858 afs_PutDCache(tdc); /* we're done with the data */
1859 bufp = sysState.name;
1863 tfid.Cell = avc->fid.Cell;
1864 tfid.Fid.Volume = avc->fid.Fid.Volume;
1865 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
1866 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
1868 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
1874 if (tvc->mvstat != 1) {
1879 ObtainWriteLock(&tvc->lock, 226);
1880 code = afs_HandleLink(tvc, areq);
1882 if (tvc->linkData) {
1883 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1886 /* we have the data */
1887 strcpy(aout, tvc->linkData);
1888 *aoutSize = strlen(tvc->linkData) + 1;
1893 ReleaseWriteLock(&tvc->lock);
1896 if (sysState.allocked)
1897 osi_FreeLargeSpace(bufp);
1902 * VIOCGETTOK (8) - Get authentication tokens
1906 * \param[in] ain userid
1907 * \param[out] aout token
1909 * \retval EIO Error if the afs daemon hasn't started yet
1910 * \retval EDOM Error if the input parameter is out of the bounds of the available tokens
1911 * \retval ENOTCONN Error if there aren't tokens for this cell
1913 * \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
1915 * \notes "it's a weird interface (from comments in the code)"
1918 DECL_PIOCTL(PGetTokens)
1920 register struct cell *tcell;
1921 register afs_int32 i;
1922 register struct unixuser *tu;
1927 AFS_STATCNT(PGetTokens);
1928 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1929 return EIO; /* Inappropriate ioctl for device */
1931 /* weird interface. If input parameter is present, it is an integer and
1932 * we're supposed to return the parm'th tokens for this unix uid.
1933 * If not present, we just return tokens for cell 1.
1934 * If counter out of bounds, return EDOM.
1935 * If no tokens for the particular cell, return ENOTCONN.
1936 * Also, if this mysterious parm is present, we return, along with the
1937 * tokens, the primary cell indicator (an afs_int32 0) and the cell name
1938 * at the end, in that order.
1940 if ((newStyle = (ainSize > 0))) {
1941 memcpy((char *)&iterator, ain, sizeof(afs_int32));
1943 i = UHash(areq->uid);
1944 ObtainReadLock(&afs_xuser);
1945 for (tu = afs_users[i]; tu; tu = tu->next) {
1947 if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1948 if (iterator-- == 0)
1949 break; /* are we done yet? */
1952 if (tu->uid == areq->uid && afs_IsPrimaryCellNum(tu->cell))
1958 * No need to hold a read lock on each user entry
1962 ReleaseReadLock(&afs_xuser);
1967 if (((tu->states & UHasTokens) == 0)
1968 || (tu->ct.EndTimestamp < osi_Time())) {
1969 tu->states |= (UTokensBad | UNeedsReset);
1970 afs_PutUser(tu, READ_LOCK);
1973 /* use iterator for temp */
1975 iterator = tu->stLen; /* for compat, we try to return 56 byte tix if they fit */
1977 iterator = 56; /* # of bytes we're returning */
1978 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1979 cp += sizeof(afs_int32);
1980 memcpy(cp, tu->stp, tu->stLen); /* copy out st */
1982 iterator = sizeof(struct ClearToken);
1983 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1984 cp += sizeof(afs_int32);
1985 memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
1986 cp += sizeof(struct ClearToken);
1988 /* put out primary id and cell name, too */
1989 iterator = (tu->states & UPrimary ? 1 : 0);
1990 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1991 cp += sizeof(afs_int32);
1992 tcell = afs_GetCell(tu->cell, READ_LOCK);
1994 strcpy(cp, tcell->cellName);
1995 cp += strlen(tcell->cellName) + 1;
1996 afs_PutCell(tcell, READ_LOCK);
2000 *aoutSize = cp - aout;
2001 afs_PutUser(tu, READ_LOCK);
2006 * VIOCUNLOG (9) - Invalidate tokens
2010 * \param[in] ain not in use
2011 * \param[out] aout not in use
2013 * \retval EIO Error if the afs daemon hasn't been started yet
2015 * \post remove tokens from a user, specified by the user id
2017 * \notes sets the token's time to 0, which then causes it to be removed
2018 * \notes Unlog is the same as un-pag in OpenAFS
2022 register afs_int32 i;
2023 register struct unixuser *tu;
2025 AFS_STATCNT(PUnlog);
2026 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2027 return EIO; /* Inappropriate ioctl for device */
2029 i = UHash(areq->uid);
2030 ObtainWriteLock(&afs_xuser, 227);
2031 for (tu = afs_users[i]; tu; tu = tu->next) {
2032 if (tu->uid == areq->uid) {
2034 tu->states &= ~UHasTokens;
2035 /* security is not having to say you're sorry */
2036 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
2038 ReleaseWriteLock(&afs_xuser);
2039 /* We have to drop the lock over the call to afs_ResetUserConns, since
2040 * it obtains the afs_xvcache lock. We could also keep the lock, and
2041 * modify ResetUserConns to take parm saying we obtained the lock
2042 * already, but that is overkill. By keeping the "tu" pointer
2043 * held over the released lock, we guarantee that we won't lose our
2044 * place, and that we'll pass over every user conn that existed when
2045 * we began this call.
2047 afs_ResetUserConns(tu);
2049 ObtainWriteLock(&afs_xuser, 228);
2051 /* set the expire times to 0, causes
2052 * afs_GCUserData to remove this entry
2054 tu->ct.EndTimestamp = 0;
2056 #endif /* UKERNEL */
2059 ReleaseWriteLock(&afs_xuser);
2064 * VIOC_AFS_MARINER_HOST (32) - Get/set mariner (cache manager monitor) host
2068 * \param[in] ain host address to be set
2069 * \param[out] aout old host address
2071 * \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
2073 * \notes Errors turn off mariner
2075 DECL_PIOCTL(PMariner)
2077 afs_int32 newHostAddr;
2078 afs_int32 oldHostAddr;
2080 AFS_STATCNT(PMariner);
2082 memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost,
2085 oldHostAddr = 0xffffffff; /* disabled */
2087 memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
2088 if (newHostAddr == 0xffffffff) {
2089 /* disable mariner operations */
2091 } else if (newHostAddr) {
2093 afs_marinerHost = newHostAddr;
2095 memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
2096 *aoutSize = sizeof(afs_int32);
2101 * VIOCCKSERV (10) - Check that servers are up
2105 * \param[in] ain name of the cell
2106 * \param[out] aout current down server list
2108 * \retval EIO Error if the afs daemon hasn't started yet
2109 * \retval EACCES Error if the user doesn't have super-user credentials
2110 * \retval ENOENT Error if we are unable to obtain the cell
2112 * \post Either a fast check (where it doesn't contact servers) or a local check (checks local cell only)
2114 DECL_PIOCTL(PCheckServers)
2116 register char *cp = 0;
2118 register struct server *ts;
2119 afs_int32 temp, *lp = (afs_int32 *) ain, havecell = 0;
2121 struct chservinfo *pcheck;
2123 AFS_STATCNT(PCheckServers);
2125 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2126 return EIO; /* Inappropriate ioctl for device */
2128 if (*lp == 0x12345678) { /* For afs3.3 version */
2129 pcheck = (struct chservinfo *)ain;
2130 if (pcheck->tinterval >= 0) {
2132 memcpy(cp, (char *)&afs_probe_interval, sizeof(afs_int32));
2133 *aoutSize = sizeof(afs_int32);
2134 if (pcheck->tinterval > 0) {
2135 if (!afs_osi_suser(*acred))
2137 afs_probe_interval = pcheck->tinterval;
2143 temp = pcheck->tflags;
2144 cp = pcheck->tbuffer;
2145 } else { /* For pre afs3.3 versions */
2146 memcpy((char *)&temp, ain, sizeof(afs_int32));
2147 cp = ain + sizeof(afs_int32);
2148 if (ainSize > sizeof(afs_int32))
2153 * 1: fast check, don't contact servers.
2154 * 2: local cell only.
2157 /* have cell name, too */
2158 cellp = afs_GetCellByName(cp, READ_LOCK);
2163 if (!cellp && (temp & 2)) {
2164 /* use local cell */
2165 cellp = afs_GetPrimaryCell(READ_LOCK);
2167 if (!(temp & 1)) { /* if not fast, call server checker routine */
2168 afs_CheckServers(1, cellp); /* check down servers */
2169 afs_CheckServers(0, cellp); /* check up servers */
2171 /* now return the current down server list */
2173 ObtainReadLock(&afs_xserver);
2174 for (i = 0; i < NSERVERS; i++) {
2175 for (ts = afs_servers[i]; ts; ts = ts->next) {
2176 if (cellp && ts->cell != cellp)
2177 continue; /* cell spec'd and wrong */
2178 if ((ts->flags & SRVR_ISDOWN)
2179 && ts->addr->sa_portal != ts->cell->vlport) {
2180 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2181 cp += sizeof(afs_int32);
2185 ReleaseReadLock(&afs_xserver);
2187 afs_PutCell(cellp, READ_LOCK);
2188 *aoutSize = cp - aout;
2193 * VIOCCKBACK (11) - Check backup volume mappings
2197 * \param[in] ain not in use
2198 * \param[out] aout not in use
2200 * \retval EIO Error if the afs daemon hasn't started yet
2202 * \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
2204 DECL_PIOCTL(PCheckVolNames)
2206 AFS_STATCNT(PCheckVolNames);
2207 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2208 return EIO; /* Inappropriate ioctl for device */
2210 afs_CheckRootVolume();
2211 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE | AFS_VOLCHECK_EXPIRED |
2212 AFS_VOLCHECK_BUSY | AFS_VOLCHECK_MTPTS);
2217 * VIOCCKCONN (12) - Check connections for a user
2221 * \param[in] ain not in use
2222 * \param[out] aout not in use
2224 * \retval EACCESS Error if no user is specififed, the user has no tokens set, or if the user's tokens are bad
2226 * \post check to see if a user has the correct authentication. If so, allow access.
2228 * \notes Check the connections to all the servers specified
2230 DECL_PIOCTL(PCheckAuth)
2234 struct afs_conn *tc;
2235 struct unixuser *tu;
2238 AFS_STATCNT(PCheckAuth);
2239 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2240 return EIO; /* Inappropriate ioctl for device */
2243 tu = afs_GetUser(areq->uid, 1, READ_LOCK); /* check local cell authentication */
2247 /* we have a user */
2248 ObtainReadLock(&afs_xsrvAddr);
2249 ObtainReadLock(&afs_xconn);
2251 /* any tokens set? */
2252 if ((tu->states & UHasTokens) == 0)
2254 /* all connections in cell 1 working? */
2255 for (i = 0; i < NSERVERS; i++) {
2256 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2257 for (tc = sa->conns; tc; tc = tc->next) {
2258 if (tc->user == tu && (tu->states & UTokensBad))
2263 ReleaseReadLock(&afs_xsrvAddr);
2264 ReleaseReadLock(&afs_xconn);
2265 afs_PutUser(tu, READ_LOCK);
2267 memcpy(aout, (char *)&retValue, sizeof(afs_int32));
2268 *aoutSize = sizeof(afs_int32);
2273 Prefetch(char *apath, struct afs_ioctl *adata, int afollow,
2274 struct AFS_UCRED *acred)
2277 register afs_int32 code;
2278 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
2284 AFS_STATCNT(Prefetch);
2287 tp = osi_AllocLargeSpace(1024);
2288 AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2290 osi_FreeLargeSpace(tp);
2293 if (afs_BBusy()) { /* do this as late as possible */
2294 osi_FreeLargeSpace(tp);
2295 return EWOULDBLOCK; /* pretty close */
2297 afs_BQueue(BOP_PATH, (struct vcache *)0, 0, 0, acred, (afs_size_t) 0,
2298 (afs_size_t) 0, tp);
2303 * VIOCWHEREIS (14) - Find out where a volume is located
2307 * \param[in] ain not in use
2308 * \param[out] aout volume location
2310 * \retval EINVAL Error if some of the default arguments don't exist
2311 * \retval ENODEV Error if there is no such volume
2313 * \post fine a volume, based on a volume file id
2315 * \notes check each of the servers specified
2317 DECL_PIOCTL(PFindVolume)
2319 register struct volume *tvp;
2320 register struct server *ts;
2321 register afs_int32 i;
2324 AFS_STATCNT(PFindVolume);
2327 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
2330 for (i = 0; i < MAXHOSTS; i++) {
2331 ts = tvp->serverHost[i];
2334 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2335 cp += sizeof(afs_int32);
2338 /* still room for terminating NULL, add it on */
2339 ainSize = 0; /* reuse vbl */
2340 memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
2341 cp += sizeof(afs_int32);
2343 *aoutSize = cp - aout;
2344 afs_PutVolume(tvp, READ_LOCK);
2351 * VIOCACCESS (20) - Access using PRS_FS bits
2355 * \param[in] ain PRS_FS bits
2356 * \param[out] aout not in use
2358 * \retval EINVAL Error if some of the initial arguments aren't set
2359 * \retval EACCES Error if access is denied
2361 * \post check to make sure access is allowed
2363 DECL_PIOCTL(PViceAccess)
2365 register afs_int32 code;
2368 AFS_STATCNT(PViceAccess);
2371 code = afs_VerifyVCache(avc, areq);
2374 memcpy((char *)&temp, ain, sizeof(afs_int32));
2375 code = afs_AccessOK(avc, temp, areq, CHECK_MODE_BITS);
2382 DECL_PIOCTL(PPrecache)
2386 /*AFS_STATCNT(PPrecache);*/
2387 if (!afs_osi_suser(*acred))
2389 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2390 afs_preCache = newValue*1024;
2395 * VIOCSETCACHESIZE (24) - Set venus cache size in 1000 units
2399 * \param[in] ain the size the venus cache should be set to
2400 * \param[out] aout not in use
2402 * \retval EACCES Error if the user doesn't have super-user credentials
2403 * \retval EROFS Error if the cache is set to be in memory
2405 * \post Set the cache size based on user input. If no size is given, set it to the default OpenAFS cache size.
2407 * \notes recompute the general cache parameters for every single block allocated
2409 DECL_PIOCTL(PSetCacheSize)
2414 AFS_STATCNT(PSetCacheSize);
2415 if (!afs_osi_suser(*acred))
2417 /* too many things are setup initially in mem cache version */
2418 if (cacheDiskType == AFS_FCACHE_TYPE_MEM)
2420 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2422 afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2424 if (newValue < afs_min_cache)
2425 afs_cacheBlocks = afs_min_cache;
2427 afs_cacheBlocks = newValue;
2429 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2430 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2431 afs_MaybeWakeupTruncateDaemon();
2432 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2433 afs_osi_Wait(1000, 0, 0);
2434 afs_MaybeWakeupTruncateDaemon();
2439 #define MAXGCSTATS 16
2441 * VIOCGETCACHEPARMS (40) - Get cache stats
2445 * \param[in] ain afs index flags
2446 * \param[out] aout cache blocks, blocks used, blocks files (in an array)
2448 * \post Get the cache blocks, and how many of the cache blocks there are
2450 DECL_PIOCTL(PGetCacheSize)
2452 afs_int32 results[MAXGCSTATS];
2454 register struct dcache * tdc;
2457 AFS_STATCNT(PGetCacheSize);
2459 if (sizeof(afs_int32) == ainSize){
2460 memcpy((char *)&flags, ain, sizeof(afs_int32));
2461 } else if (0 == ainSize){
2467 memset((char *)results, 0, sizeof(results));
2468 results[0] = afs_cacheBlocks;
2469 results[1] = afs_blocksUsed;
2470 results[2] = afs_cacheFiles;
2473 for (i = 0; i < afs_cacheFiles; i++) {
2474 if (afs_indexFlags[i] & IFFree) results[3]++;
2476 } else if (2 == flags){
2477 for (i = 0; i < afs_cacheFiles; i++) {
2478 if (afs_indexFlags[i] & IFFree) results[3]++;
2479 if (afs_indexFlags[i] & IFEverUsed) results[4]++;
2480 if (afs_indexFlags[i] & IFDataMod) results[5]++;
2481 if (afs_indexFlags[i] & IFDirtyPages) results[6]++;
2482 if (afs_indexFlags[i] & IFAnyPages) results[7]++;
2483 if (afs_indexFlags[i] & IFDiscarded) results[8]++;
2485 tdc = afs_indexTable[i];
2488 size = tdc->validPos;
2489 if ( 0 < size && size < (1<<12) ) results[10]++;
2490 else if (size < (1<<14) ) results[11]++;
2491 else if (size < (1<<16) ) results[12]++;
2492 else if (size < (1<<18) ) results[13]++;
2493 else if (size < (1<<20) ) results[14]++;
2494 else if (size >= (1<<20) ) results[15]++;
2498 memcpy(aout, (char *)results, sizeof(results));
2499 *aoutSize = sizeof(results);
2504 * VIOCFLUSHCB (25) - Flush callback only
2508 * \param[in] ain not in use
2509 * \param[out] aout not in use
2511 * \retval EINVAL Error if some of the standard args aren't set
2512 * \retval 0 0 returned if the volume is set to read-only
2514 * \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.
2516 DECL_PIOCTL(PRemoveCallBack)
2518 register struct afs_conn *tc;
2519 register afs_int32 code = 0;
2520 struct AFSCallBack CallBacks_Array[1];
2521 struct AFSCBFids theFids;
2522 struct AFSCBs theCBs;
2525 AFS_STATCNT(PRemoveCallBack);
2528 if (avc->states & CRO)
2529 return 0; /* read-only-ness can't change */
2530 ObtainWriteLock(&avc->lock, 229);
2531 theFids.AFSCBFids_len = 1;
2532 theCBs.AFSCBs_len = 1;
2533 theFids.AFSCBFids_val = (struct AFSFid *)&avc->fid.Fid;
2534 theCBs.AFSCBs_val = CallBacks_Array;
2535 CallBacks_Array[0].CallBackType = CB_DROPPED;
2536 if (avc->callback) {
2538 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2540 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2542 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2546 /* don't set code on failure since we wouldn't use it */
2547 } while (afs_Analyze
2548 (tc, code, &avc->fid, areq,
2549 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK, NULL));
2551 ObtainWriteLock(&afs_xcbhash, 457);
2552 afs_DequeueCallback(avc);
2554 avc->states &= ~(CStatd | CUnique);
2555 ReleaseWriteLock(&afs_xcbhash);
2556 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2557 osi_dnlc_purgedp(avc);
2559 ReleaseWriteLock(&avc->lock);
2564 * VIOCNEWCELL (26) - Configure new cell
2568 * \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
2569 * \param[out] aout not in use
2571 * \retval EIO Error if the afs daemon hasn't started yet
2572 * \retval EACCES Error if the user doesn't have super-user cedentials
2573 * \retval EINVAL Error if some 'magic' var doesn't have a certain bit set
2575 * \post creates a new cell
2577 DECL_PIOCTL(PNewCell)
2579 /* create a new cell */
2580 afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic = 0;
2581 char *newcell = 0, *linkedcell = 0, *tp = ain;
2582 register afs_int32 code, linkedstate = 0, ls;
2583 u_short fsport = 0, vlport = 0;
2586 AFS_STATCNT(PNewCell);
2587 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2588 return EIO; /* Inappropriate ioctl for device */
2590 if (!afs_osi_suser(*acred))
2593 memcpy((char *)&magic, tp, sizeof(afs_int32));
2594 tp += sizeof(afs_int32);
2595 if (magic != 0x12345678)
2598 /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2599 * server addresses while the 3.5 fs newcell command passes
2600 * MAXHOSTS. To figure out which is which, check if the cellname
2603 newcell = tp + (MAXCELLHOSTS + 3) * sizeof(afs_int32);
2604 scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2606 /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2607 memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
2608 tp += (scount * sizeof(afs_int32));
2610 lp = (afs_int32 *) tp;
2614 fsport = 0; /* Privileged ports not allowed */
2616 vlport = 0; /* Privileged ports not allowed */
2617 tp += (3 * sizeof(afs_int32));
2619 if ((ls = *lp) & 1) {
2620 linkedcell = tp + strlen(newcell) + 1;
2621 linkedstate |= CLinkedCell;
2624 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2626 afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport,
2631 DECL_PIOCTL(PNewAlias)
2633 /* create a new cell alias */
2635 register afs_int32 code;
2636 char *realName, *aliasName;
2638 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2639 return EIO; /* Inappropriate ioctl for device */
2641 if (!afs_osi_suser(*acred))
2645 tp += strlen(aliasName) + 1;
2648 code = afs_NewCellAlias(aliasName, realName);
2654 * VIOCGETCELL (27) - Get cell info
2658 * \param[in] ain The cell index of a specific cell
2659 * \param[out] aout list of servers in the cell
2661 * \retval EIO Error if the afs daemon hasn't started yet
2662 * \retval EDOM Error if there is no cell asked about
2664 * \post Lists the cell's server names and and addresses
2666 DECL_PIOCTL(PListCells)
2668 afs_int32 whichCell;
2669 register struct cell *tcell = 0;
2670 register afs_int32 i;
2671 register char *cp, *tp = ain;
2673 AFS_STATCNT(PListCells);
2674 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2675 return EIO; /* Inappropriate ioctl for device */
2677 memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2678 tp += sizeof(afs_int32);
2679 tcell = afs_GetCellByIndex(whichCell, READ_LOCK);
2682 memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
2683 for (i = 0; i < MAXCELLHOSTS; i++) {
2684 if (tcell->cellHosts[i] == 0)
2686 memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip,
2688 cp += sizeof(afs_int32);
2690 cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2691 strcpy(cp, tcell->cellName);
2692 cp += strlen(tcell->cellName) + 1;
2693 *aoutSize = cp - aout;
2694 afs_PutCell(tcell, READ_LOCK);
2702 DECL_PIOCTL(PListAliases)
2704 afs_int32 whichAlias;
2705 register struct cell_alias *tcalias = 0;
2706 register char *cp, *tp = ain;
2708 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2709 return EIO; /* Inappropriate ioctl for device */
2710 if (ainSize < sizeof(afs_int32))
2713 memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2714 tp += sizeof(afs_int32);
2716 tcalias = afs_GetCellAlias(whichAlias);
2719 strcpy(cp, tcalias->alias);
2720 cp += strlen(tcalias->alias) + 1;
2721 strcpy(cp, tcalias->cell);
2722 cp += strlen(tcalias->cell) + 1;
2723 *aoutSize = cp - aout;
2724 afs_PutCellAlias(tcalias);
2733 * VIOC_AFS_DELETE_MT_PT (28) - Delete mount point
2737 * \param[in] ain the name of the file in this dir to remove
2738 * \param[out] aout not in use
2740 * \retval EINVAL Error if some of the standard args aren't set
2741 * \retval ENOTDIR Error if the argument to remove is not a directory
2742 * \retval ENOENT Error if there is no cache to remove the mount point from or if a vcache doesn't exist
2744 * \post Ensure that everything is OK before deleting the mountpoint. If not, don't delete. Delete a mount point based on a file id.
2746 DECL_PIOCTL(PRemoveMount)
2748 register afs_int32 code;
2750 struct sysname_info sysState;
2751 afs_size_t offset, len;
2752 register struct afs_conn *tc;
2753 register struct dcache *tdc;
2754 register struct vcache *tvc;
2755 struct AFSFetchStatus OutDirStatus;
2756 struct VenusFid tfid;
2757 struct AFSVolSync tsync;
2761 /* "ain" is the name of the file in this dir to remove */
2763 AFS_STATCNT(PRemoveMount);
2766 code = afs_VerifyVCache(avc, areq);
2769 if (vType(avc) != VDIR)
2772 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1); /* test for error below */
2775 Check_AtSys(avc, ain, &sysState, areq);
2776 ObtainReadLock(&tdc->lock);
2778 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
2779 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2780 ReleaseReadLock(&tdc->lock);
2781 bufp = sysState.name;
2786 tfid.Cell = avc->fid.Cell;
2787 tfid.Fid.Volume = avc->fid.Fid.Volume;
2788 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
2789 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
2791 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
2798 if (tvc->mvstat != 1) {
2804 ObtainWriteLock(&tvc->lock, 230);
2805 code = afs_HandleLink(tvc, areq);
2807 if (tvc->linkData) {
2808 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2813 ReleaseWriteLock(&tvc->lock);
2814 osi_dnlc_purgedp(tvc);
2820 ObtainWriteLock(&avc->lock, 231);
2821 osi_dnlc_remove(avc, bufp, tvc);
2823 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2825 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2828 RXAFS_RemoveFile(tc->id, (struct AFSFid *)&avc->fid.Fid, bufp,
2829 &OutDirStatus, &tsync);
2834 } while (afs_Analyze
2835 (tc, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_REMOVEFILE,
2836 SHARED_LOCK, NULL));
2841 ReleaseWriteLock(&avc->lock);
2845 /* we have the thing in the cache */
2846 ObtainWriteLock(&tdc->lock, 661);
2847 if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2848 /* we can do it locally */
2849 code = afs_dir_Delete(tdc, bufp);
2851 ZapDCE(tdc); /* surprise error -- invalid value */
2855 ReleaseWriteLock(&tdc->lock);
2856 afs_PutDCache(tdc); /* drop ref count */
2858 avc->states &= ~CUnique; /* For the dfs xlator */
2859 ReleaseWriteLock(&avc->lock);
2862 if (sysState.allocked)
2863 osi_FreeLargeSpace(bufp);
2868 * VIOC_VENUSLOG (34) - Enable/Disable venus logging
2872 * \retval EINVAL Error if some of the standard args aren't set
2874 * \notes Obsoleted, perhaps should be PBogus
2876 DECL_PIOCTL(PVenusLogging)
2878 return EINVAL; /* OBSOLETE */
2882 * VIOC_GETCELLSTATUS (35) - Get cell status info
2886 * \param[in] ain The cell you want status information on
2887 * \param[out] aout cell state (as a struct)
2889 * \retval EIO Error if the afs daemon hasn't started yet
2890 * \retval ENOENT Error if the cell doesn't exist
2892 * \post Returns the state of the cell as defined in a struct cell
2894 DECL_PIOCTL(PGetCellStatus)
2896 register struct cell *tcell;
2899 AFS_STATCNT(PGetCellStatus);
2900 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2901 return EIO; /* Inappropriate ioctl for device */
2903 tcell = afs_GetCellByName(ain, READ_LOCK);
2906 temp = tcell->states;
2907 afs_PutCell(tcell, READ_LOCK);
2908 memcpy(aout, (char *)&temp, sizeof(afs_int32));
2909 *aoutSize = sizeof(afs_int32);
2914 * VIOC_SETCELLSTATUS (36) - Set corresponding info
2918 * \param[in] ain The cell you want to set information about, and the values you want to set
2919 * \param[out] aout not in use
2921 * \retval EIO Error if the afs daemon hasn't started yet
2922 * \retval EACCES Error if the user doesn't have super-user credentials
2924 * \post Set the state of the cell in a defined struct cell, based on whether or not SetUID is allowed
2926 DECL_PIOCTL(PSetCellStatus)
2928 register struct cell *tcell;
2931 if (!afs_osi_suser(*acred))
2933 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2934 return EIO; /* Inappropriate ioctl for device */
2936 tcell = afs_GetCellByName(ain + 2 * sizeof(afs_int32), WRITE_LOCK);
2939 memcpy((char *)&temp, ain, sizeof(afs_int32));
2941 tcell->states |= CNoSUID;
2943 tcell->states &= ~CNoSUID;
2944 afs_PutCell(tcell, WRITE_LOCK);
2949 * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
2953 * \param[in] ain not in use (args in avc)
2954 * \param[out] aout not in use
2956 * \retval EINVAL Error if some of the standard args aren't set
2957 * \retval EIO Error if the afs daemon hasn't started yet
2959 * \post Wipe everything on the volume. This is done dependent on which platform this is for.
2961 * \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.
2963 DECL_PIOCTL(PFlushVolumeData)
2965 register afs_int32 i;
2966 register struct dcache *tdc;
2967 register struct vcache *tvc;
2968 register struct volume *tv;
2969 afs_int32 cell, volume;
2970 struct afs_q *tq, *uq;
2971 #ifdef AFS_DARWIN80_ENV
2975 AFS_STATCNT(PFlushVolumeData);
2978 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2979 return EIO; /* Inappropriate ioctl for device */
2981 volume = avc->fid.Fid.Volume; /* who to zap */
2982 cell = avc->fid.Cell;
2985 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
2986 * the vcaches associated with the volume.
2989 ObtainReadLock(&afs_xvcache);
2990 i = VCHashV(&avc->fid);
2991 for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
2994 if (tvc->fid.Fid.Volume == volume && tvc->fid.Cell == cell) {
2995 if (tvc->states & CVInit) {
2996 ReleaseReadLock(&afs_xvcache);
2997 afs_osi_Sleep(&tvc->states);
3000 #ifdef AFS_DARWIN80_ENV
3001 if (tvc->states & CDeadVnode) {
3002 ReleaseReadLock(&afs_xvcache);
3003 afs_osi_Sleep(&tvc->states);
3007 #if defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
3008 VN_HOLD(AFSTOV(tvc));
3010 #ifdef AFS_DARWIN80_ENV
3014 if (vnode_ref(vp)) {
3021 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
3024 VREFCOUNT_INC(tvc); /* AIX, apparently */
3028 ReleaseReadLock(&afs_xvcache);
3029 #ifdef AFS_BOZONLOCK_ENV
3030 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3032 ObtainWriteLock(&tvc->lock, 232);
3034 ObtainWriteLock(&afs_xcbhash, 458);
3035 afs_DequeueCallback(tvc);
3036 tvc->states &= ~(CStatd | CDirty);
3037 ReleaseWriteLock(&afs_xcbhash);
3038 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
3039 osi_dnlc_purgedp(tvc);
3040 afs_TryToSmush(tvc, *acred, 1);
3041 ReleaseWriteLock(&tvc->lock);
3042 #ifdef AFS_BOZONLOCK_ENV
3043 afs_BozonUnlock(&tvc->pvnLock, tvc);
3045 #ifdef AFS_DARWIN80_ENV
3046 vnode_put(AFSTOV(tvc));
3048 ObtainReadLock(&afs_xvcache);
3050 /* our tvc ptr is still good until now */
3054 ReleaseReadLock(&afs_xvcache);
3057 MObtainWriteLock(&afs_xdcache, 328); /* needed if you're going to flush any stuff */
3058 for (i = 0; i < afs_cacheFiles; i++) {
3059 if (!(afs_indexFlags[i] & IFEverUsed))
3060 continue; /* never had any data */
3061 tdc = afs_GetDSlot(i, NULL);
3062 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
3063 ReleaseReadLock(&tdc->tlock);
3064 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
3065 if (!(afs_indexFlags[i] & IFDataMod)) {
3066 /* if the file is modified, but has a ref cnt of only 1, then
3067 * someone probably has the file open and is writing into it.
3068 * Better to skip flushing such a file, it will be brought back
3069 * immediately on the next write anyway.
3071 * If we *must* flush, then this code has to be rearranged to call
3072 * afs_storeAllSegments() first */
3073 afs_FlushDCache(tdc);
3077 ReleaseReadLock(&tdc->tlock);
3079 afs_PutDCache(tdc); /* bumped by getdslot */
3081 MReleaseWriteLock(&afs_xdcache);
3083 ObtainReadLock(&afs_xvolume);
3084 for (i = 0; i < NVOLS; i++) {
3085 for (tv = afs_volumes[i]; tv; tv = tv->next) {
3086 if (tv->volume == volume) {
3087 afs_ResetVolumeInfo(tv);
3092 ReleaseReadLock(&afs_xvolume);
3094 /* probably, a user is doing this, probably, because things are screwed up.
3095 * maybe it's the dnlc's fault? */
3102 * VIOCGETVCXSTATUS (41) - gets vnode x status
3106 * \param[in] ain not in use (avc used)
3107 * \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
3109 * \retval EINVAL Error if some of the initial default arguments aren't set
3110 * \retval EACCES Error if access to check the mode bits is denied
3112 * \post gets stats for the vnode, a struct listed in vcxstat
3114 DECL_PIOCTL(PGetVnodeXStatus)
3116 register afs_int32 code;
3117 struct vcxstat stat;
3120 /* AFS_STATCNT(PGetVnodeXStatus); */
3123 code = afs_VerifyVCache(avc, areq);
3126 if (vType(avc) == VDIR)
3127 mode = PRSFS_LOOKUP;
3130 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3133 memset(&stat, 0, sizeof(struct vcxstat));
3134 stat.fid = avc->fid;
3135 hset32(stat.DataVersion, hgetlo(avc->m.DataVersion));
3136 stat.lock = avc->lock;
3137 stat.parentVnode = avc->parentVnode;
3138 stat.parentUnique = avc->parentUnique;
3139 hset(stat.flushDV, avc->flushDV);
3140 hset(stat.mapDV, avc->mapDV);
3141 stat.truncPos = avc->truncPos;
3142 { /* just grab the first two - won't break anything... */
3143 struct axscache *ac;
3145 for (i = 0, ac = avc->Access; ac && i < CPSIZE; i++, ac = ac->next) {
3146 stat.randomUid[i] = ac->uid;
3147 stat.randomAccess[i] = ac->axess;
3150 stat.callback = afs_data_pointer_to_int32(avc->callback);
3151 stat.cbExpires = avc->cbExpires;
3152 stat.anyAccess = avc->anyAccess;
3153 stat.opens = avc->opens;
3154 stat.execsOrWriters = avc->execsOrWriters;
3155 stat.flockCount = avc->flockCount;
3156 stat.mvstat = avc->mvstat;
3157 stat.states = avc->states;
3158 memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
3159 *aoutSize = sizeof(struct vcxstat);
3164 DECL_PIOCTL(PGetVnodeXStatus2)
3166 register afs_int32 code;
3167 struct vcxstat2 stat;
3172 code = afs_VerifyVCache(avc, areq);
3175 if (vType(avc) == VDIR)
3176 mode = PRSFS_LOOKUP;
3179 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3182 memset(&stat, 0, sizeof(struct vcxstat2));
3184 stat.cbExpires = avc->cbExpires;
3185 stat.anyAccess = avc->anyAccess;
3186 stat.mvstat = avc->mvstat;
3187 stat.callerAccess = afs_GetAccessBits(avc, ~0, areq);
3189 memcpy(aout, (char *)&stat, sizeof(struct vcxstat2));
3190 *aoutSize = sizeof(struct vcxstat2);
3196 * VIOC_AFS_SYSNAME (38) - Change @sys value
3200 * \param[in] ain new value for @sys
3201 * \param[out] aout count, entry, list (debug values?)
3203 * \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"
3204 * \retval ENODEV Error if there isn't already a system named that ("I THINK")
3205 * \retval EACCES Error if the user doesn't have super-user credentials
3207 * \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
3209 * \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.
3211 DECL_PIOCTL(PSetSysName)
3213 char *cp, *cp2 = NULL, inname[MAXSYSNAME], outname[MAXSYSNAME];
3214 afs_int32 setsysname;
3216 register struct afs_exporter *exporter;
3217 register struct unixuser *au;
3218 register afs_int32 pag, error;
3219 int t, count, num = 0, allpags = 0;
3222 AFS_STATCNT(PSetSysName);
3223 if (!afs_globalVFS) {
3224 /* Afsd is NOT running; disable it */
3225 #if defined(KERNEL_HAVE_UERROR)
3226 return (setuerror(EINVAL), EINVAL);
3231 memset(inname, 0, MAXSYSNAME);
3232 memcpy(&setsysname, ain, sizeof(afs_int32));
3233 ain += sizeof(afs_int32);
3234 if (setsysname & 0x8000) {
3236 setsysname &= ~0x8000;
3241 if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
3244 for (cp = ain, count = 0; count < setsysname; count++) {
3245 /* won't go past end of ain since maxsysname*num < ain length */
3247 if (t >= MAXSYSNAME || t <= 0)
3249 /* check for names that can shoot us in the foot */
3250 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
3256 /* inname gets first entry in case we're being a translator */
3258 memcpy(inname, ain, t + 1); /* include terminating null */
3262 if ((*acred)->cr_gid == RMTUSER_REQ ||
3263 (*acred)->cr_gid == RMTUSER_REQ_PRIV) { /* Handles all exporters */
3264 if (allpags && (*acred)->cr_gid != RMTUSER_REQ_PRIV) {
3267 pag = PagInCred(*acred);
3269 return EINVAL; /* Better than panicing */
3271 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
3272 return EINVAL; /* Better than panicing */
3274 if (!(exporter = au->exporter)) {
3275 afs_PutUser(au, READ_LOCK);
3276 return EINVAL; /* Better than panicing */
3278 error = EXP_SYSNAME(exporter, (setsysname ? cp2 : NULL), &sysnamelist,
3281 if (error == ENODEV)
3282 foundname = 0; /* sysname not set yet! */
3284 afs_PutUser(au, READ_LOCK);
3289 strcpy(outname, sysnamelist[0]);
3291 afs_PutUser(au, READ_LOCK);
3295 /* Not xlating, so local case */
3297 osi_Panic("PSetSysName: !afs_sysname\n");
3298 if (!setsysname) { /* user just wants the info */
3299 strcpy(outname, afs_sysname);
3300 foundname = afs_sysnamecount;
3301 sysnamelist = afs_sysnamelist;
3302 } else { /* Local guy; only root can change sysname */
3303 if (!afs_osi_suser(*acred))
3306 /* allpags makes no sense for local use */
3310 /* clear @sys entries from the dnlc, once afs_lookup can
3311 * do lookups of @sys entries and thinks it can trust them */
3312 /* privs ok, store the entry, ... */
3313 strcpy(afs_sysname, inname);
3314 if (setsysname > 1) { /* ... or list */
3316 for (count = 1; count < setsysname; ++count) {
3317 if (!afs_sysnamelist[count])
3319 ("PSetSysName: no afs_sysnamelist entry to write\n");
3321 memcpy(afs_sysnamelist[count], cp, t + 1); /* include null */
3325 afs_sysnamecount = setsysname;
3330 cp = aout; /* not changing so report back the count and ... */
3331 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
3332 cp += sizeof(afs_int32);
3334 strcpy(cp, outname); /* ... the entry, ... */
3335 cp += strlen(outname) + 1;
3336 for (count = 1; count < foundname; ++count) { /* ... or list. */
3337 if (!sysnamelist[count])
3339 ("PSetSysName: no afs_sysnamelist entry to read\n");
3340 t = strlen(sysnamelist[count]);
3341 if (t >= MAXSYSNAME)
3342 osi_Panic("PSetSysName: sysname entry garbled\n");
3343 strcpy(cp, sysnamelist[count]);
3347 *aoutSize = cp - aout;
3352 /* sequential search through the list of touched cells is not a good
3353 * long-term solution here. For small n, though, it should be just
3354 * fine. Should consider special-casing the local cell for large n.
3355 * Likewise for PSetSPrefs.
3357 * s - number of ids in array l[] -- NOT index of last id
3358 * l - array of cell ids which have volumes that need to be sorted
3359 * vlonly - sort vl servers or file servers?
3362 ReSortCells_cb(struct cell *cell, void *arg)
3364 afs_int32 *p = (afs_int32 *) arg;
3365 afs_int32 *l = p + 1;
3368 for (i = 0; i < s; i++) {
3369 if (l[i] == cell->cellNum) {
3370 ObtainWriteLock(&cell->lock, 690);
3371 afs_SortServers(cell->cellHosts, MAXCELLHOSTS);
3372 ReleaseWriteLock(&cell->lock);
3380 ReSortCells(int s, afs_int32 * l, int vlonly)
3388 p = (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * (s + 1));
3390 memcpy(p + 1, l, s * sizeof(afs_int32));
3391 afs_TraverseCells(&ReSortCells_cb, p);
3392 afs_osi_Free(p, sizeof(afs_int32) * (s + 1));
3396 ObtainReadLock(&afs_xvolume);
3397 for (i = 0; i < NVOLS; i++) {
3398 for (j = afs_volumes[i]; j; j = j->next) {
3399 for (k = 0; k < s; k++)
3400 if (j->cell == l[k]) {
3401 ObtainWriteLock(&j->lock, 233);
3402 afs_SortServers(j->serverHost, MAXHOSTS);
3403 ReleaseWriteLock(&j->lock);
3408 ReleaseReadLock(&afs_xvolume);
3412 static int debugsetsp = 0;
3414 afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
3417 int i, j, k, matches, touchedSize;
3418 struct server *srvr = NULL;
3419 afs_int32 touched[34];
3423 for (k = 0; k < num; sp++, k++) {
3425 printf("sp host=%x, rank=%d\n", sp->host.s_addr, sp->rank);
3428 ObtainReadLock(&afs_xserver);
3430 i = SHash(sp->host.s_addr);
3431 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
3432 if (sa->sa_ip == sp->host.s_addr) {
3434 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3435 || (sa->sa_portal == AFS_FSPORT);
3436 if ((!vlonly && isfs) || (vlonly && !isfs)) {
3443 if (sa && matches) { /* found one! */
3445 printf("sa ip=%x, ip_rank=%d\n", sa->sa_ip, sa->sa_iprank);
3447 sa->sa_iprank = sp->rank + afs_randomMod15();
3448 afs_SortOneServer(sa->server);
3451 /* if we don't know yet what cell it's in, this is moot */
3452 for (j = touchedSize - 1;
3453 j >= 0 && touched[j] != srvr->cell->cellNum; j--)
3454 /* is it in our list of touched cells ? */ ;
3455 if (j < 0) { /* no, it's not */
3456 touched[touchedSize++] = srvr->cell->cellNum;
3457 if (touchedSize >= 32) { /* watch for ovrflow */
3458 ReleaseReadLock(&afs_xserver);
3459 ReSortCells(touchedSize, touched, vlonly);
3461 ObtainReadLock(&afs_xserver);
3467 ReleaseReadLock(&afs_xserver);
3468 /* if we didn't find one, start to create one. */
3469 /* Note that it doesn't have a cell yet... */
3471 afs_uint32 temp = sp->host.s_addr;
3473 afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
3474 WRITE_LOCK, (afsUUID *) 0, 0);
3475 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3476 afs_PutServer(srvr, WRITE_LOCK);
3478 } /* for all cited preferences */
3480 ReSortCells(touchedSize, touched, vlonly);
3485 * VIOC_SETPREFS (46) - Set server ranks
3487 * \param[in] ain the sprefs value you want the sprefs to be set to
3488 * \param[out] aout not in use
3490 * \retval EIO Error if the afs daemon hasn't started yet
3491 * \retval EACCES Error if the user doesn't have super-user credentials
3492 * \retval EINVAL Error if the struct setsprefs is too large or if it multiplied by the number of servers is too large
3494 * \post set the sprefs using the afs_setsprefs() function
3496 DECL_PIOCTL(PSetSPrefs)
3498 struct setspref *ssp;
3499 AFS_STATCNT(PSetSPrefs);
3501 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3502 return EIO; /* Inappropriate ioctl for device */
3504 if (!afs_osi_suser(*acred))
3507 if (ainSize < sizeof(struct setspref))
3510 ssp = (struct setspref *)ain;
3511 if (ainSize < sizeof(struct spref) * ssp->num_servers)
3514 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
3515 (ssp->flags & DBservers));
3520 * VIOC_SETPREFS33 (42) - Set server ranks (deprecated)
3522 * \param[in] ain the server preferences to be set
3523 * \param[out] aout not in use
3525 * \retval EIO Error if the afs daemon hasn't started yet
3526 * \retval EACCES Error if the user doesn't have super-user credentials
3528 * \post set the server preferences, calling a function
3530 * \notes this may only be performed by the local root user.
3532 DECL_PIOCTL(PSetSPrefs33)
3535 AFS_STATCNT(PSetSPrefs);
3536 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3537 return EIO; /* Inappropriate ioctl for device */
3540 if (!afs_osi_suser(*acred))
3543 sp = (struct spref *)ain;
3544 afs_setsprefs(sp, ainSize / (sizeof(struct spref)), 0 /*!vlonly */ );
3549 * VIOC_GETSPREFS (43) - Get server ranks
3553 * \param[in] ain the server preferences to get
3554 * \param[out] aout the server preferences information
3556 * \retval EIO Error if the afs daemon hasn't started yet
3557 * \retval ENOENT Error if the sprefrequest is too large
3559 * \post Get the sprefs
3561 * \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.
3563 DECL_PIOCTL(PGetSPrefs)
3565 struct sprefrequest *spin; /* input */
3566 struct sprefinfo *spout; /* output */
3567 struct spref *srvout; /* one output component */
3568 int i, j; /* counters for hash table traversal */
3569 struct server *srvr; /* one of CM's server structs */
3571 int vlonly; /* just return vlservers ? */
3574 AFS_STATCNT(PGetSPrefs);
3575 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3576 return EIO; /* Inappropriate ioctl for device */
3579 if (ainSize < sizeof(struct sprefrequest_33)) {
3582 spin = ((struct sprefrequest *)ain);
3585 if (ainSize > sizeof(struct sprefrequest_33)) {
3586 vlonly = (spin->flags & DBservers);
3590 /* struct sprefinfo includes 1 server struct... that size gets added
3591 * in during the loop that follows.
3593 *aoutSize = sizeof(struct sprefinfo) - sizeof(struct spref);
3594 spout = (struct sprefinfo *)aout;
3595 spout->next_offset = spin->offset;
3596 spout->num_servers = 0;
3597 srvout = spout->servers;
3599 ObtainReadLock(&afs_xserver);
3600 for (i = 0, j = 0; j < NSERVERS; j++) { /* sift through hash table */
3601 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3602 if (spin->offset > (unsigned short)i) {
3603 continue; /* catch up to where we left off */
3605 spout->next_offset++;
3608 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3609 || (sa->sa_portal == AFS_FSPORT);
3611 if ((vlonly && isfs) || (!vlonly && !isfs)) {
3612 /* only report ranks for vl servers */
3616 srvout->host.s_addr = sa->sa_ip;
3617 srvout->rank = sa->sa_iprank;
3618 *aoutSize += sizeof(struct spref);
3619 spout->num_servers++;
3622 if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3623 ReleaseReadLock(&afs_xserver); /* no more room! */
3628 ReleaseReadLock(&afs_xserver);
3630 spout->next_offset = 0; /* start over from the beginning next time */
3634 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3635 int afs_NFSRootOnly = 1;
3637 * VIOC_EXPORTAFS (39) - Export afs to nfs clients
3641 * \param[in] ain a struct Vic * EIOctl containing export values needed to change between nfs and afs
3642 * \param[out] aout a struct of the exporter states (exporter->exp_states)
3644 * \retval ENODEV Error if the exporter doesn't exist
3645 * \retval EACCES Error if the user doesn't have super-user credentials
3647 * \post Changes the state of various values to reflect the change of the export values between nfs and afs.
3649 * \notes Legacy code obtained from IBM.
3651 DECL_PIOCTL(PExportAfs)
3653 afs_int32 export, newint =
3654 0, type, changestate, handleValue, convmode, pwsync, smounts;
3655 afs_int32 rempags = 0, pagcb = 0;
3656 register struct afs_exporter *exporter;
3658 AFS_STATCNT(PExportAfs);
3659 memcpy((char *)&handleValue, ain, sizeof(afs_int32));
3660 type = handleValue >> 24;
3665 exporter = exporter_find(type);
3667 export = handleValue & 3;
3668 changestate = handleValue & 0xfff;
3669 smounts = (handleValue >> 2) & 3;
3670 pwsync = (handleValue >> 4) & 3;
3671 convmode = (handleValue >> 6) & 3;
3672 rempags = (handleValue >> 8) & 3;
3673 pagcb = (handleValue >> 10) & 3;
3675 changestate = (handleValue >> 16) & 0x1;
3676 convmode = (handleValue >> 16) & 0x2;
3677 pwsync = (handleValue >> 16) & 0x4;
3678 smounts = (handleValue >> 16) & 0x8;
3679 export = handleValue & 0xff;
3682 /* Failed finding desired exporter; */
3686 handleValue = exporter->exp_states;
3687 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3688 *aoutSize = sizeof(afs_int32);
3690 if (!afs_osi_suser(*acred))
3691 return EACCES; /* Only superuser can do this */
3695 exporter->exp_states |= EXP_EXPORTED;
3697 exporter->exp_states &= ~EXP_EXPORTED;
3701 exporter->exp_states |= EXP_UNIXMODE;
3703 exporter->exp_states &= ~EXP_UNIXMODE;
3707 exporter->exp_states |= EXP_PWSYNC;
3709 exporter->exp_states &= ~EXP_PWSYNC;
3713 afs_NFSRootOnly = 0;
3714 exporter->exp_states |= EXP_SUBMOUNTS;
3716 afs_NFSRootOnly = 1;
3717 exporter->exp_states &= ~EXP_SUBMOUNTS;
3722 exporter->exp_states |= EXP_CLIPAGS;
3724 exporter->exp_states &= ~EXP_CLIPAGS;
3728 exporter->exp_states |= EXP_CALLBACK;
3730 exporter->exp_states &= ~EXP_CALLBACK;
3732 handleValue = exporter->exp_states;
3733 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3734 *aoutSize = sizeof(afs_int32);
3737 exporter->exp_states |= EXP_EXPORTED;
3739 exporter->exp_states &= ~EXP_EXPORTED;
3741 exporter->exp_states |= EXP_UNIXMODE;
3743 exporter->exp_states &= ~EXP_UNIXMODE;
3745 exporter->exp_states |= EXP_PWSYNC;
3747 exporter->exp_states &= ~EXP_PWSYNC;
3749 afs_NFSRootOnly = 0;
3750 exporter->exp_states |= EXP_SUBMOUNTS;
3752 afs_NFSRootOnly = 1;
3753 exporter->exp_states &= ~EXP_SUBMOUNTS;
3762 * VIOC_GAG (44) - Silence Cache Manager
3766 * \param[in] ain the flags to either gag or de-gag the cache manager
3767 * \param[out] aout not in use
3769 * \retval EACCES Error if the user doesn't have super-user credentials
3771 * \post set the gag flags, then show these flags
3775 struct gaginfo *gagflags;
3777 if (!afs_osi_suser(*acred))
3780 gagflags = (struct gaginfo *)ain;
3781 afs_showflags = gagflags->showflags;
3787 * VIOC_TWIDDLE (45) - Adjust RX knobs
3791 * \param[in] ain the previous settings of the 'knobs'
3792 * \param[out] aout not in use
3794 * \retval EACCES Error if the user doesn't have super-user credentials
3796 * \post build out the struct rxp, from a struct rx
3798 DECL_PIOCTL(PTwiddleRx)
3800 struct rxparams *rxp;
3802 if (!afs_osi_suser(*acred))
3805 rxp = (struct rxparams *)ain;
3807 if (rxp->rx_initReceiveWindow)
3808 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3809 if (rxp->rx_maxReceiveWindow)
3810 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3811 if (rxp->rx_initSendWindow)
3812 rx_initSendWindow = rxp->rx_initSendWindow;
3813 if (rxp->rx_maxSendWindow)
3814 rx_maxSendWindow = rxp->rx_maxSendWindow;
3815 if (rxp->rxi_nSendFrags)
3816 rxi_nSendFrags = rxp->rxi_nSendFrags;
3817 if (rxp->rxi_nRecvFrags)
3818 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3819 if (rxp->rxi_OrphanFragSize)
3820 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3821 if (rxp->rx_maxReceiveSize) {
3822 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3823 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3825 if (rxp->rx_MyMaxSendSize)
3826 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3832 * VIOC_GETINITPARAMS (49) - Get initial cache manager parameters
3836 * \param[in] ain not in use
3837 * \param[out] aout initial cache manager params
3839 * \retval E2BIG Error if the initial parameters are bigger than some PIGGYSIZE
3841 * \post return the initial cache manager parameters
3843 DECL_PIOCTL(PGetInitParams)
3845 if (sizeof(struct cm_initparams) > PIGGYSIZE)
3848 memcpy(aout, (char *)&cm_initParams, sizeof(struct cm_initparams));
3849 *aoutSize = sizeof(struct cm_initparams);
3853 #ifdef AFS_SGI65_ENV
3854 /* They took crget() from us, so fake it. */
3859 cr = crdup(get_current_cred());
3860 memset((char *)cr, 0, sizeof(cred_t));
3861 #if CELL || CELL_PREPARE
3869 * VIOC_GETRXKCRYPT (55) - Get rxkad encryption flag
3873 * \param[in] ain not in use
3874 * \param[out] aout value of cryptall
3876 * \post get the value of cryptall (presumably whether or not things should be encrypted)
3878 DECL_PIOCTL(PGetRxkcrypt)
3880 memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3881 *aoutSize = sizeof(afs_int32);
3886 * VIOC_SETRXKCRYPT (56) - Set rxkad encryption flag
3890 * \param[in] ain the argument whether or not things should be encrypted
3891 * \param[out] aout not in use
3893 * \retval EPERM Error if the user doesn't have super-user credentials
3894 * \retval EINVAL Error if the input is too big, or if the input is outside the bounds of what it can be set to
3896 * \post set whether or not things should be encrypted
3898 * \notes may need to be modified at a later date to take into account other values for cryptall (beyond true or false)
3900 DECL_PIOCTL(PSetRxkcrypt)
3904 if (!afs_osi_suser(*acred))
3906 if (ainSize != sizeof(afs_int32) || ain == NULL)
3908 memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3909 /* if new mappings added later this will need to be changed */
3910 if (tmpval != 0 && tmpval != 1)
3916 #ifdef AFS_NEED_CLIENTCONTEXT
3918 * Create new credentials to correspond to a remote user with given
3919 * <hostaddr, uid, g0, g1>. This allows a server running as root to
3920 * provide pioctl (and other) services to foreign clients (i.e. nfs
3921 * clients) by using this call to `become' the client.
3924 #define PIOCTL_HEADER 6
3926 HandleClientContext(struct afs_ioctl *ablob, int *com,
3927 struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3930 afs_uint32 hostaddr;
3931 afs_int32 uid, g0, g1, i, code, pag, exporter_type, isroot = 0;
3932 struct afs_exporter *exporter, *outexporter;
3933 struct AFS_UCRED *newcred;
3934 struct unixuser *au;
3935 afs_uint32 comp = *com & 0xff00;
3938 #if defined(AFS_SGIMP_ENV)
3939 osi_Assert(ISAFS_GLOCK());
3941 AFS_STATCNT(HandleClientContext);
3942 if (ablob->in_size < PIOCTL_HEADER * sizeof(afs_int32)) {
3943 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3944 return EINVAL; /* Too small to be good */
3946 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3947 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER * sizeof(afs_int32), code);
3949 osi_FreeLargeSpace(inData);
3953 /* Extract information for remote user */
3954 hostaddr = *((afs_uint32 *) ain);
3955 ain += sizeof(hostaddr);
3956 uid = *((afs_uint32 *) ain);
3958 g0 = *((afs_uint32 *) ain);
3960 g1 = *((afs_uint32 *) ain);
3962 *com = *((afs_uint32 *) ain);
3963 ain += sizeof(afs_int32);
3964 exporter_type = *((afs_uint32 *) ain); /* In case we support more than NFS */
3967 * Of course, one must be root for most of these functions, but
3968 * we'll allow (for knfs) you to set things if the pag is 0 and
3969 * you're setting tokens or unlogging.
3972 if (!afs_osi_suser(credp)) {
3973 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI64_ENV)
3974 /* Since SGI's suser() returns explicit failure after the call.. */
3977 /* check for acceptable opcodes for normal folks, which are, so far,
3978 * get/set tokens, sysname, and unlog.
3980 if (i != 9 && i != 3 && i != 38 && i != 8) {
3981 osi_FreeLargeSpace(inData);
3986 ablob->in_size -= PIOCTL_HEADER * sizeof(afs_int32);
3987 ablob->in += PIOCTL_HEADER * sizeof(afs_int32);
3988 osi_FreeLargeSpace(inData);
3991 * We map uid 0 to nobody to match the mapping that the nfs
3992 * server does and to ensure that the suser() calls in the afs
3993 * code fails for remote client roots.
3995 uid = afs_nobody; /* NFS_NOBODY == -2 */
3999 #ifdef AFS_AIX41_ENV
4002 newcred->cr_gid = isroot ? RMTUSER_REQ_PRIV : RMTUSER_REQ;
4003 #ifdef AFS_AIX51_ENV
4004 newcred->cr_groupset.gs_union.un_groups[0] = g0;
4005 newcred->cr_groupset.gs_union.un_groups[1] = g1;
4006 #elif defined(AFS_LINUX26_ENV)
4007 #ifdef AFS_LINUX26_ONEGROUP_ENV
4008 newcred->cr_group_info = groups_alloc(1); /* not that anything sets this */
4009 l = (((g0-0x3f00) & 0x3fff) << 14) | ((g1-0x3f00) & 0x3fff);
4010 h = ((g0-0x3f00) >> 14);
4011 h = ((g1-0x3f00) >> 14) + h + h + h;
4012 GROUP_AT(newcred->cr_group_info, 0) = ((h << 28) | l);
4014 newcred->cr_group_info = groups_alloc(2);
4015 GROUP_AT(newcred->cr_group_info, 0) = g0;
4016 GROUP_AT(newcred->cr_group_info, 1) = g1;
4019 newcred->cr_groups[0] = g0;
4020 newcred->cr_groups[1] = g1;
4023 newcred->cr_ngrps = 2;
4024 #elif !defined(AFS_LINUX26_ENV)
4025 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
4026 newcred->cr_ngroups = 2;
4028 for (i = 2; i < NGROUPS; i++)
4029 newcred->cr_groups[i] = NOGROUP;
4032 #if !defined(AFS_OSF_ENV)
4033 afs_nfsclient_init(); /* before looking for exporter, ensure one exists */
4035 if (!(exporter = exporter_find(exporter_type))) {
4036 /* Exporter wasn't initialized or an invalid exporter type */
4040 if (exporter->exp_states & EXP_PWSYNC) {
4041 if (uid != credp->cr_uid) {
4043 return ENOEXEC; /* XXX Find a better errno XXX */
4046 newcred->cr_uid = uid; /* Only temporary */
4047 code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
4048 /* The client's pag is the only unique identifier for it */
4049 newcred->cr_uid = pag;
4051 if (!code && *com == PSETPAG) {
4052 /* Special case for 'setpag' */
4053 afs_uint32 pagvalue = genpag();
4055 au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
4057 * Note that we leave the 'outexporter' struct held so it won't
4060 au->exporter = outexporter;
4061 if (ablob->out_size >= 4) {
4062 AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32),
4065 afs_PutUser(au, WRITE_LOCK);
4068 return PSETPAG; /* Special return for setpag */
4070 EXP_RELE(outexporter);
4073 *com = (*com) | comp;
4076 #endif /* AFS_NEED_CLIENTCONTEXT */
4080 * VIOC_GETCPREFS (50) - Get client interface
4084 * \param[in] ain sprefrequest input
4085 * \param[out] aout spref information
4087 * \retval EIO Error if the afs daemon hasn't started yet
4088 * \retval EINVAL Error if some of the standard args aren't set
4090 * \post get all interface addresses and other information of the client interface
4092 DECL_PIOCTL(PGetCPrefs)
4094 struct sprefrequest *spin; /* input */
4095 struct sprefinfo *spout; /* output */
4096 struct spref *srvout; /* one output component */
4100 AFS_STATCNT(PGetCPrefs);
4101 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4102 return EIO; /* Inappropriate ioctl for device */
4104 if (ainSize < sizeof(struct sprefrequest))
4107 spin = (struct sprefrequest *)ain;
4108 spout = (struct sprefinfo *)aout;
4110 maxNumber = spin->num_servers; /* max addrs this time */
4111 srvout = spout->servers;
4113 ObtainReadLock(&afs_xinterface);
4115 /* copy out the client interface information from the
4116 ** kernel data structure "interface" to the output buffer
4118 for (i = spin->offset, j = 0; (i < afs_cb_interface.numberOfInterfaces)
4119 && (j < maxNumber); i++, j++, srvout++)
4120 srvout->host.s_addr = afs_cb_interface.addr_in[i];
4122 spout->num_servers = j;
4123 *aoutSize = sizeof(struct sprefinfo) + (j - 1) * sizeof(struct spref);
4125 if (i >= afs_cb_interface.numberOfInterfaces)
4126 spout->next_offset = 0; /* start from beginning again */
4128 spout->next_offset = spin->offset + j;
4130 ReleaseReadLock(&afs_xinterface);
4135 * VIOC_SETCPREFS (51) - Set client interface
4139 * \param[in] ain the interfaces you want set
4140 * \param[out] aout not in use
4142 * \retval EIO Error if the afs daemon hasn't started yet
4143 * \retval EINVAL Error if the input is too large for the struct
4144 * \retval ENOMEM Error if there are too many servers
4146 * \post set the callbak interfaces addresses to those of the hosts
4148 DECL_PIOCTL(PSetCPrefs)
4150 struct setspref *sin;
4153 AFS_STATCNT(PSetCPrefs);
4154 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4155 return EIO; /* Inappropriate ioctl for device */
4157 sin = (struct setspref *)ain;
4159 if (ainSize < sizeof(struct setspref))
4161 #if 0 /* num_servers is unsigned */
4162 if (sin->num_servers < 0)
4165 if (sin->num_servers > AFS_MAX_INTERFACE_ADDR)
4168 ObtainWriteLock(&afs_xinterface, 412);
4169 afs_cb_interface.numberOfInterfaces = sin->num_servers;
4170 for (i = 0; (unsigned short)i < sin->num_servers; i++)
4171 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
4173 ReleaseWriteLock(&afs_xinterface);
4178 * VIOC_AFS_FLUSHMOUNT (52) - Flush mount symlink data
4182 * \param[in] ain the last part of a path to a mount point, which tells us what to flush
4183 * \param[out] aout not in use
4185 * \retval EINVAL Error if some of the initial arguments aren't set
4186 * \retval ENOTDIR Error if the initial argument for the mount point isn't a directory
4187 * \retval ENOENT Error if the dcache entry isn't set
4189 * \post remove all of the mount data from the dcache regarding a certain mount point
4191 DECL_PIOCTL(PFlushMount)
4193 register afs_int32 code;
4194 register struct vcache *tvc;
4195 register struct dcache *tdc;
4196 struct VenusFid tfid;
4198 struct sysname_info sysState;
4199 afs_size_t offset, len;
4201 AFS_STATCNT(PFlushMount);
4204 code = afs_VerifyVCache(avc, areq);
4207 if (vType(avc) != VDIR) {
4210 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
4213 Check_AtSys(avc, ain, &sysState, areq);
4214 ObtainReadLock(&tdc->lock);
4216 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
4217 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
4218 ReleaseReadLock(&tdc->lock);
4219 afs_PutDCache(tdc); /* we're done with the data */
4220 bufp = sysState.name;
4224 tfid.Cell = avc->fid.Cell;
4225 tfid.Fid.Volume = avc->fid.Fid.Volume;
4226 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
4227 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
4229 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4235 if (tvc->mvstat != 1) {
4240 #ifdef AFS_BOZONLOCK_ENV
4241 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
4243 ObtainWriteLock(&tvc->lock, 649);
4244 ObtainWriteLock(&afs_xcbhash, 650);
4245 afs_DequeueCallback(tvc);
4246 tvc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
4247 ReleaseWriteLock(&afs_xcbhash);
4248 /* now find the disk cache entries */
4249 afs_TryToSmush(tvc, *acred, 1);
4250 osi_dnlc_purgedp(tvc);
4251 if (tvc->linkData && !(tvc->states & CCore)) {
4252 afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
4253 tvc->linkData = NULL;
4255 ReleaseWriteLock(&tvc->lock);
4256 #ifdef AFS_BOZONLOCK_ENV
4257 afs_BozonUnlock(&tvc->pvnLock, tvc);
4261 if (sysState.allocked)
4262 osi_FreeLargeSpace(bufp);
4267 * VIOC_RXSTAT_PROC (53) - Control process RX statistics
4271 * \param[in] ain the flags that control which stats to use
4272 * \param[out] aout not in use
4274 * \retval EACCES Error if the user doesn't have super-user credentials
4275 * \retval EINVAL Error if the flag input is too long
4277 * \post either enable process RPCStats, disable process RPCStats, or clear the process RPCStats
4279 DECL_PIOCTL(PRxStatProc)
4284 if (!afs_osi_suser(*acred)) {
4288 if (ainSize != sizeof(afs_int32)) {
4292 memcpy((char *)&flags, ain, sizeof(afs_int32));
4293 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4297 if (flags & AFSCALL_RXSTATS_ENABLE) {
4298 rx_enableProcessRPCStats();
4300 if (flags & AFSCALL_RXSTATS_DISABLE) {
4301 rx_disableProcessRPCStats();
4303 if (flags & AFSCALL_RXSTATS_CLEAR) {
4304 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
4313 * VIOC_RXSTAT_PEER (54) - Control peer RX statistics
4317 * \param[in] ain the flags that control which statistics to use
4318 * \param[out] aout not in use
4320 * \retval EACCES Error if the user doesn't have super-user credentials
4321 * \retval EINVAL Error if the flag input is too long
4323 * \post either enable peer RPCStatws, disable peer RPCStats, or clear the peer RPCStats
4325 DECL_PIOCTL(PRxStatPeer)
4330 if (!afs_osi_suser(*acred)) {
4334 if (ainSize != sizeof(afs_int32)) {
4338 memcpy((char *)&flags, ain, sizeof(afs_int32));
4339 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4343 if (flags & AFSCALL_RXSTATS_ENABLE) {
4344 rx_enablePeerRPCStats();
4346 if (flags & AFSCALL_RXSTATS_DISABLE) {
4347 rx_disablePeerRPCStats();
4349 if (flags & AFSCALL_RXSTATS_CLEAR) {
4350 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
4357 DECL_PIOCTL(PPrefetchFromTape)
4359 register afs_int32 code, code1;
4361 struct afs_conn *tc;
4362 struct rx_call *tcall;
4363 struct AFSVolSync tsync;
4364 struct AFSFetchStatus OutStatus;
4365 struct AFSCallBack CallBack;
4366 struct VenusFid tfid;
4370 AFS_STATCNT(PSetAcl);
4374 if (ain && (ainSize == 3 * sizeof(afs_int32)))
4375 Fid = (struct AFSFid *)ain;
4377 Fid = &avc->fid.Fid;
4378 tfid.Cell = avc->fid.Cell;
4379 tfid.Fid.Volume = Fid->Volume;
4380 tfid.Fid.Vnode = Fid->Vnode;
4381 tfid.Fid.Unique = Fid->Unique;
4383 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4385 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4386 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &avc->fid);
4389 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4390 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &tvc->fid);
4393 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
4397 tcall = rx_NewCall(tc->id);
4399 StartRXAFS_FetchData(tcall, (struct AFSFid *)&tvc->fid.Fid, 0,
4402 bytes = rx_Read(tcall, (char *)aout, sizeof(afs_int32));
4404 EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
4406 code1 = rx_EndCall(tcall, code);
4410 } while (afs_Analyze
4411 (tc, code, &tvc->fid, areq, AFS_STATS_FS_RPCIDX_RESIDENCYRPCS,
4412 SHARED_LOCK, NULL));
4413 /* This call is done only to have the callback things handled correctly */
4414 afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
4418 *aoutSize = sizeof(afs_int32);
4423 DECL_PIOCTL(PResidencyCmd)
4425 register afs_int32 code;
4426 struct afs_conn *tc;
4428 struct ResidencyCmdInputs *Inputs;
4429 struct ResidencyCmdOutputs *Outputs;
4430 struct VenusFid tfid;
4433 Inputs = (struct ResidencyCmdInputs *)ain;
4434 Outputs = (struct ResidencyCmdOutputs *)aout;
4437 if (!ain || ainSize != sizeof(struct ResidencyCmdInputs))
4442 Fid = &avc->fid.Fid;
4444 tfid.Cell = avc->fid.Cell;
4445 tfid.Fid.Volume = Fid->Volume;
4446 tfid.Fid.Vnode = Fid->Vnode;
4447 tfid.Fid.Unique = Fid->Unique;
4449 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4450 afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD, ICL_TYPE_POINTER, tvc,
4451 ICL_TYPE_INT32, Inputs->command, ICL_TYPE_FID, &tfid);
4455 if (Inputs->command) {
4457 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
4461 RXAFS_ResidencyCmd(tc->id, Fid, Inputs,
4462 (struct ResidencyCmdOutputs *)aout);
4466 } while (afs_Analyze
4467 (tc, code, &tvc->fid, areq,
4468 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK, NULL));
4469 /* This call is done to have the callback things handled correctly */
4470 afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4471 } else { /* just a status request, return also link data */
4473 Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4474 Outputs->chars[0] = 0;
4475 if (vType(tvc) == VLNK) {
4476 ObtainWriteLock(&tvc->lock, 555);
4477 if (afs_HandleLink(tvc, areq) == 0)
4478 strncpy((char *)&Outputs->chars, tvc->linkData, MAXCMDCHARS);
4479 ReleaseWriteLock(&tvc->lock);
4486 *aoutSize = sizeof(struct ResidencyCmdOutputs);
4491 DECL_PIOCTL(PNewUuid)
4493 /*AFS_STATCNT(PNewUuid); */
4494 if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4495 return EIO; /* Inappropriate ioctl for device */
4497 if (!afs_osi_suser(acred))
4500 ObtainWriteLock(&afs_xinterface, 555);
4501 afs_uuid_create(&afs_cb_interface.uuid);
4502 ReleaseWriteLock(&afs_xinterface);
4503 ForceAllNewConnections();
4507 #if defined(AFS_CACHE_BYPASS)
4509 DECL_PIOCTL(PSetCachingThreshold)
4514 setting = getting = 1;
4516 if (ain == NULL || ainSize < sizeof(afs_int32))
4522 if (setting == 0 && getting == 0)
4526 * If setting, set first, and return the value now in effect
4529 afs_int32 threshold;
4531 if (!afs_osi_suser(*acred))
4533 memcpy((char *)&threshold, ain, sizeof(afs_int32));
4534 cache_bypass_threshold = threshold;
4535 afs_warn("Cache Bypass Threshold set to: %d\n", threshold);
4536 /* TODO: move to separate pioctl, or enhance pioctl */
4537 cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
4541 /* Return the current size threshold */
4542 afs_int32 oldThreshold = cache_bypass_threshold;
4543 memcpy(aout, (char *)&oldThreshold, sizeof(afs_int32));
4544 *aoutSize = sizeof(afs_int32);
4550 #endif /* defined(AFS_CACHE_BYPASS) */
4552 DECL_PIOCTL(PCallBackAddr)
4555 afs_uint32 addr, code;
4559 struct afs_conn *tc;
4561 struct unixuser *tu;
4562 struct srvAddr **addrs;
4564 /*AFS_STATCNT(PCallBackAddr); */
4565 if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4566 return EIO; /* Inappropriate ioctl for device */
4568 if (!afs_osi_suser(acred))
4571 if (ainSize < sizeof(afs_int32))
4574 memcpy(&addr, ain, sizeof(afs_int32));
4576 ObtainReadLock(&afs_xinterface);
4577 for (i = 0; (unsigned short)i < afs_cb_interface.numberOfInterfaces; i++) {
4578 if (afs_cb_interface.addr_in[i] == addr)
4582 ReleaseWriteLock(&afs_xinterface);
4584 if (afs_cb_interface.addr_in[i] != addr)
4587 ObtainReadLock(&afs_xserver); /* Necessary? */
4588 ObtainReadLock(&afs_xsrvAddr);
4591 for (i = 0; i < NSERVERS; i++) {
4592 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4597 addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
4599 for (i = 0; i < NSERVERS; i++) {
4600 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4601 if (j >= srvAddrCount)
4607 ReleaseReadLock(&afs_xsrvAddr);
4608 ReleaseReadLock(&afs_xserver);
4610 for (i = 0; i < j; i++) {
4616 /* vlserver has no callback conn */
4617 if (sa->sa_portal == AFS_VLPORT) {
4621 if (!ts->cell) /* not really an active server, anyway, it must */
4622 continue; /* have just been added by setsprefs */
4624 /* get a connection, even if host is down; bumps conn ref count */
4625 tu = afs_GetUser(areq->uid, ts->cell->cellNum, SHARED_LOCK);
4626 tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
4627 1 /*force */ , 1 /*create */ , SHARED_LOCK);
4628 afs_PutUser(tu, SHARED_LOCK);
4632 if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(ts)) {
4633 if (sa->sa_flags & SRVADDR_ISDOWN) {
4634 rx_SetConnDeadTime(tc->id, 3);
4636 #ifdef RX_ENABLE_LOCKS
4638 #endif /* RX_ENABLE_LOCKS */
4639 code = RXAFS_CallBackRxConnAddr(tc->id, &addr);
4640 #ifdef RX_ENABLE_LOCKS
4642 #endif /* RX_ENABLE_LOCKS */
4644 afs_PutConn(tc, SHARED_LOCK); /* done with it now */
4645 } /* Outer loop over addrs */
4646 #endif /* UKERNEL */
4650 DECL_PIOCTL(PDiscon)
4652 #ifdef AFS_DISCON_ENV
4653 static afs_int32 mode = 1; /* Start up in 'off' */
4654 afs_int32 force = 0;
4659 if (!afs_osi_suser(*acred))
4665 afs_ConflictPolicy = ain[1] - 1;
4670 * All of these numbers are hard coded in fs.c. If they
4671 * change here, they should change there and vice versa
4674 case 0: /* Disconnect ("offline" mode), breaking all callbacks */
4675 if (!AFS_IS_DISCONNECTED) {
4676 ObtainWriteLock(&afs_discon_lock, 999);
4677 afs_DisconGiveUpCallbacks();
4678 afs_RemoveAllConns();
4679 afs_is_disconnected = 1;
4680 afs_is_discon_rw = 1;
4681 ReleaseWriteLock(&afs_discon_lock);
4684 case 1: /* Fully connected, ("online" mode). */
4685 ObtainWriteLock(&afs_discon_lock, 998);
4688 afs_MarkAllServersUp();
4689 code = afs_ResyncDisconFiles(areq, *acred);
4692 if (code && !force) {
4693 printf("Files not synchronized properly, still in discon state. \n"
4694 "Please retry or use \"force\".\n");
4698 afs_DisconDiscardAll(*acred);
4700 afs_is_disconnected = 0;
4701 afs_is_discon_rw = 0;
4702 printf("\nSync succeeded. You are back online.\n");
4705 ReleaseWriteLock(&afs_discon_lock);
4714 memcpy(aout, &mode, sizeof(afs_int32));
4715 *aoutSize = sizeof(afs_int32);
4722 DECL_PIOCTL(PNFSNukeCreds)
4724 afs_uint32 addr, code;
4725 register afs_int32 i;
4726 register struct unixuser *tu;
4728 AFS_STATCNT(PUnlog);
4729 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4730 return EIO; /* Inappropriate ioctl for device */
4732 if (ainSize < sizeof(afs_int32))
4734 memcpy(&addr, ain, sizeof(afs_int32));
4736 if ((*acred)->cr_gid == RMTUSER_REQ_PRIV && !addr) {
4737 tu = afs_GetUser(areq->uid, -1, SHARED_LOCK);
4738 if (!tu->exporter || !(addr = EXP_GETHOST(tu->exporter))) {
4739 afs_PutUser(tu, SHARED_LOCK);
4742 afs_PutUser(tu, SHARED_LOCK);
4743 } else if (!afs_osi_suser(acred)) {
4747 ObtainWriteLock(&afs_xuser, 227);
4748 for (i = 0; i < NUSERS; i++) {
4749 for (tu = afs_users[i]; tu; tu = tu->next) {
4750 if (tu->exporter && EXP_CHECKHOST(tu->exporter, addr)) {
4752 tu->states &= ~UHasTokens;
4753 /* security is not having to say you're sorry */
4754 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
4756 ReleaseWriteLock(&afs_xuser);
4757 afs_ResetUserConns(tu);
4759 ObtainWriteLock(&afs_xuser, 228);
4761 /* set the expire times to 0, causes
4762 * afs_GCUserData to remove this entry
4764 tu->ct.EndTimestamp = 0;
4766 #endif /* UKERNEL */
4770 ReleaseWriteLock(&afs_xuser);