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_logging;
37 afs_int32 afs_is_discon_rw;
38 /* On reconnection, turn this knob on until it finishes,
41 afs_int32 afs_in_sync = 0;
45 * \defgroup pioctl Path IOCTL functions
47 * DECL_PIOCTL is a macro defined to contain the following parameters for functions:
49 * \param[in] avc the AFS vcache structure in use by pioctl
50 * \param[in] afun not in use
51 * \param[in] areq the AFS vrequest structure
52 * \param[in] ain as defined by the function
53 * \param[in] aout as defined by the function
54 * \param[in] ainSize size of ain
55 * \param[in] aoutSize size of aout
56 * \param[in] acred UNIX credentials structure underlying the operation
59 #define DECL_PIOCTL(x) static int x(struct vcache *avc, int afun, struct vrequest *areq, \
60 char *ain, char *aout, afs_int32 ainSize, afs_int32 *aoutSize, \
61 struct AFS_UCRED **acred)
63 /* Prototypes for pioctl routines */
66 DECL_PIOCTL(PStoreBehind);
71 DECL_PIOCTL(PGetFileCell);
72 DECL_PIOCTL(PGetWSCell);
73 DECL_PIOCTL(PGetUserCell);
74 DECL_PIOCTL(PSetTokens);
75 DECL_PIOCTL(PGetVolumeStatus);
76 DECL_PIOCTL(PSetVolumeStatus);
78 DECL_PIOCTL(PNewStatMount);
79 DECL_PIOCTL(PGetTokens);
81 DECL_PIOCTL(PMariner);
82 DECL_PIOCTL(PCheckServers);
83 DECL_PIOCTL(PCheckVolNames);
84 DECL_PIOCTL(PCheckAuth);
85 DECL_PIOCTL(PFindVolume);
86 DECL_PIOCTL(PViceAccess);
87 DECL_PIOCTL(PSetCacheSize);
88 DECL_PIOCTL(PGetCacheSize);
89 DECL_PIOCTL(PRemoveCallBack);
90 DECL_PIOCTL(PNewCell);
91 DECL_PIOCTL(PNewAlias);
92 DECL_PIOCTL(PListCells);
93 DECL_PIOCTL(PListAliases);
94 DECL_PIOCTL(PRemoveMount);
95 DECL_PIOCTL(PVenusLogging);
96 DECL_PIOCTL(PGetCellStatus);
97 DECL_PIOCTL(PSetCellStatus);
98 DECL_PIOCTL(PFlushVolumeData);
99 DECL_PIOCTL(PGetVnodeXStatus);
100 DECL_PIOCTL(PGetVnodeXStatus2);
101 DECL_PIOCTL(PSetSysName);
102 DECL_PIOCTL(PSetSPrefs);
103 DECL_PIOCTL(PSetSPrefs33);
104 DECL_PIOCTL(PGetSPrefs);
105 DECL_PIOCTL(PExportAfs);
107 DECL_PIOCTL(PTwiddleRx);
108 DECL_PIOCTL(PGetInitParams);
109 DECL_PIOCTL(PGetRxkcrypt);
110 DECL_PIOCTL(PSetRxkcrypt);
111 DECL_PIOCTL(PGetCPrefs);
112 DECL_PIOCTL(PSetCPrefs);
113 DECL_PIOCTL(PFlushMount);
114 DECL_PIOCTL(PRxStatProc);
115 DECL_PIOCTL(PRxStatPeer);
116 DECL_PIOCTL(PPrefetchFromTape);
117 DECL_PIOCTL(PResidencyCmd);
118 DECL_PIOCTL(PCallBackAddr);
119 DECL_PIOCTL(PDiscon);
120 DECL_PIOCTL(PNFSNukeCreds);
121 DECL_PIOCTL(PNewUuid);
122 DECL_PIOCTL(PPrecache);
123 #if defined(AFS_CACHE_BYPASS)
124 DECL_PIOCTL(PSetCachingThreshold);
125 DECL_PIOCTL(PSetCachingBlkSize);
129 * A macro that says whether we're going to need HandleClientContext().
130 * This is currently used only by the nfs translator.
132 #if !defined(AFS_NONFSTRANS) || defined(AFS_AIX_IAUTH_ENV)
133 #define AFS_NEED_CLIENTCONTEXT
136 /* Prototypes for private routines */
137 #ifdef AFS_NEED_CLIENTCONTEXT
138 static int HandleClientContext(struct afs_ioctl *ablob, int *com,
139 struct AFS_UCRED **acred,
140 struct AFS_UCRED *credp);
142 int HandleIoctl(register struct vcache *avc, register afs_int32 acom,
143 struct afs_ioctl *adata);
144 int afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
145 register struct afs_ioctl *ablob, int afollow,
146 struct AFS_UCRED **acred);
147 static int Prefetch(char *apath, struct afs_ioctl *adata, int afollow,
148 struct AFS_UCRED *acred);
151 static int (*(VpioctlSw[])) () = {
156 PGetVolumeStatus, /* 4 */
157 PSetVolumeStatus, /* 5 */
162 PCheckServers, /* 10 */
163 PCheckVolNames, /* 11 */
165 PBogus, /* 13 -- used to be quick check time */
166 PFindVolume, /* 14 */
167 PBogus, /* 15 -- prefetch is now special-cased; see pioctl code! */
168 PBogus, /* 16 -- used to be testing code */
169 PNoop, /* 17 -- used to be enable group */
170 PNoop, /* 18 -- used to be disable group */
171 PBogus, /* 19 -- used to be list group */
172 PViceAccess, /* 20 */
173 PUnlog, /* 21 -- unlog *is* unpag in this system */
174 PGetFID, /* 22 -- get file ID */
175 PBogus, /* 23 -- used to be waitforever */
176 PSetCacheSize, /* 24 */
177 PRemoveCallBack, /* 25 -- flush only the callback */
180 PRemoveMount, /* 28 -- delete mount point */
181 PNewStatMount, /* 29 -- new style mount point stat */
182 PGetFileCell, /* 30 -- get cell name for input file */
183 PGetWSCell, /* 31 -- get cell name for workstation */
184 PMariner, /* 32 - set/get mariner host */
185 PGetUserCell, /* 33 -- get cell name for user */
186 PVenusLogging, /* 34 -- Enable/Disable logging */
187 PGetCellStatus, /* 35 */
188 PSetCellStatus, /* 36 */
189 PFlushVolumeData, /* 37 -- flush all data from a volume */
190 PSetSysName, /* 38 - Set system name */
191 PExportAfs, /* 39 - Export Afs to remote nfs clients */
192 PGetCacheSize, /* 40 - get cache size and usage */
193 PGetVnodeXStatus, /* 41 - get vcache's special status */
194 PSetSPrefs33, /* 42 - Set CM Server preferences... */
195 PGetSPrefs, /* 43 - Get CM Server preferences... */
196 PGag, /* 44 - turn off/on all CM messages */
197 PTwiddleRx, /* 45 - adjust some RX params */
198 PSetSPrefs, /* 46 - Set CM Server preferences... */
199 PStoreBehind, /* 47 - set degree of store behind to be done */
200 PGCPAGs, /* 48 - disable automatic pag gc-ing */
201 PGetInitParams, /* 49 - get initial cm params */
202 PGetCPrefs, /* 50 - get client interface addresses */
203 PSetCPrefs, /* 51 - set client interface addresses */
204 PFlushMount, /* 52 - flush mount symlink data */
205 PRxStatProc, /* 53 - control process RX statistics */
206 PRxStatPeer, /* 54 - control peer RX statistics */
207 PGetRxkcrypt, /* 55 -- Get rxkad encryption flag */
208 PSetRxkcrypt, /* 56 -- Set rxkad encryption flag */
209 PBogus, /* 57 -- arla: set file prio */
210 PBogus, /* 58 -- arla: fallback getfh */
211 PBogus, /* 59 -- arla: fallback fhopen */
212 PBogus, /* 60 -- arla: controls xfsdebug */
213 PBogus, /* 61 -- arla: controls arla debug */
214 PBogus, /* 62 -- arla: debug interface */
215 PBogus, /* 63 -- arla: print xfs status */
216 PBogus, /* 64 -- arla: force cache check */
217 PBogus, /* 65 -- arla: break callback */
218 PPrefetchFromTape, /* 66 -- MR-AFS: prefetch file from tape */
219 PResidencyCmd, /* 67 -- MR-AFS: generic commnd interface */
220 PBogus, /* 68 -- arla: fetch stats */
221 PGetVnodeXStatus2, /* 69 - get caller access and some vcache status */
224 static int (*(CpioctlSw[])) () = {
226 PNewAlias, /* 1 -- create new cell alias */
227 PListAliases, /* 2 -- list cell aliases */
228 PCallBackAddr, /* 3 -- request addr for callback rxcon */
240 static int (*(OpioctlSw[])) () = {
242 PNFSNukeCreds, /* 1 -- nuke all creds for NFS client */
243 #if defined(AFS_CACHE_BYPASS)
244 PSetCachingThreshold /* 2 -- get/set cache-bypass size threshold */
246 PNoop /* 2 -- get/set cache-bypass size threshold */
250 #define PSetClientContext 99 /* Special pioctl to setup caller's creds */
251 int afs_nobody = NFS_NOBODY;
254 HandleIoctl(register struct vcache *avc, register afs_int32 acom,
255 struct afs_ioctl *adata)
257 register afs_int32 code;
260 AFS_STATCNT(HandleIoctl);
262 switch (acom & 0xff) {
264 avc->states |= CSafeStore;
268 /* case 2 used to be abort store, but this is no longer provided,
269 * since it is impossible to implement under normal Unix.
273 /* return the name of the cell this file is open on */
274 register struct cell *tcell;
275 register afs_int32 i;
277 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
279 i = strlen(tcell->cellName) + 1; /* bytes to copy out */
281 if (i > adata->out_size) {
282 /* 0 means we're not interested in the output */
283 if (adata->out_size != 0)
287 AFS_COPYOUT(tcell->cellName, adata->out, i, code);
289 afs_PutCell(tcell, READ_LOCK);
295 case 49: /* VIOC_GETINITPARAMS */
296 if (adata->out_size < sizeof(struct cm_initparams)) {
299 AFS_COPYOUT(&cm_initParams, adata->out,
300 sizeof(struct cm_initparams), code);
312 return code; /* so far, none implemented */
317 /* For aix we don't temporarily bypass ioctl(2) but rather do our
318 * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
319 * is now called from afs_gn_ioctl.
322 afs_ioctl(struct vcache *tvc, int cmd, int arg)
324 struct afs_ioctl data;
327 AFS_STATCNT(afs_ioctl);
328 if (((cmd >> 8) & 0xff) == 'V') {
329 /* This is a VICEIOCTL call */
330 AFS_COPYIN(arg, (caddr_t) & data, sizeof(data), error);
333 error = HandleIoctl(tvc, cmd, &data);
336 /* No-op call; just return. */
340 #endif /* AFS_AIX_ENV */
342 #if defined(AFS_SGI_ENV)
343 afs_ioctl(OSI_VN_DECL(tvc), int cmd, void *arg, int flag, cred_t * cr,
346 , struct vopbd * vbds
350 struct afs_ioctl data;
356 AFS_STATCNT(afs_ioctl);
357 if (((cmd >> 8) & 0xff) == 'V') {
358 /* This is a VICEIOCTL call */
359 error = copyin_afs_ioctl(arg, &data);
362 locked = ISAFS_GLOCK();
365 error = HandleIoctl(tvc, cmd, &data);
370 /* No-op call; just return. */
374 #endif /* AFS_SGI_ENV */
376 /* unlike most calls here, this one uses u.u_error to return error conditions,
377 since this is really an intercepted chapter 2 call, rather than a vnode
380 /* AFS_HPUX102 and up uses VNODE ioctl instead */
381 #if !defined(AFS_HPUX102_ENV) && !defined(AFS_DARWIN80_ENV)
382 #if !defined(AFS_SGI_ENV)
386 kioctl(fdes, com, arg, ext, arg2, arg3)
387 #else /* __64BIT__ */
388 kioctl32(fdes, com, arg, ext, arg2, arg3)
389 #endif /* __64BIT__ */
392 kioctl(fdes, com, arg, ext)
403 } u_uap, *uap = &u_uap;
405 #if defined(AFS_SUN5_ENV)
407 struct afs_ioctl_sys {
414 struct afs_ioctl_sys *uap;
417 #elif defined(AFS_OSF_ENV)
418 afs_xioctl(p, args, retval)
427 } *uap = (struct a *)args;
428 #elif defined(AFS_FBSD50_ENV)
431 afs_xioctl(td, uap, retval)
433 register struct ioctl_args *uap;
436 struct proc *p = td->td_proc;
437 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
445 afs_xioctl(p, uap, retval)
447 register struct ioctl_args *uap;
450 #elif defined(AFS_LINUX22_ENV)
451 struct afs_ioctl_sys {
456 afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
459 struct afs_ioctl_sys ua, *uap = &ua;
468 } *uap = (struct a *)u.u_ap;
469 #endif /* AFS_SUN5_ENV */
471 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
473 #elif !defined(AFS_LINUX22_ENV)
474 register struct file *fd;
476 #if defined(AFS_XBSD_ENV)
477 register struct filedesc *fdp;
479 register struct vcache *tvc;
480 register int ioctlDone = 0, code = 0;
482 AFS_STATCNT(afs_xioctl);
483 #if defined(AFS_DARWIN_ENV)
484 if ((code = fdgetf(p, uap->fd, &fd)))
486 #elif defined(AFS_XBSD_ENV)
488 if ((u_int) uap->fd >= fdp->fd_nfiles
489 || (fd = fdp->fd_ofiles[uap->fd]) == NULL)
491 if ((fd->f_flag & (FREAD | FWRITE)) == 0)
493 #elif defined(AFS_LINUX22_ENV)
496 #elif defined(AFS_AIX32_ENV)
504 if (setuerror(getf(uap->fd, &fd))) {
507 #elif defined(AFS_OSF_ENV)
509 if (code = getf(&fd, uap->fd, FILE_FLAGS_NULL, &u.u_file_state))
511 #elif defined(AFS_SUN5_ENV)
512 # if defined(AFS_SUN57_ENV)
516 # elif defined(AFS_SUN54_ENV)
521 if (code = getf(uap->fd, &fd)) {
524 # endif /* AFS_SUN57_ENV */
530 /* first determine whether this is any sort of vnode */
531 #if defined(AFS_LINUX22_ENV)
536 if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
538 if (fd->f_type == DTYPE_VNODE) {
540 /* good, this is a vnode; next see if it is an AFS vnode */
541 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
542 tvc = VTOAFS(fd->f_vnode); /* valid, given a vnode */
543 #elif defined(AFS_OBSD_ENV)
545 IsAfsVnode((struct vnode *)fd->
546 f_data) ? VTOAFS((struct vnode *)fd->f_data) : NULL;
548 tvc = VTOAFS((struct vnode *)fd->f_data); /* valid, given a vnode */
550 #endif /* AFS_LINUX22_ENV */
551 if (tvc && IsAfsVnode(AFSTOV(tvc))) {
552 /* This is an AFS vnode */
553 if (((uap->com >> 8) & 0xff) == 'V') {
554 register struct afs_ioctl *datap;
557 (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
558 code=copyin_afs_ioctl((char *)uap->arg, datap);
560 osi_FreeSmallSpace(datap);
562 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
565 #if defined(AFS_SUN5_ENV)
580 #else /* AFS_OSF_ENV */
584 #ifdef AFS_LINUX22_ENV
594 code = HandleIoctl(tvc, uap->com, datap);
595 osi_FreeSmallSpace(datap);
609 #if defined(AFS_LINUX22_ENV)
621 code = okioctl(fdes, com, arg, ext, arg2, arg3);
622 #else /* __64BIT__ */
623 code = okioctl32(fdes, com, arg, ext, arg2, arg3);
624 #endif /* __64BIT__ */
625 #else /* !AFS_AIX51_ENV */
626 code = okioctl(fdes, com, arg, ext);
627 #endif /* AFS_AIX51_ENV */
629 #else /* !AFS_AIX41_ENV */
631 okioctl(fdes, com, arg, ext);
632 #elif defined(AFS_SUN5_ENV)
633 #if defined(AFS_SUN57_ENV)
635 #elif defined(AFS_SUN54_ENV)
640 code = ioctl(uap, rvp);
641 #elif defined(AFS_FBSD50_ENV)
642 return ioctl(td, uap);
643 #elif defined(AFS_FBSD_ENV)
644 return ioctl(p, uap);
645 #elif defined(AFS_OBSD_ENV)
646 code = sys_ioctl(p, uap, retval);
647 #elif defined(AFS_DARWIN_ENV)
648 return ioctl(p, uap, retval);
649 #elif defined(AFS_OSF_ENV)
650 code = ioctl(p, args, retval);
657 #elif !defined(AFS_LINUX22_ENV)
671 #ifdef AFS_LINUX22_ENV
674 #if defined(KERNEL_HAVE_UERROR)
677 #if defined(AFS_AIX32_ENV) && !defined(AFS_AIX41_ENV)
678 return (getuerror()? -1 : u.u_ioctlrv);
680 return getuerror()? -1 : 0;
683 #endif /* AFS_LINUX22_ENV */
684 #endif /* AFS_SUN5_ENV */
685 #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
689 #endif /* AFS_SGI_ENV */
690 #endif /* AFS_HPUX102_ENV */
692 #if defined(AFS_SGI_ENV)
693 /* "pioctl" system call entry point; just pass argument to the parameterized
702 afs_pioctl(struct pioctlargs *uap, rval_t * rvp)
706 AFS_STATCNT(afs_pioctl);
708 code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
717 #elif defined(AFS_OSF_ENV)
718 afs_pioctl(p, args, retval)
728 } *uap = (struct a *)args;
730 AFS_STATCNT(afs_pioctl);
731 return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow));
734 #elif defined(AFS_FBSD50_ENV)
736 afs_pioctl(td, args, retval)
746 } *uap = (struct a *)args;
748 AFS_STATCNT(afs_pioctl);
749 return (afs_syscall_pioctl
750 (uap->path, uap->cmd, uap->cmarg, uap->follow, td->td_ucred));
753 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
755 afs_pioctl(p, args, retval)
765 } *uap = (struct a *)args;
767 AFS_STATCNT(afs_pioctl);
768 #ifdef AFS_DARWIN80_ENV
769 return (afs_syscall_pioctl
770 (uap->path, uap->cmd, uap->cmarg, uap->follow,
773 return (afs_syscall_pioctl
774 (uap->path, uap->cmd, uap->cmarg, uap->follow,
775 p->p_cred->pc_ucred));
781 /* macro to avoid adding any more #ifdef's to pioctl code. */
782 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
783 #define PIOCTL_FREE_CRED() crfree(credp)
785 #define PIOCTL_FREE_CRED()
790 afs_syscall_pioctl(path, com, cmarg, follow, rvp, credp)
792 struct AFS_UCRED *credp;
794 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
795 afs_syscall_pioctl(path, com, cmarg, follow, credp)
796 struct AFS_UCRED *credp;
798 afs_syscall_pioctl(path, com, cmarg, follow)
806 struct afs_ioctl data;
807 #ifdef AFS_NEED_CLIENTCONTEXT
808 struct AFS_UCRED *tmpcred = NULL;
810 struct AFS_UCRED *foreigncreds = NULL;
811 register afs_int32 code = 0;
812 struct vnode *vp = NULL;
814 struct ucred *credp = crref(); /* don't free until done! */
816 #ifdef AFS_LINUX22_ENV
817 cred_t *credp = crref(); /* don't free until done! */
821 AFS_STATCNT(afs_syscall_pioctl);
823 follow = 1; /* compat. with old venus */
824 code = copyin_afs_ioctl(cmarg, &data);
827 #if defined(KERNEL_HAVE_UERROR)
832 if ((com & 0xff) == PSetClientContext) {
833 #ifdef AFS_NEED_CLIENTCONTEXT
834 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
835 code = HandleClientContext(&data, &com, &foreigncreds, credp);
837 code = HandleClientContext(&data, &com, &foreigncreds, osi_curcred());
841 crfree(foreigncreds);
844 #if defined(KERNEL_HAVE_UERROR)
845 return (setuerror(code), code);
850 #else /* AFS_NEED_CLIENTCONTEXT */
852 #endif /* AFS_NEED_CLIENTCONTEXT */
854 #ifdef AFS_NEED_CLIENTCONTEXT
857 * We could have done without temporary setting the u.u_cred below
858 * (foreigncreds could be passed as param the pioctl modules)
859 * but calls such as afs_osi_suser() doesn't allow that since it
860 * references u.u_cred directly. We could, of course, do something
861 * like afs_osi_suser(cred) which, I think, is better since it
862 * generalizes and supports multi cred environments...
864 #if defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
866 credp = foreigncreds;
867 #elif defined(AFS_AIX41_ENV)
868 tmpcred = crref(); /* XXX */
870 #elif defined(AFS_HPUX101_ENV)
871 tmpcred = p_cred(u.u_procp);
872 set_p_cred(u.u_procp, foreigncreds);
873 #elif defined(AFS_SGI_ENV)
874 tmpcred = OSI_GET_CURRENT_CRED();
875 OSI_SET_CURRENT_CRED(foreigncreds);
878 u.u_cred = foreigncreds;
881 #endif /* AFS_NEED_CLIENTCONTEXT */
882 if ((com & 0xff) == 15) {
883 /* special case prefetch so entire pathname eval occurs in helper process.
884 * otherwise, the pioctl call is essentially useless */
885 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
887 Prefetch(path, &data, follow,
888 foreigncreds ? foreigncreds : credp);
890 code = Prefetch(path, &data, follow, osi_curcred());
893 #if defined(KERNEL_HAVE_UERROR)
902 lookupname(path, USR, follow, NULL, &vp,
903 foreigncreds ? foreigncreds : credp);
905 #ifdef AFS_LINUX22_ENV
906 code = gop_lookupname(path, AFS_UIOUSER, follow, &dp);
908 vp = (struct vnode *)dp->d_inode;
910 code = gop_lookupname(path, AFS_UIOUSER, follow, &vp);
911 #endif /* AFS_LINUX22_ENV */
912 #endif /* AFS_AIX41_ENV */
916 #if defined(KERNEL_HAVE_UERROR)
924 #if defined(AFS_SUN510_ENV)
925 if (vp && !IsAfsVnode(vp)) {
926 struct vnode *realvp;
928 #ifdef AFS_SUN511_ENV
929 (VOP_REALVP(vp, &realvp, NULL) == 0)
931 (VOP_REALVP(vp, &realvp) == 0)
934 struct vnode *oldvp = vp;
942 /* now make the call if we were passed no file, or were passed an AFS file */
943 if (!vp || IsAfsVnode(vp)) {
944 #if defined(AFS_SUN5_ENV)
945 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
946 #elif defined(AFS_AIX41_ENV)
948 struct ucred *cred1, *cred2;
951 cred1 = cred2 = foreigncreds;
953 cred1 = cred2 = credp;
955 code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
956 if (cred1 != cred2) {
957 /* something changed the creds */
961 #elif defined(AFS_HPUX101_ENV)
963 struct ucred *cred = p_cred(u.u_procp);
964 code = afs_HandlePioctl(vp, com, &data, follow, &cred);
966 #elif defined(AFS_SGI_ENV)
969 credp = OSI_GET_CURRENT_CRED();
970 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
972 #elif defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
973 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
975 code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
978 #if defined(KERNEL_HAVE_UERROR)
981 code = EINVAL; /* not in /afs */
986 #if defined(AFS_NEED_CLIENTCONTEXT)
989 crset(tmpcred); /* restore original credentials */
991 #if defined(AFS_HPUX101_ENV)
992 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
993 #elif defined(AFS_SGI_ENV)
994 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
995 #elif defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
996 credp = tmpcred; /* restore original credentials */
998 osi_curcred() = tmpcred; /* restore original credentials */
999 #endif /* AFS_HPUX101_ENV */
1000 crfree(foreigncreds);
1003 #endif /* AFS_NEED_CLIENTCONTEXT */
1005 #ifdef AFS_LINUX22_ENV
1008 AFS_RELE(vp); /* put vnode back */
1012 #if defined(KERNEL_HAVE_UERROR)
1015 return (getuerror());
1021 #define MAXPIOCTLTOKENLEN \
1022 (3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
1025 afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
1026 register struct afs_ioctl *ablob, int afollow,
1027 struct AFS_UCRED **acred)
1030 struct vrequest treq;
1031 register afs_int32 code;
1032 register afs_int32 function, device;
1033 afs_int32 inSize, outSize, outSizeMax;
1034 char *inData, *outData;
1035 int (*(*pioctlSw)) ();
1037 struct afs_fakestat_state fakestate;
1039 avc = avp ? VTOAFS(avp) : NULL;
1040 afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
1041 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
1042 AFS_STATCNT(HandlePioctl);
1043 if ((code = afs_InitReq(&treq, *acred)))
1045 afs_InitFakeStat(&fakestate);
1047 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
1049 afs_PutFakeStat(&fakestate);
1053 device = (acom & 0xff00) >> 8;
1055 case 'V': /* Original pioctls */
1056 pioctlSw = VpioctlSw;
1057 pioctlSwSize = sizeof(VpioctlSw);
1059 case 'C': /* Coordinated/common pioctls */
1060 pioctlSw = CpioctlSw;
1061 pioctlSwSize = sizeof(CpioctlSw);
1063 case 'O': /* Coordinated/common pioctls */
1064 pioctlSw = OpioctlSw;
1065 pioctlSwSize = sizeof(OpioctlSw);
1068 afs_PutFakeStat(&fakestate);
1071 function = acom & 0xff;
1072 if (function >= (pioctlSwSize / sizeof(char *))) {
1073 afs_PutFakeStat(&fakestate);
1074 return EINVAL; /* out of range */
1076 inSize = ablob->in_size;
1078 /* Do all range checking before continuing */
1079 if (inSize > MAXPIOCTLTOKENLEN || inSize < 0 || ablob->out_size < 0)
1082 /* Note that we use osi_Alloc for large allocs and osi_AllocLargeSpace for small ones */
1083 if (inSize > AFS_LRALLOCSIZ) {
1084 inData = osi_Alloc(inSize + 1);
1086 inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1091 AFS_COPYIN(ablob->in, inData, inSize, code);
1092 inData[inSize] = '\0';
1096 if (inSize > AFS_LRALLOCSIZ) {
1097 osi_Free(inData, inSize + 1);
1099 osi_FreeLargeSpace(inData);
1101 afs_PutFakeStat(&fakestate);
1104 if (function == 8 && device == 'V') { /* PGetTokens */
1105 outSizeMax = MAXPIOCTLTOKENLEN;
1106 outData = osi_Alloc(outSizeMax);
1108 outSizeMax = AFS_LRALLOCSIZ;
1109 outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1112 if (inSize > AFS_LRALLOCSIZ) {
1113 osi_Free(inData, inSize + 1);
1115 osi_FreeLargeSpace(inData);
1117 afs_PutFakeStat(&fakestate);
1122 (*pioctlSw[function]) (avc, function, &treq, inData, outData, inSize,
1124 if (inSize > AFS_LRALLOCSIZ) {
1125 osi_Free(inData, inSize + 1);
1127 osi_FreeLargeSpace(inData);
1129 if (code == 0 && ablob->out_size > 0) {
1130 if (outSize > ablob->out_size) {
1131 code = E2BIG; /* data wont fit in user buffer */
1132 } else if (outSize) {
1133 AFS_COPYOUT(outData, ablob->out, outSize, code);
1136 if (outSizeMax > AFS_LRALLOCSIZ) {
1137 osi_Free(outData, outSizeMax);
1139 osi_FreeLargeSpace(outData);
1141 afs_PutFakeStat(&fakestate);
1142 return afs_CheckCode(code, &treq, 41);
1146 * VIOCETFID (22) - Get file ID quickly
1150 * \param[in] ain not in use
1151 * \param[out] aout not in use
1153 * \retval EINVAL Error if some of the initial arguments aren't set
1155 * \post get the file id of some file
1157 DECL_PIOCTL(PGetFID)
1159 AFS_STATCNT(PGetFID);
1162 memcpy(aout, (char *)&avc->fid, sizeof(struct VenusFid));
1163 *aoutSize = sizeof(struct VenusFid);
1168 * VIOCSETAL (1) - Set access control list
1172 * \param[in] ain the ACL being set
1173 * \param[out] aout the ACL being set returned
1175 * \retval EINVAL Error if some of the standard args aren't set
1177 * \post Changed ACL, via direct writing to the wire
1179 int dummy_PSetAcl(char *ain, char *aout)
1184 DECL_PIOCTL(PSetAcl)
1186 register afs_int32 code;
1188 struct AFSOpaque acl;
1189 struct AFSVolSync tsync;
1190 struct AFSFetchStatus OutStatus;
1193 AFS_STATCNT(PSetAcl);
1196 if ((acl.AFSOpaque_len = strlen(ain) + 1) > 1024 /* AFSOPAQUEMAX */)
1199 acl.AFSOpaque_val = ain;
1201 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1203 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1206 RXAFS_StoreACL(tconn->id, (struct AFSFid *)&avc->fid.Fid,
1207 &acl, &OutStatus, &tsync);
1212 } while (afs_Analyze
1213 (tconn, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_STOREACL,
1214 SHARED_LOCK, NULL));
1216 /* now we've forgotten all of the access info */
1217 ObtainWriteLock(&afs_xcbhash, 455);
1219 afs_DequeueCallback(avc);
1220 avc->states &= ~(CStatd | CUnique);
1221 ReleaseWriteLock(&afs_xcbhash);
1222 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1223 osi_dnlc_purgedp(avc);
1227 int afs_defaultAsynchrony = 0;
1230 * VIOC_STOREBEHIND (47) Adjust store asynchrony
1234 * \param[in] ain sbstruct (store behind structure) input
1235 * \param[out] aout resulting sbstruct
1237 * \retval EPERM Error if the user doesn't have super-user credentials
1238 * \retval EACCES Error if there isn't enough access to not check the mode bits
1240 * \post sets asynchrony based on a file, from a struct sbstruct "I THINK"
1242 DECL_PIOCTL(PStoreBehind)
1245 struct sbstruct *sbr;
1247 sbr = (struct sbstruct *)ain;
1248 if (sbr->sb_default != -1) {
1249 if (afs_osi_suser(*acred))
1250 afs_defaultAsynchrony = sbr->sb_default;
1255 if (avc && (sbr->sb_thisfile != -1)) {
1257 (avc, PRSFS_WRITE | PRSFS_ADMINISTER, areq, DONT_CHECK_MODE_BITS))
1258 avc->asynchrony = sbr->sb_thisfile;
1263 *aoutSize = sizeof(struct sbstruct);
1264 sbr = (struct sbstruct *)aout;
1265 sbr->sb_default = afs_defaultAsynchrony;
1267 sbr->sb_thisfile = avc->asynchrony;
1274 * VIOC_GCPAGS (48) - Disable automatic PAG gc'ing
1278 * \param[in] ain not in use
1279 * \param[out] aout not in use
1281 * \retval EACCES Error if the user doesn't have super-user credentials
1283 * \post set the gcpags to GCPAGS_USERDISABLED
1285 DECL_PIOCTL(PGCPAGs)
1287 if (!afs_osi_suser(*acred)) {
1290 afs_gcpags = AFS_GCPAGS_USERDISABLED;
1295 * VIOCGETAL (2) - Get access control list
1299 * \param[in] ain not in use
1300 * \param[out] aout the ACL
1302 * \retval EINVAL Error if some of the standard args aren't set
1303 * \retval ERANGE Error if the vnode of the file id is too large
1304 * \retval -1 Error if getting the ACL failed
1306 * \post Obtain the ACL, based on file ID
1308 * \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
1310 DECL_PIOCTL(PGetAcl)
1312 struct AFSOpaque acl;
1313 struct AFSVolSync tsync;
1314 struct AFSFetchStatus OutStatus;
1320 AFS_STATCNT(PGetAcl);
1323 Fid.Volume = avc->fid.Fid.Volume;
1324 Fid.Vnode = avc->fid.Fid.Vnode;
1325 Fid.Unique = avc->fid.Fid.Unique;
1326 if (avc->states & CForeign) {
1328 * For a dfs xlator acl we have a special hack so that the
1329 * xlator will distinguish which type of acl will return. So
1330 * we currently use the top 2-bytes (vals 0-4) to tell which
1331 * type of acl to bring back. Horrible hack but this will
1332 * cause the least number of changes to code size and interfaces.
1334 if (Fid.Vnode & 0xc0000000)
1336 Fid.Vnode |= (ainSize << 30);
1338 acl.AFSOpaque_val = aout;
1340 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1343 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1345 code = RXAFS_FetchACL(tconn->id, &Fid, &acl, &OutStatus, &tsync);
1350 } while (afs_Analyze
1351 (tconn, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_FETCHACL,
1352 SHARED_LOCK, NULL));
1355 *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1361 * PNoop returns success. Used for functions which are not implemented or are no longer in use.
1365 * \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
1374 * PBogus returns fail. Used for functions which are not implemented or are no longer in use.
1378 * \retval EINVAL Error if some of the standard args aren't set
1380 * \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;
1384 AFS_STATCNT(PBogus);
1389 * VIOC_FILE_CELL_NAME (30) - Get cell in which file lives
1393 * \param[in] ain not in use (avc used to pass in file id)
1394 * \param[out] aout cell name
1396 * \retval EINVAL Error if some of the standard args aren't set
1397 * \retval ESRCH Error if the file isn't part of a cell
1399 * \post Get a cell based on a passed in file id
1401 DECL_PIOCTL(PGetFileCell)
1403 register struct cell *tcell;
1405 AFS_STATCNT(PGetFileCell);
1408 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
1411 strcpy(aout, tcell->cellName);
1412 afs_PutCell(tcell, READ_LOCK);
1413 *aoutSize = strlen(aout) + 1;
1418 * VIOC_GET_WS_CELL (31) - Get cell in which workstation lives
1422 * \param[in] ain not in use
1423 * \param[out] aout cell name
1425 * \retval EIO Error if the afs daemon hasn't started yet
1426 * \retval ESRCH Error if the machine isn't part of a cell, for whatever reason
1428 * \post Get the primary cell that the machine is a part of.
1430 DECL_PIOCTL(PGetWSCell)
1432 struct cell *tcell = NULL;
1434 AFS_STATCNT(PGetWSCell);
1435 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1436 return EIO; /* Inappropriate ioctl for device */
1438 tcell = afs_GetPrimaryCell(READ_LOCK);
1439 if (!tcell) /* no primary cell? */
1441 strcpy(aout, tcell->cellName);
1442 *aoutSize = strlen(aout) + 1;
1443 afs_PutCell(tcell, READ_LOCK);
1448 * VIOC_GET_PRIMARY_CELL (33) - Get primary cell for caller
1452 * \param[in] ain not in use (user id found via areq)
1453 * \param[out] aout cell name
1455 * \retval ESRCH Error if the user id doesn't have a primary cell specified
1457 * \post Get the primary cell for a certain user, based on the user's uid
1459 DECL_PIOCTL(PGetUserCell)
1461 register afs_int32 i;
1462 register struct unixuser *tu;
1463 register struct cell *tcell;
1465 AFS_STATCNT(PGetUserCell);
1466 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1467 return EIO; /* Inappropriate ioctl for device */
1469 /* return the cell name of the primary cell for this user */
1470 i = UHash(areq->uid);
1471 ObtainWriteLock(&afs_xuser, 224);
1472 for (tu = afs_users[i]; tu; tu = tu->next) {
1473 if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1475 ReleaseWriteLock(&afs_xuser);
1480 tcell = afs_GetCell(tu->cell, READ_LOCK);
1481 afs_PutUser(tu, WRITE_LOCK);
1485 strcpy(aout, tcell->cellName);
1486 afs_PutCell(tcell, READ_LOCK);
1487 *aoutSize = strlen(aout) + 1; /* 1 for the null */
1490 ReleaseWriteLock(&afs_xuser);
1498 * VIOCSETTOK (3) - Set authentication tokens
1502 * \param[in] ain the krb tickets from which to set the afs tokens
1503 * \param[out] aout not in use
1505 * \retval EINVAL Error if the ticket is either too long or too short
1506 * \retval EIO Error if the AFS initState is below 101
1507 * \retval ESRCH Error if the cell for which the Token is being set can't be found
1509 * \post Set the Tokens for a specific cell name, unless there is none set, then default to primary
1512 DECL_PIOCTL(PSetTokens)
1515 register struct unixuser *tu;
1516 struct ClearToken clear;
1517 register struct cell *tcell;
1520 struct vrequest treq;
1521 afs_int32 flag, set_parent_pag = 0;
1523 AFS_STATCNT(PSetTokens);
1524 if (!afs_resourceinit_flag) {
1527 memcpy((char *)&i, ain, sizeof(afs_int32));
1528 ain += sizeof(afs_int32);
1529 stp = ain; /* remember where the ticket is */
1530 if (i < 0 || i > MAXKTCTICKETLEN)
1531 return EINVAL; /* malloc may fail */
1533 ain += i; /* skip over ticket */
1534 memcpy((char *)&i, ain, sizeof(afs_int32));
1535 ain += sizeof(afs_int32);
1536 if (i != sizeof(struct ClearToken)) {
1539 memcpy((char *)&clear, ain, sizeof(struct ClearToken));
1540 if (clear.AuthHandle == -1)
1541 clear.AuthHandle = 999; /* more rxvab compat stuff */
1542 ain += sizeof(struct ClearToken);
1543 if (ainSize != 2 * sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1544 /* still stuff left? we've got primary flag and cell name. Set these */
1545 memcpy((char *)&flag, ain, sizeof(afs_int32)); /* primary id flag */
1546 ain += sizeof(afs_int32); /* skip id field */
1547 /* rest is cell name, look it up */
1548 /* some versions of gcc appear to need != 0 in order to get this right */
1549 if ((flag & 0x8000) != 0) { /* XXX Use Constant XXX */
1553 tcell = afs_GetCellByName(ain, READ_LOCK);
1557 /* default to primary cell, primary id */
1558 flag = 1; /* primary id */
1559 tcell = afs_GetPrimaryCell(READ_LOCK);
1564 afs_PutCell(tcell, READ_LOCK);
1565 if (set_parent_pag) {
1567 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1568 #if defined(AFS_DARWIN_ENV)
1569 struct proc *p = current_proc(); /* XXX */
1571 struct proc *p = curproc; /* XXX */
1573 #ifndef AFS_DARWIN80_ENV
1574 uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1575 p->p_pid, p->p_comm);
1577 if (!setpag(p, acred, -1, &pag, 1)) {
1580 if (!setpag(u.u_procp, acred, -1, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
1582 if (!setpag(acred, -1, &pag, 1)) {
1585 afs_InitReq(&treq, *acred);
1589 /* now we just set the tokens */
1590 tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1591 tu->vid = clear.ViceId;
1592 if (tu->stp != NULL) {
1593 afs_osi_Free(tu->stp, tu->stLen);
1595 tu->stp = (char *)afs_osi_Alloc(stLen);
1596 if (tu->stp == NULL) {
1600 memcpy(tu->stp, stp, stLen);
1603 afs_stats_cmfullperf.authent.TicketUpdates++;
1604 afs_ComputePAGStats();
1605 #endif /* AFS_NOSTATS */
1606 tu->states |= UHasTokens;
1607 tu->states &= ~UTokensBad;
1608 afs_SetPrimary(tu, flag);
1609 tu->tokenTime = osi_Time();
1610 afs_ResetUserConns(tu);
1611 afs_PutUser(tu, WRITE_LOCK);
1627 * VIOCGETVOLSTAT (4) - Get volume status
1631 * \param[in] ain not in use
1632 * \param[out] aout status of the volume
1634 * \retval EINVAL Error if some of the standard args aren't set
1636 * \post The status of a volume (based on the FID of the volume), or an offline message /motd
1638 DECL_PIOCTL(PGetVolumeStatus)
1641 char *offLineMsg = afs_osi_Alloc(256);
1642 char *motd = afs_osi_Alloc(256);
1643 register struct conn *tc;
1644 register afs_int32 code = 0;
1645 struct AFSFetchVolumeStatus volstat;
1647 char *Name, *OfflineMsg, *MOTD;
1650 AFS_STATCNT(PGetVolumeStatus);
1656 OfflineMsg = offLineMsg;
1659 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1661 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1664 RXAFS_GetVolumeStatus(tc->id, avc->fid.Fid.Volume, &volstat,
1665 &Name, &OfflineMsg, &MOTD);
1670 } while (afs_Analyze
1671 (tc, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1672 SHARED_LOCK, NULL));
1676 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1678 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1679 cp += sizeof(VolumeStatus);
1680 strcpy(cp, volName);
1681 cp += strlen(volName) + 1;
1682 strcpy(cp, offLineMsg);
1683 cp += strlen(offLineMsg) + 1;
1685 cp += strlen(motd) + 1;
1686 *aoutSize = (cp - aout);
1688 afs_osi_Free(offLineMsg, 256);
1689 afs_osi_Free(motd, 256);
1694 * VIOCSETVOLSTAT (5) - Set volume status
1698 * \param[in] ain values to set the status at, offline message, message of the day, volume name, minimum quota, maximum quota
1699 * \param[out] aout status of a volume, offlines messages, minimum quota, maximumm quota
1701 * \retval EINVAL Error if some of the standard args aren't set
1702 * \retval EROFS Error if the volume is read only, or a backup volume
1703 * \retval ENODEV Error if the volume can't be accessed
1704 * \retval E2BIG Error if the volume name, offline message, and motd are too big
1706 * \post Set the status of a volume, including any offline messages, a minimum quota, and a maximum quota
1708 DECL_PIOCTL(PSetVolumeStatus)
1711 char *offLineMsg = afs_osi_Alloc(256);
1712 char *motd = afs_osi_Alloc(256);
1713 register struct conn *tc;
1714 register afs_int32 code = 0;
1715 struct AFSFetchVolumeStatus volstat;
1716 struct AFSStoreVolumeStatus storeStat;
1717 register struct volume *tvp;
1721 AFS_STATCNT(PSetVolumeStatus);
1727 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
1729 if (tvp->states & (VRO | VBackup)) {
1730 afs_PutVolume(tvp, READ_LOCK);
1734 afs_PutVolume(tvp, READ_LOCK);
1739 /* Copy the junk out, using cp as a roving pointer. */
1741 memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
1742 cp += sizeof(AFSFetchVolumeStatus);
1743 if (strlen(cp) >= sizeof(volName)) {
1747 strcpy(volName, cp);
1748 cp += strlen(volName) + 1;
1749 if (strlen(cp) >= sizeof(offLineMsg)) {
1753 strcpy(offLineMsg, cp);
1754 cp += strlen(offLineMsg) + 1;
1755 if (strlen(cp) >= sizeof(motd)) {
1761 if (volstat.MinQuota != -1) {
1762 storeStat.MinQuota = volstat.MinQuota;
1763 storeStat.Mask |= AFS_SETMINQUOTA;
1765 if (volstat.MaxQuota != -1) {
1766 storeStat.MaxQuota = volstat.MaxQuota;
1767 storeStat.Mask |= AFS_SETMAXQUOTA;
1770 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1772 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1775 RXAFS_SetVolumeStatus(tc->id, avc->fid.Fid.Volume, &storeStat,
1776 volName, offLineMsg, motd);
1781 } while (afs_Analyze
1782 (tc, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1783 SHARED_LOCK, NULL));
1787 /* we are sending parms back to make compat. with prev system. should
1788 * change interface later to not ask for current status, just set new status */
1790 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1791 cp += sizeof(VolumeStatus);
1792 strcpy(cp, volName);
1793 cp += strlen(volName) + 1;
1794 strcpy(cp, offLineMsg);
1795 cp += strlen(offLineMsg) + 1;
1797 cp += strlen(motd) + 1;
1798 *aoutSize = cp - aout;
1800 afs_osi_Free(offLineMsg, 256);
1801 afs_osi_Free(motd, 256);
1806 * VIOCFLUSH (6) - Invalidate cache entry
1810 * \param[in] ain not in use
1811 * \param[out] aout not in use
1813 * \retval EINVAL Error if some of the standard args aren't set
1815 * \post Flush any information the cache manager has on an entry
1819 AFS_STATCNT(PFlush);
1822 #ifdef AFS_BOZONLOCK_ENV
1823 afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
1825 ObtainWriteLock(&avc->lock, 225);
1826 ObtainWriteLock(&afs_xcbhash, 456);
1827 afs_DequeueCallback(avc);
1828 avc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
1829 ReleaseWriteLock(&afs_xcbhash);
1830 /* now find the disk cache entries */
1831 afs_TryToSmush(avc, *acred, 1);
1832 osi_dnlc_purgedp(avc);
1833 if (avc->linkData && !(avc->states & CCore)) {
1834 afs_osi_Free(avc->linkData, strlen(avc->linkData) + 1);
1835 avc->linkData = NULL;
1837 ReleaseWriteLock(&avc->lock);
1838 #ifdef AFS_BOZONLOCK_ENV
1839 afs_BozonUnlock(&avc->pvnLock, avc);
1845 * VIOC_AFS_STAT_MT_PT (29) - Stat mount point
1849 * \param[in] ain the last component in a path, related to mountpoint that we're looking for information about
1850 * \param[out] aout volume, cell, link data
1852 * \retval EINVAL Error if some of the standard args aren't set
1853 * \retval ENOTDIR Error if the 'mount point' argument isn't a directory
1854 * \retval EIO Error if the link data can't be accessed
1856 * \post Get the volume, and cell, as well as the link data for a mount point
1858 DECL_PIOCTL(PNewStatMount)
1860 register afs_int32 code;
1861 register struct vcache *tvc;
1862 register struct dcache *tdc;
1863 struct VenusFid tfid;
1865 struct sysname_info sysState;
1866 afs_size_t offset, len;
1868 AFS_STATCNT(PNewStatMount);
1871 code = afs_VerifyVCache(avc, areq);
1874 if (vType(avc) != VDIR) {
1877 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
1880 Check_AtSys(avc, ain, &sysState, areq);
1881 ObtainReadLock(&tdc->lock);
1883 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
1884 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1885 ReleaseReadLock(&tdc->lock);
1886 afs_PutDCache(tdc); /* we're done with the data */
1887 bufp = sysState.name;
1891 tfid.Cell = avc->fid.Cell;
1892 tfid.Fid.Volume = avc->fid.Fid.Volume;
1893 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
1894 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
1896 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
1902 if (tvc->mvstat != 1) {
1907 ObtainWriteLock(&tvc->lock, 226);
1908 code = afs_HandleLink(tvc, areq);
1910 if (tvc->linkData) {
1911 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1914 /* we have the data */
1915 strcpy(aout, tvc->linkData);
1916 *aoutSize = strlen(tvc->linkData) + 1;
1921 ReleaseWriteLock(&tvc->lock);
1924 if (sysState.allocked)
1925 osi_FreeLargeSpace(bufp);
1930 * VIOCGETTOK (8) - Get authentication tokens
1934 * \param[in] ain userid
1935 * \param[out] aout token
1937 * \retval EIO Error if the afs daemon hasn't started yet
1938 * \retval EDOM Error if the input parameter is out of the bounds of the available tokens
1939 * \retval ENOTCONN Error if there aren't tokens for this cell
1941 * \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
1943 * \notes "it's a weird interface (from comments in the code)"
1946 DECL_PIOCTL(PGetTokens)
1948 register struct cell *tcell;
1949 register afs_int32 i;
1950 register struct unixuser *tu;
1955 AFS_STATCNT(PGetTokens);
1956 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1957 return EIO; /* Inappropriate ioctl for device */
1959 /* weird interface. If input parameter is present, it is an integer and
1960 * we're supposed to return the parm'th tokens for this unix uid.
1961 * If not present, we just return tokens for cell 1.
1962 * If counter out of bounds, return EDOM.
1963 * If no tokens for the particular cell, return ENOTCONN.
1964 * Also, if this mysterious parm is present, we return, along with the
1965 * tokens, the primary cell indicator (an afs_int32 0) and the cell name
1966 * at the end, in that order.
1968 if ((newStyle = (ainSize > 0))) {
1969 memcpy((char *)&iterator, ain, sizeof(afs_int32));
1971 i = UHash(areq->uid);
1972 ObtainReadLock(&afs_xuser);
1973 for (tu = afs_users[i]; tu; tu = tu->next) {
1975 if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1976 if (iterator-- == 0)
1977 break; /* are we done yet? */
1980 if (tu->uid == areq->uid && afs_IsPrimaryCellNum(tu->cell))
1986 * No need to hold a read lock on each user entry
1990 ReleaseReadLock(&afs_xuser);
1995 if (((tu->states & UHasTokens) == 0)
1996 || (tu->ct.EndTimestamp < osi_Time())) {
1997 tu->states |= (UTokensBad | UNeedsReset);
1998 afs_PutUser(tu, READ_LOCK);
2001 /* use iterator for temp */
2003 iterator = tu->stLen; /* for compat, we try to return 56 byte tix if they fit */
2005 iterator = 56; /* # of bytes we're returning */
2006 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
2007 cp += sizeof(afs_int32);
2008 memcpy(cp, tu->stp, tu->stLen); /* copy out st */
2010 iterator = sizeof(struct ClearToken);
2011 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
2012 cp += sizeof(afs_int32);
2013 memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
2014 cp += sizeof(struct ClearToken);
2016 /* put out primary id and cell name, too */
2017 iterator = (tu->states & UPrimary ? 1 : 0);
2018 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
2019 cp += sizeof(afs_int32);
2020 tcell = afs_GetCell(tu->cell, READ_LOCK);
2022 strcpy(cp, tcell->cellName);
2023 cp += strlen(tcell->cellName) + 1;
2024 afs_PutCell(tcell, READ_LOCK);
2028 *aoutSize = cp - aout;
2029 afs_PutUser(tu, READ_LOCK);
2034 * VIOCUNLOG (9) - Invalidate tokens
2038 * \param[in] ain not in use
2039 * \param[out] aout not in use
2041 * \retval EIO Error if the afs daemon hasn't been started yet
2043 * \post remove tokens from a user, specified by the user id
2045 * \notes sets the token's time to 0, which then causes it to be removed
2046 * \notes Unlog is the same as un-pag in OpenAFS
2050 register afs_int32 i;
2051 register struct unixuser *tu;
2053 AFS_STATCNT(PUnlog);
2054 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2055 return EIO; /* Inappropriate ioctl for device */
2057 i = UHash(areq->uid);
2058 ObtainWriteLock(&afs_xuser, 227);
2059 for (tu = afs_users[i]; tu; tu = tu->next) {
2060 if (tu->uid == areq->uid) {
2062 tu->states &= ~UHasTokens;
2063 /* security is not having to say you're sorry */
2064 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
2066 ReleaseWriteLock(&afs_xuser);
2067 /* We have to drop the lock over the call to afs_ResetUserConns, since
2068 * it obtains the afs_xvcache lock. We could also keep the lock, and
2069 * modify ResetUserConns to take parm saying we obtained the lock
2070 * already, but that is overkill. By keeping the "tu" pointer
2071 * held over the released lock, we guarantee that we won't lose our
2072 * place, and that we'll pass over every user conn that existed when
2073 * we began this call.
2075 afs_ResetUserConns(tu);
2077 ObtainWriteLock(&afs_xuser, 228);
2079 /* set the expire times to 0, causes
2080 * afs_GCUserData to remove this entry
2082 tu->ct.EndTimestamp = 0;
2084 #endif /* UKERNEL */
2087 ReleaseWriteLock(&afs_xuser);
2092 * VIOC_AFS_MARINER_HOST (32) - Get/set mariner (cache manager monitor) host
2096 * \param[in] ain host address to be set
2097 * \param[out] aout old host address
2099 * \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
2101 * \notes Errors turn off mariner
2103 DECL_PIOCTL(PMariner)
2105 afs_int32 newHostAddr;
2106 afs_int32 oldHostAddr;
2108 AFS_STATCNT(PMariner);
2110 memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost,
2113 oldHostAddr = 0xffffffff; /* disabled */
2115 memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
2116 if (newHostAddr == 0xffffffff) {
2117 /* disable mariner operations */
2119 } else if (newHostAddr) {
2121 afs_marinerHost = newHostAddr;
2123 memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
2124 *aoutSize = sizeof(afs_int32);
2129 * VIOCCKSERV (10) - Check that servers are up
2133 * \param[in] ain name of the cell
2134 * \param[out] aout current down server list
2136 * \retval EIO Error if the afs daemon hasn't started yet
2137 * \retval EACCES Error if the user doesn't have super-user credentials
2138 * \retval ENOENT Error if we are unable to obtain the cell
2140 * \post Either a fast check (where it doesn't contact servers) or a local check (checks local cell only)
2142 DECL_PIOCTL(PCheckServers)
2144 register char *cp = 0;
2146 register struct server *ts;
2147 afs_int32 temp, *lp = (afs_int32 *) ain, havecell = 0;
2149 struct chservinfo *pcheck;
2151 AFS_STATCNT(PCheckServers);
2153 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2154 return EIO; /* Inappropriate ioctl for device */
2156 if (*lp == 0x12345678) { /* For afs3.3 version */
2157 pcheck = (struct chservinfo *)ain;
2158 if (pcheck->tinterval >= 0) {
2160 memcpy(cp, (char *)&afs_probe_interval, sizeof(afs_int32));
2161 *aoutSize = sizeof(afs_int32);
2162 if (pcheck->tinterval > 0) {
2163 if (!afs_osi_suser(*acred))
2165 afs_probe_interval = pcheck->tinterval;
2171 temp = pcheck->tflags;
2172 cp = pcheck->tbuffer;
2173 } else { /* For pre afs3.3 versions */
2174 memcpy((char *)&temp, ain, sizeof(afs_int32));
2175 cp = ain + sizeof(afs_int32);
2176 if (ainSize > sizeof(afs_int32))
2181 * 1: fast check, don't contact servers.
2182 * 2: local cell only.
2185 /* have cell name, too */
2186 cellp = afs_GetCellByName(cp, READ_LOCK);
2191 if (!cellp && (temp & 2)) {
2192 /* use local cell */
2193 cellp = afs_GetPrimaryCell(READ_LOCK);
2195 if (!(temp & 1)) { /* if not fast, call server checker routine */
2196 afs_CheckServers(1, cellp); /* check down servers */
2197 afs_CheckServers(0, cellp); /* check up servers */
2199 /* now return the current down server list */
2201 ObtainReadLock(&afs_xserver);
2202 for (i = 0; i < NSERVERS; i++) {
2203 for (ts = afs_servers[i]; ts; ts = ts->next) {
2204 if (cellp && ts->cell != cellp)
2205 continue; /* cell spec'd and wrong */
2206 if ((ts->flags & SRVR_ISDOWN)
2207 && ts->addr->sa_portal != ts->cell->vlport) {
2208 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2209 cp += sizeof(afs_int32);
2213 ReleaseReadLock(&afs_xserver);
2215 afs_PutCell(cellp, READ_LOCK);
2216 *aoutSize = cp - aout;
2221 * VIOCCKBACK (11) - Check backup volume mappings
2225 * \param[in] ain not in use
2226 * \param[out] aout not in use
2228 * \retval EIO Error if the afs daemon hasn't started yet
2230 * \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
2232 DECL_PIOCTL(PCheckVolNames)
2234 AFS_STATCNT(PCheckVolNames);
2235 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2236 return EIO; /* Inappropriate ioctl for device */
2238 afs_CheckRootVolume();
2239 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE | AFS_VOLCHECK_EXPIRED |
2240 AFS_VOLCHECK_BUSY | AFS_VOLCHECK_MTPTS);
2245 * VIOCCKCONN (12) - Check connections for a user
2249 * \param[in] ain not in use
2250 * \param[out] aout not in use
2252 * \retval EACCESS Error if no user is specififed, the user has no tokens set, or if the user's tokens are bad
2254 * \post check to see if a user has the correct authentication. If so, allow access.
2256 * \notes Check the connections to all the servers specified
2258 DECL_PIOCTL(PCheckAuth)
2263 struct unixuser *tu;
2266 AFS_STATCNT(PCheckAuth);
2267 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2268 return EIO; /* Inappropriate ioctl for device */
2271 tu = afs_GetUser(areq->uid, 1, READ_LOCK); /* check local cell authentication */
2275 /* we have a user */
2276 ObtainReadLock(&afs_xsrvAddr);
2277 ObtainReadLock(&afs_xconn);
2279 /* any tokens set? */
2280 if ((tu->states & UHasTokens) == 0)
2282 /* all connections in cell 1 working? */
2283 for (i = 0; i < NSERVERS; i++) {
2284 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2285 for (tc = sa->conns; tc; tc = tc->next) {
2286 if (tc->user == tu && (tu->states & UTokensBad))
2291 ReleaseReadLock(&afs_xsrvAddr);
2292 ReleaseReadLock(&afs_xconn);
2293 afs_PutUser(tu, READ_LOCK);
2295 memcpy(aout, (char *)&retValue, sizeof(afs_int32));
2296 *aoutSize = sizeof(afs_int32);
2301 Prefetch(char *apath, struct afs_ioctl *adata, int afollow,
2302 struct AFS_UCRED *acred)
2305 register afs_int32 code;
2306 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
2312 AFS_STATCNT(Prefetch);
2315 tp = osi_AllocLargeSpace(1024);
2316 AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2318 osi_FreeLargeSpace(tp);
2321 if (afs_BBusy()) { /* do this as late as possible */
2322 osi_FreeLargeSpace(tp);
2323 return EWOULDBLOCK; /* pretty close */
2325 afs_BQueue(BOP_PATH, (struct vcache *)0, 0, 0, acred, (afs_size_t) 0,
2326 (afs_size_t) 0, tp);
2331 * VIOCWHEREIS (14) - Find out where a volume is located
2335 * \param[in] ain not in use
2336 * \param[out] aout volume location
2338 * \retval EINVAL Error if some of the default arguments don't exist
2339 * \retval ENODEV Error if there is no such volume
2341 * \post fine a volume, based on a volume file id
2343 * \notes check each of the servers specified
2345 DECL_PIOCTL(PFindVolume)
2347 register struct volume *tvp;
2348 register struct server *ts;
2349 register afs_int32 i;
2352 AFS_STATCNT(PFindVolume);
2355 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
2358 for (i = 0; i < MAXHOSTS; i++) {
2359 ts = tvp->serverHost[i];
2362 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2363 cp += sizeof(afs_int32);
2366 /* still room for terminating NULL, add it on */
2367 ainSize = 0; /* reuse vbl */
2368 memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
2369 cp += sizeof(afs_int32);
2371 *aoutSize = cp - aout;
2372 afs_PutVolume(tvp, READ_LOCK);
2379 * VIOCACCESS (20) - Access using PRS_FS bits
2383 * \param[in] ain PRS_FS bits
2384 * \param[out] aout not in use
2386 * \retval EINVAL Error if some of the initial arguments aren't set
2387 * \retval EACCES Error if access is denied
2389 * \post check to make sure access is allowed
2391 DECL_PIOCTL(PViceAccess)
2393 register afs_int32 code;
2396 AFS_STATCNT(PViceAccess);
2399 code = afs_VerifyVCache(avc, areq);
2402 memcpy((char *)&temp, ain, sizeof(afs_int32));
2403 code = afs_AccessOK(avc, temp, areq, CHECK_MODE_BITS);
2410 DECL_PIOCTL(PPrecache)
2414 /*AFS_STATCNT(PPrecache);*/
2415 if (!afs_osi_suser(*acred))
2417 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2418 afs_preCache = newValue*1024;
2423 * VIOCSETCACHESIZE (24) - Set venus cache size in 1000 units
2427 * \param[in] ain the size the venus cache should be set to
2428 * \param[out] aout not in use
2430 * \retval EACCES Error if the user doesn't have super-user credentials
2431 * \retval EROFS Error if the cache is set to be in memory
2433 * \post Set the cache size based on user input. If no size is given, set it to the default OpenAFS cache size.
2435 * \notes recompute the general cache parameters for every single block allocated
2437 DECL_PIOCTL(PSetCacheSize)
2442 AFS_STATCNT(PSetCacheSize);
2443 if (!afs_osi_suser(*acred))
2445 /* too many things are setup initially in mem cache version */
2446 if (cacheDiskType == AFS_FCACHE_TYPE_MEM)
2448 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2450 afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2452 if (newValue < afs_min_cache)
2453 afs_cacheBlocks = afs_min_cache;
2455 afs_cacheBlocks = newValue;
2457 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2458 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2459 afs_MaybeWakeupTruncateDaemon();
2460 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2461 afs_osi_Wait(1000, 0, 0);
2462 afs_MaybeWakeupTruncateDaemon();
2467 #define MAXGCSTATS 16
2469 * VIOCGETCACHEPARMS (40) - Get cache stats
2473 * \param[in] ain afs index flags
2474 * \param[out] aout cache blocks, blocks used, blocks files (in an array)
2476 * \post Get the cache blocks, and how many of the cache blocks there are
2478 DECL_PIOCTL(PGetCacheSize)
2480 afs_int32 results[MAXGCSTATS];
2482 register struct dcache * tdc;
2485 AFS_STATCNT(PGetCacheSize);
2487 if (sizeof(afs_int32) == ainSize){
2488 memcpy((char *)&flags, ain, sizeof(afs_int32));
2489 } else if (0 == ainSize){
2495 memset((char *)results, 0, sizeof(results));
2496 results[0] = afs_cacheBlocks;
2497 results[1] = afs_blocksUsed;
2498 results[2] = afs_cacheFiles;
2501 for (i = 0; i < afs_cacheFiles; i++) {
2502 if (afs_indexFlags[i] & IFFree) results[3]++;
2504 } else if (2 == flags){
2505 for (i = 0; i < afs_cacheFiles; i++) {
2506 if (afs_indexFlags[i] & IFFree) results[3]++;
2507 if (afs_indexFlags[i] & IFEverUsed) results[4]++;
2508 if (afs_indexFlags[i] & IFDataMod) results[5]++;
2509 if (afs_indexFlags[i] & IFDirtyPages) results[6]++;
2510 if (afs_indexFlags[i] & IFAnyPages) results[7]++;
2511 if (afs_indexFlags[i] & IFDiscarded) results[8]++;
2513 tdc = afs_indexTable[i];
2516 size = tdc->validPos;
2517 if ( 0 < size && size < (1<<12) ) results[10]++;
2518 else if (size < (1<<14) ) results[11]++;
2519 else if (size < (1<<16) ) results[12]++;
2520 else if (size < (1<<18) ) results[13]++;
2521 else if (size < (1<<20) ) results[14]++;
2522 else if (size >= (1<<20) ) results[15]++;
2526 memcpy(aout, (char *)results, sizeof(results));
2527 *aoutSize = sizeof(results);
2532 * VIOCFLUSHCB (25) - Flush callback only
2536 * \param[in] ain not in use
2537 * \param[out] aout not in use
2539 * \retval EINVAL Error if some of the standard args aren't set
2540 * \retval 0 0 returned if the volume is set to read-only
2542 * \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.
2544 DECL_PIOCTL(PRemoveCallBack)
2546 register struct conn *tc;
2547 register afs_int32 code = 0;
2548 struct AFSCallBack CallBacks_Array[1];
2549 struct AFSCBFids theFids;
2550 struct AFSCBs theCBs;
2553 AFS_STATCNT(PRemoveCallBack);
2556 if (avc->states & CRO)
2557 return 0; /* read-only-ness can't change */
2558 ObtainWriteLock(&avc->lock, 229);
2559 theFids.AFSCBFids_len = 1;
2560 theCBs.AFSCBs_len = 1;
2561 theFids.AFSCBFids_val = (struct AFSFid *)&avc->fid.Fid;
2562 theCBs.AFSCBs_val = CallBacks_Array;
2563 CallBacks_Array[0].CallBackType = CB_DROPPED;
2564 if (avc->callback) {
2566 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2568 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2570 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2574 /* don't set code on failure since we wouldn't use it */
2575 } while (afs_Analyze
2576 (tc, code, &avc->fid, areq,
2577 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK, NULL));
2579 ObtainWriteLock(&afs_xcbhash, 457);
2580 afs_DequeueCallback(avc);
2582 avc->states &= ~(CStatd | CUnique);
2583 ReleaseWriteLock(&afs_xcbhash);
2584 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2585 osi_dnlc_purgedp(avc);
2587 ReleaseWriteLock(&avc->lock);
2592 * VIOCNEWCELL (26) - Configure new cell
2596 * \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
2597 * \param[out] aout not in use
2599 * \retval EIO Error if the afs daemon hasn't started yet
2600 * \retval EACCES Error if the user doesn't have super-user cedentials
2601 * \retval EINVAL Error if some 'magic' var doesn't have a certain bit set
2603 * \post creates a new cell
2605 DECL_PIOCTL(PNewCell)
2607 /* create a new cell */
2608 afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic = 0;
2609 char *newcell = 0, *linkedcell = 0, *tp = ain;
2610 register afs_int32 code, linkedstate = 0, ls;
2611 u_short fsport = 0, vlport = 0;
2614 AFS_STATCNT(PNewCell);
2615 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2616 return EIO; /* Inappropriate ioctl for device */
2618 if (!afs_osi_suser(*acred))
2621 memcpy((char *)&magic, tp, sizeof(afs_int32));
2622 tp += sizeof(afs_int32);
2623 if (magic != 0x12345678)
2626 /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2627 * server addresses while the 3.5 fs newcell command passes
2628 * MAXHOSTS. To figure out which is which, check if the cellname
2631 newcell = tp + (MAXCELLHOSTS + 3) * sizeof(afs_int32);
2632 scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2634 /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2635 memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
2636 tp += (scount * sizeof(afs_int32));
2638 lp = (afs_int32 *) tp;
2642 fsport = 0; /* Privileged ports not allowed */
2644 vlport = 0; /* Privileged ports not allowed */
2645 tp += (3 * sizeof(afs_int32));
2647 if ((ls = *lp) & 1) {
2648 linkedcell = tp + strlen(newcell) + 1;
2649 linkedstate |= CLinkedCell;
2652 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2654 afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport,
2659 DECL_PIOCTL(PNewAlias)
2661 /* create a new cell alias */
2663 register afs_int32 code;
2664 char *realName, *aliasName;
2666 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2667 return EIO; /* Inappropriate ioctl for device */
2669 if (!afs_osi_suser(*acred))
2673 tp += strlen(aliasName) + 1;
2676 code = afs_NewCellAlias(aliasName, realName);
2682 * VIOCGETCELL (27) - Get cell info
2686 * \param[in] ain The cell index of a specific cell
2687 * \param[out] aout list of servers in the cell
2689 * \retval EIO Error if the afs daemon hasn't started yet
2690 * \retval EDOM Error if there is no cell asked about
2692 * \post Lists the cell's server names and and addresses
2694 DECL_PIOCTL(PListCells)
2696 afs_int32 whichCell;
2697 register struct cell *tcell = 0;
2698 register afs_int32 i;
2699 register char *cp, *tp = ain;
2701 AFS_STATCNT(PListCells);
2702 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2703 return EIO; /* Inappropriate ioctl for device */
2705 memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2706 tp += sizeof(afs_int32);
2707 tcell = afs_GetCellByIndex(whichCell, READ_LOCK);
2710 memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
2711 for (i = 0; i < MAXCELLHOSTS; i++) {
2712 if (tcell->cellHosts[i] == 0)
2714 memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip,
2716 cp += sizeof(afs_int32);
2718 cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2719 strcpy(cp, tcell->cellName);
2720 cp += strlen(tcell->cellName) + 1;
2721 *aoutSize = cp - aout;
2722 afs_PutCell(tcell, READ_LOCK);
2730 DECL_PIOCTL(PListAliases)
2732 afs_int32 whichAlias;
2733 register struct cell_alias *tcalias = 0;
2734 register char *cp, *tp = ain;
2736 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2737 return EIO; /* Inappropriate ioctl for device */
2738 if (ainSize < sizeof(afs_int32))
2741 memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2742 tp += sizeof(afs_int32);
2744 tcalias = afs_GetCellAlias(whichAlias);
2747 strcpy(cp, tcalias->alias);
2748 cp += strlen(tcalias->alias) + 1;
2749 strcpy(cp, tcalias->cell);
2750 cp += strlen(tcalias->cell) + 1;
2751 *aoutSize = cp - aout;
2752 afs_PutCellAlias(tcalias);
2761 * VIOC_AFS_DELETE_MT_PT (28) - Delete mount point
2765 * \param[in] ain the name of the file in this dir to remove
2766 * \param[out] aout not in use
2768 * \retval EINVAL Error if some of the standard args aren't set
2769 * \retval ENOTDIR Error if the argument to remove is not a directory
2770 * \retval ENOENT Error if there is no cache to remove the mount point from or if a vcache doesn't exist
2772 * \post Ensure that everything is OK before deleting the mountpoint. If not, don't delete. Delete a mount point based on a file id.
2774 DECL_PIOCTL(PRemoveMount)
2776 register afs_int32 code;
2778 struct sysname_info sysState;
2779 afs_size_t offset, len;
2780 register struct conn *tc;
2781 register struct dcache *tdc;
2782 register struct vcache *tvc;
2783 struct AFSFetchStatus OutDirStatus;
2784 struct VenusFid tfid;
2785 struct AFSVolSync tsync;
2789 /* "ain" is the name of the file in this dir to remove */
2791 AFS_STATCNT(PRemoveMount);
2794 code = afs_VerifyVCache(avc, areq);
2797 if (vType(avc) != VDIR)
2800 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1); /* test for error below */
2803 Check_AtSys(avc, ain, &sysState, areq);
2804 ObtainReadLock(&tdc->lock);
2806 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
2807 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2808 ReleaseReadLock(&tdc->lock);
2809 bufp = sysState.name;
2814 tfid.Cell = avc->fid.Cell;
2815 tfid.Fid.Volume = avc->fid.Fid.Volume;
2816 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
2817 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
2819 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
2826 if (tvc->mvstat != 1) {
2832 ObtainWriteLock(&tvc->lock, 230);
2833 code = afs_HandleLink(tvc, areq);
2835 if (tvc->linkData) {
2836 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2841 ReleaseWriteLock(&tvc->lock);
2842 osi_dnlc_purgedp(tvc);
2848 ObtainWriteLock(&avc->lock, 231);
2849 osi_dnlc_remove(avc, bufp, tvc);
2851 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2853 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2856 RXAFS_RemoveFile(tc->id, (struct AFSFid *)&avc->fid.Fid, bufp,
2857 &OutDirStatus, &tsync);
2862 } while (afs_Analyze
2863 (tc, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_REMOVEFILE,
2864 SHARED_LOCK, NULL));
2869 ReleaseWriteLock(&avc->lock);
2873 /* we have the thing in the cache */
2874 ObtainWriteLock(&tdc->lock, 661);
2875 if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2876 /* we can do it locally */
2877 code = afs_dir_Delete(tdc, bufp);
2879 ZapDCE(tdc); /* surprise error -- invalid value */
2883 ReleaseWriteLock(&tdc->lock);
2884 afs_PutDCache(tdc); /* drop ref count */
2886 avc->states &= ~CUnique; /* For the dfs xlator */
2887 ReleaseWriteLock(&avc->lock);
2890 if (sysState.allocked)
2891 osi_FreeLargeSpace(bufp);
2896 * VIOC_VENUSLOG (34) - Enable/Disable venus logging
2900 * \retval EINVAL Error if some of the standard args aren't set
2902 * \notes Obsoleted, perhaps should be PBogus
2904 DECL_PIOCTL(PVenusLogging)
2906 return EINVAL; /* OBSOLETE */
2910 * VIOC_GETCELLSTATUS (35) - Get cell status info
2914 * \param[in] ain The cell you want status information on
2915 * \param[out] aout cell state (as a struct)
2917 * \retval EIO Error if the afs daemon hasn't started yet
2918 * \retval ENOENT Error if the cell doesn't exist
2920 * \post Returns the state of the cell as defined in a struct cell
2922 DECL_PIOCTL(PGetCellStatus)
2924 register struct cell *tcell;
2927 AFS_STATCNT(PGetCellStatus);
2928 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2929 return EIO; /* Inappropriate ioctl for device */
2931 tcell = afs_GetCellByName(ain, READ_LOCK);
2934 temp = tcell->states;
2935 afs_PutCell(tcell, READ_LOCK);
2936 memcpy(aout, (char *)&temp, sizeof(afs_int32));
2937 *aoutSize = sizeof(afs_int32);
2942 * VIOC_SETCELLSTATUS (36) - Set corresponding info
2946 * \param[in] ain The cell you want to set information about, and the values you want to set
2947 * \param[out] aout not in use
2949 * \retval EIO Error if the afs daemon hasn't started yet
2950 * \retval EACCES Error if the user doesn't have super-user credentials
2952 * \post Set the state of the cell in a defined struct cell, based on whether or not SetUID is allowed
2954 DECL_PIOCTL(PSetCellStatus)
2956 register struct cell *tcell;
2959 if (!afs_osi_suser(*acred))
2961 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2962 return EIO; /* Inappropriate ioctl for device */
2964 tcell = afs_GetCellByName(ain + 2 * sizeof(afs_int32), WRITE_LOCK);
2967 memcpy((char *)&temp, ain, sizeof(afs_int32));
2969 tcell->states |= CNoSUID;
2971 tcell->states &= ~CNoSUID;
2972 afs_PutCell(tcell, WRITE_LOCK);
2977 * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
2981 * \param[in] ain not in use (args in avc)
2982 * \param[out] aout not in use
2984 * \retval EINVAL Error if some of the standard args aren't set
2985 * \retval EIO Error if the afs daemon hasn't started yet
2987 * \post Wipe everything on the volume. This is done dependent on which platform this is for.
2989 * \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.
2991 DECL_PIOCTL(PFlushVolumeData)
2993 register afs_int32 i;
2994 register struct dcache *tdc;
2995 register struct vcache *tvc;
2996 register struct volume *tv;
2997 afs_int32 cell, volume;
2998 struct afs_q *tq, *uq;
2999 #ifdef AFS_DARWIN80_ENV
3003 AFS_STATCNT(PFlushVolumeData);
3006 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3007 return EIO; /* Inappropriate ioctl for device */
3009 volume = avc->fid.Fid.Volume; /* who to zap */
3010 cell = avc->fid.Cell;
3013 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
3014 * the vcaches associated with the volume.
3017 ObtainReadLock(&afs_xvcache);
3018 i = VCHashV(&avc->fid);
3019 for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
3022 if (tvc->fid.Fid.Volume == volume && tvc->fid.Cell == cell) {
3023 if (tvc->states & CVInit) {
3024 ReleaseReadLock(&afs_xvcache);
3025 afs_osi_Sleep(&tvc->states);
3028 #ifdef AFS_DARWIN80_ENV
3029 if (tvc->states & CDeadVnode) {
3030 ReleaseReadLock(&afs_xvcache);
3031 afs_osi_Sleep(&tvc->states);
3035 #if defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
3036 VN_HOLD(AFSTOV(tvc));
3038 #ifdef AFS_DARWIN80_ENV
3042 if (vnode_ref(vp)) {
3049 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
3052 VREFCOUNT_INC(tvc); /* AIX, apparently */
3056 ReleaseReadLock(&afs_xvcache);
3057 #ifdef AFS_BOZONLOCK_ENV
3058 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3060 ObtainWriteLock(&tvc->lock, 232);
3062 ObtainWriteLock(&afs_xcbhash, 458);
3063 afs_DequeueCallback(tvc);
3064 tvc->states &= ~(CStatd | CDirty);
3065 ReleaseWriteLock(&afs_xcbhash);
3066 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
3067 osi_dnlc_purgedp(tvc);
3068 afs_TryToSmush(tvc, *acred, 1);
3069 ReleaseWriteLock(&tvc->lock);
3070 #ifdef AFS_BOZONLOCK_ENV
3071 afs_BozonUnlock(&tvc->pvnLock, tvc);
3073 #ifdef AFS_DARWIN80_ENV
3074 vnode_put(AFSTOV(tvc));
3076 ObtainReadLock(&afs_xvcache);
3078 /* our tvc ptr is still good until now */
3082 ReleaseReadLock(&afs_xvcache);
3085 MObtainWriteLock(&afs_xdcache, 328); /* needed if you're going to flush any stuff */
3086 for (i = 0; i < afs_cacheFiles; i++) {
3087 if (!(afs_indexFlags[i] & IFEverUsed))
3088 continue; /* never had any data */
3089 tdc = afs_GetDSlot(i, NULL);
3090 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
3091 ReleaseReadLock(&tdc->tlock);
3092 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
3093 if (!(afs_indexFlags[i] & IFDataMod)) {
3094 /* if the file is modified, but has a ref cnt of only 1, then
3095 * someone probably has the file open and is writing into it.
3096 * Better to skip flushing such a file, it will be brought back
3097 * immediately on the next write anyway.
3099 * If we *must* flush, then this code has to be rearranged to call
3100 * afs_storeAllSegments() first */
3101 afs_FlushDCache(tdc);
3105 ReleaseReadLock(&tdc->tlock);
3107 afs_PutDCache(tdc); /* bumped by getdslot */
3109 MReleaseWriteLock(&afs_xdcache);
3111 ObtainReadLock(&afs_xvolume);
3112 for (i = 0; i < NVOLS; i++) {
3113 for (tv = afs_volumes[i]; tv; tv = tv->next) {
3114 if (tv->volume == volume) {
3115 afs_ResetVolumeInfo(tv);
3120 ReleaseReadLock(&afs_xvolume);
3122 /* probably, a user is doing this, probably, because things are screwed up.
3123 * maybe it's the dnlc's fault? */
3130 * VIOCGETVCXSTATUS (41) - gets vnode x status
3134 * \param[in] ain not in use (avc used)
3135 * \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
3137 * \retval EINVAL Error if some of the initial default arguments aren't set
3138 * \retval EACCES Error if access to check the mode bits is denied
3140 * \post gets stats for the vnode, a struct listed in vcxstat
3142 DECL_PIOCTL(PGetVnodeXStatus)
3144 register afs_int32 code;
3145 struct vcxstat stat;
3148 /* AFS_STATCNT(PGetVnodeXStatus); */
3151 code = afs_VerifyVCache(avc, areq);
3154 if (vType(avc) == VDIR)
3155 mode = PRSFS_LOOKUP;
3158 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3161 memset(&stat, 0, sizeof(struct vcxstat));
3162 stat.fid = avc->fid;
3163 hset32(stat.DataVersion, hgetlo(avc->m.DataVersion));
3164 stat.lock = avc->lock;
3165 stat.parentVnode = avc->parentVnode;
3166 stat.parentUnique = avc->parentUnique;
3167 hset(stat.flushDV, avc->flushDV);
3168 hset(stat.mapDV, avc->mapDV);
3169 stat.truncPos = avc->truncPos;
3170 { /* just grab the first two - won't break anything... */
3171 struct axscache *ac;
3173 for (i = 0, ac = avc->Access; ac && i < CPSIZE; i++, ac = ac->next) {
3174 stat.randomUid[i] = ac->uid;
3175 stat.randomAccess[i] = ac->axess;
3178 stat.callback = afs_data_pointer_to_int32(avc->callback);
3179 stat.cbExpires = avc->cbExpires;
3180 stat.anyAccess = avc->anyAccess;
3181 stat.opens = avc->opens;
3182 stat.execsOrWriters = avc->execsOrWriters;
3183 stat.flockCount = avc->flockCount;
3184 stat.mvstat = avc->mvstat;
3185 stat.states = avc->states;
3186 memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
3187 *aoutSize = sizeof(struct vcxstat);
3192 DECL_PIOCTL(PGetVnodeXStatus2)
3194 register afs_int32 code;
3195 struct vcxstat2 stat;
3200 code = afs_VerifyVCache(avc, areq);
3203 if (vType(avc) == VDIR)
3204 mode = PRSFS_LOOKUP;
3207 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3210 memset(&stat, 0, sizeof(struct vcxstat2));
3212 stat.cbExpires = avc->cbExpires;
3213 stat.anyAccess = avc->anyAccess;
3214 stat.mvstat = avc->mvstat;
3215 stat.callerAccess = afs_GetAccessBits(avc, ~0, areq);
3217 memcpy(aout, (char *)&stat, sizeof(struct vcxstat2));
3218 *aoutSize = sizeof(struct vcxstat2);
3224 * VIOC_AFS_SYSNAME (38) - Change @sys value
3228 * \param[in] ain new value for @sys
3229 * \param[out] aout count, entry, list (debug values?)
3231 * \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"
3232 * \retval ENODEV Error if there isn't already a system named that ("I THINK")
3233 * \retval EACCES Error if the user doesn't have super-user credentials
3235 * \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
3237 * \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.
3239 DECL_PIOCTL(PSetSysName)
3241 char *cp, *cp2 = NULL, inname[MAXSYSNAME], outname[MAXSYSNAME];
3242 afs_int32 setsysname;
3244 register struct afs_exporter *exporter;
3245 register struct unixuser *au;
3246 register afs_int32 pag, error;
3247 int t, count, num = 0, allpags = 0;
3250 AFS_STATCNT(PSetSysName);
3251 if (!afs_globalVFS) {
3252 /* Afsd is NOT running; disable it */
3253 #if defined(KERNEL_HAVE_UERROR)
3254 return (setuerror(EINVAL), EINVAL);
3259 memset(inname, 0, MAXSYSNAME);
3260 memcpy(&setsysname, ain, sizeof(afs_int32));
3261 ain += sizeof(afs_int32);
3262 if (setsysname & 0x8000) {
3264 setsysname &= ~0x8000;
3269 if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
3272 for (cp = ain, count = 0; count < setsysname; count++) {
3273 /* won't go past end of ain since maxsysname*num < ain length */
3275 if (t >= MAXSYSNAME || t <= 0)
3277 /* check for names that can shoot us in the foot */
3278 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
3284 /* inname gets first entry in case we're being a translator */
3286 memcpy(inname, ain, t + 1); /* include terminating null */
3290 if ((*acred)->cr_gid == RMTUSER_REQ ||
3291 (*acred)->cr_gid == RMTUSER_REQ_PRIV) { /* Handles all exporters */
3292 if (allpags && (*acred)->cr_gid != RMTUSER_REQ_PRIV) {
3295 pag = PagInCred(*acred);
3297 return EINVAL; /* Better than panicing */
3299 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
3300 return EINVAL; /* Better than panicing */
3302 if (!(exporter = au->exporter)) {
3303 afs_PutUser(au, READ_LOCK);
3304 return EINVAL; /* Better than panicing */
3306 error = EXP_SYSNAME(exporter, (setsysname ? cp2 : NULL), &sysnamelist,
3309 if (error == ENODEV)
3310 foundname = 0; /* sysname not set yet! */
3312 afs_PutUser(au, READ_LOCK);
3317 strcpy(outname, sysnamelist[0]);
3319 afs_PutUser(au, READ_LOCK);
3323 /* Not xlating, so local case */
3325 osi_Panic("PSetSysName: !afs_sysname\n");
3326 if (!setsysname) { /* user just wants the info */
3327 strcpy(outname, afs_sysname);
3328 foundname = afs_sysnamecount;
3329 sysnamelist = afs_sysnamelist;
3330 } else { /* Local guy; only root can change sysname */
3331 if (!afs_osi_suser(*acred))
3334 /* allpags makes no sense for local use */
3338 /* clear @sys entries from the dnlc, once afs_lookup can
3339 * do lookups of @sys entries and thinks it can trust them */
3340 /* privs ok, store the entry, ... */
3341 strcpy(afs_sysname, inname);
3342 if (setsysname > 1) { /* ... or list */
3344 for (count = 1; count < setsysname; ++count) {
3345 if (!afs_sysnamelist[count])
3347 ("PSetSysName: no afs_sysnamelist entry to write\n");
3349 memcpy(afs_sysnamelist[count], cp, t + 1); /* include null */
3353 afs_sysnamecount = setsysname;
3358 cp = aout; /* not changing so report back the count and ... */
3359 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
3360 cp += sizeof(afs_int32);
3362 strcpy(cp, outname); /* ... the entry, ... */
3363 cp += strlen(outname) + 1;
3364 for (count = 1; count < foundname; ++count) { /* ... or list. */
3365 if (!sysnamelist[count])
3367 ("PSetSysName: no afs_sysnamelist entry to read\n");
3368 t = strlen(sysnamelist[count]);
3369 if (t >= MAXSYSNAME)
3370 osi_Panic("PSetSysName: sysname entry garbled\n");
3371 strcpy(cp, sysnamelist[count]);
3375 *aoutSize = cp - aout;
3380 /* sequential search through the list of touched cells is not a good
3381 * long-term solution here. For small n, though, it should be just
3382 * fine. Should consider special-casing the local cell for large n.
3383 * Likewise for PSetSPrefs.
3385 * s - number of ids in array l[] -- NOT index of last id
3386 * l - array of cell ids which have volumes that need to be sorted
3387 * vlonly - sort vl servers or file servers?
3390 ReSortCells_cb(struct cell *cell, void *arg)
3392 afs_int32 *p = (afs_int32 *) arg;
3393 afs_int32 *l = p + 1;
3396 for (i = 0; i < s; i++) {
3397 if (l[i] == cell->cellNum) {
3398 ObtainWriteLock(&cell->lock, 690);
3399 afs_SortServers(cell->cellHosts, MAXCELLHOSTS);
3400 ReleaseWriteLock(&cell->lock);
3408 ReSortCells(int s, afs_int32 * l, int vlonly)
3416 p = (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * (s + 1));
3418 memcpy(p + 1, l, s * sizeof(afs_int32));
3419 afs_TraverseCells(&ReSortCells_cb, p);
3420 afs_osi_Free(p, sizeof(afs_int32) * (s + 1));
3424 ObtainReadLock(&afs_xvolume);
3425 for (i = 0; i < NVOLS; i++) {
3426 for (j = afs_volumes[i]; j; j = j->next) {
3427 for (k = 0; k < s; k++)
3428 if (j->cell == l[k]) {
3429 ObtainWriteLock(&j->lock, 233);
3430 afs_SortServers(j->serverHost, MAXHOSTS);
3431 ReleaseWriteLock(&j->lock);
3436 ReleaseReadLock(&afs_xvolume);
3440 static int debugsetsp = 0;
3442 afs_setsprefs(sp, num, vlonly)
3445 unsigned int vlonly;
3448 int i, j, k, matches, touchedSize;
3449 struct server *srvr = NULL;
3450 afs_int32 touched[34];
3454 for (k = 0; k < num; sp++, k++) {
3456 printf("sp host=%x, rank=%d\n", sp->host.s_addr, sp->rank);
3459 ObtainReadLock(&afs_xserver);
3461 i = SHash(sp->host.s_addr);
3462 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
3463 if (sa->sa_ip == sp->host.s_addr) {
3465 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3466 || (sa->sa_portal == AFS_FSPORT);
3467 if ((!vlonly && isfs) || (vlonly && !isfs)) {
3474 if (sa && matches) { /* found one! */
3476 printf("sa ip=%x, ip_rank=%d\n", sa->sa_ip, sa->sa_iprank);
3478 sa->sa_iprank = sp->rank + afs_randomMod15();
3479 afs_SortOneServer(sa->server);
3482 /* if we don't know yet what cell it's in, this is moot */
3483 for (j = touchedSize - 1;
3484 j >= 0 && touched[j] != srvr->cell->cellNum; j--)
3485 /* is it in our list of touched cells ? */ ;
3486 if (j < 0) { /* no, it's not */
3487 touched[touchedSize++] = srvr->cell->cellNum;
3488 if (touchedSize >= 32) { /* watch for ovrflow */
3489 ReleaseReadLock(&afs_xserver);
3490 ReSortCells(touchedSize, touched, vlonly);
3492 ObtainReadLock(&afs_xserver);
3498 ReleaseReadLock(&afs_xserver);
3499 /* if we didn't find one, start to create one. */
3500 /* Note that it doesn't have a cell yet... */
3502 afs_uint32 temp = sp->host.s_addr;
3504 afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
3505 WRITE_LOCK, (afsUUID *) 0, 0);
3506 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3507 afs_PutServer(srvr, WRITE_LOCK);
3509 } /* for all cited preferences */
3511 ReSortCells(touchedSize, touched, vlonly);
3516 * VIOC_SETPREFS (46) - Set server ranks
3518 * \param[in] ain the sprefs value you want the sprefs to be set to
3519 * \param[out] aout not in use
3521 * \retval EIO Error if the afs daemon hasn't started yet
3522 * \retval EACCES Error if the user doesn't have super-user credentials
3523 * \retval EINVAL Error if the struct setsprefs is too large or if it multiplied by the number of servers is too large
3525 * \post set the sprefs using the afs_setsprefs() function
3527 DECL_PIOCTL(PSetSPrefs)
3529 struct setspref *ssp;
3530 AFS_STATCNT(PSetSPrefs);
3532 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3533 return EIO; /* Inappropriate ioctl for device */
3535 if (!afs_osi_suser(*acred))
3538 if (ainSize < sizeof(struct setspref))
3541 ssp = (struct setspref *)ain;
3542 if (ainSize < sizeof(struct spref) * ssp->num_servers)
3545 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
3546 (ssp->flags & DBservers));
3551 * VIOC_SETPREFS33 (42) - Set server ranks (deprecated)
3553 * \param[in] ain the server preferences to be set
3554 * \param[out] aout not in use
3556 * \retval EIO Error if the afs daemon hasn't started yet
3557 * \retval EACCES Error if the user doesn't have super-user credentials
3559 * \post set the server preferences, calling a function
3561 * \notes this may only be performed by the local root user.
3563 DECL_PIOCTL(PSetSPrefs33)
3566 AFS_STATCNT(PSetSPrefs);
3567 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3568 return EIO; /* Inappropriate ioctl for device */
3571 if (!afs_osi_suser(*acred))
3574 sp = (struct spref *)ain;
3575 afs_setsprefs(sp, ainSize / (sizeof(struct spref)), 0 /*!vlonly */ );
3580 * VIOC_GETSPREFS (43) - Get server ranks
3584 * \param[in] ain the server preferences to get
3585 * \param[out] aout the server preferences information
3587 * \retval EIO Error if the afs daemon hasn't started yet
3588 * \retval ENOENT Error if the sprefrequest is too large
3590 * \post Get the sprefs
3592 * \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.
3594 DECL_PIOCTL(PGetSPrefs)
3596 struct sprefrequest *spin; /* input */
3597 struct sprefinfo *spout; /* output */
3598 struct spref *srvout; /* one output component */
3599 int i, j; /* counters for hash table traversal */
3600 struct server *srvr; /* one of CM's server structs */
3602 int vlonly; /* just return vlservers ? */
3605 AFS_STATCNT(PGetSPrefs);
3606 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3607 return EIO; /* Inappropriate ioctl for device */
3610 if (ainSize < sizeof(struct sprefrequest_33)) {
3613 spin = ((struct sprefrequest *)ain);
3616 if (ainSize > sizeof(struct sprefrequest_33)) {
3617 vlonly = (spin->flags & DBservers);
3621 /* struct sprefinfo includes 1 server struct... that size gets added
3622 * in during the loop that follows.
3624 *aoutSize = sizeof(struct sprefinfo) - sizeof(struct spref);
3625 spout = (struct sprefinfo *)aout;
3626 spout->next_offset = spin->offset;
3627 spout->num_servers = 0;
3628 srvout = spout->servers;
3630 ObtainReadLock(&afs_xserver);
3631 for (i = 0, j = 0; j < NSERVERS; j++) { /* sift through hash table */
3632 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3633 if (spin->offset > (unsigned short)i) {
3634 continue; /* catch up to where we left off */
3636 spout->next_offset++;
3639 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3640 || (sa->sa_portal == AFS_FSPORT);
3642 if ((vlonly && isfs) || (!vlonly && !isfs)) {
3643 /* only report ranks for vl servers */
3647 srvout->host.s_addr = sa->sa_ip;
3648 srvout->rank = sa->sa_iprank;
3649 *aoutSize += sizeof(struct spref);
3650 spout->num_servers++;
3653 if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3654 ReleaseReadLock(&afs_xserver); /* no more room! */
3659 ReleaseReadLock(&afs_xserver);
3661 spout->next_offset = 0; /* start over from the beginning next time */
3665 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3666 int afs_NFSRootOnly = 1;
3668 * VIOC_EXPORTAFS (39) - Export afs to nfs clients
3672 * \param[in] ain a struct Vic * EIOctl containing export values needed to change between nfs and afs
3673 * \param[out] aout a struct of the exporter states (exporter->exp_states)
3675 * \retval ENODEV Error if the exporter doesn't exist
3676 * \retval EACCES Error if the user doesn't have super-user credentials
3678 * \post Changes the state of various values to reflect the change of the export values between nfs and afs.
3680 * \notes Legacy code obtained from IBM.
3682 DECL_PIOCTL(PExportAfs)
3684 afs_int32 export, newint =
3685 0, type, changestate, handleValue, convmode, pwsync, smounts;
3686 afs_int32 rempags = 0, pagcb = 0;
3687 register struct afs_exporter *exporter;
3689 AFS_STATCNT(PExportAfs);
3690 memcpy((char *)&handleValue, ain, sizeof(afs_int32));
3691 type = handleValue >> 24;
3696 exporter = exporter_find(type);
3698 export = handleValue & 3;
3699 changestate = handleValue & 0xfff;
3700 smounts = (handleValue >> 2) & 3;
3701 pwsync = (handleValue >> 4) & 3;
3702 convmode = (handleValue >> 6) & 3;
3703 rempags = (handleValue >> 8) & 3;
3704 pagcb = (handleValue >> 10) & 3;
3706 changestate = (handleValue >> 16) & 0x1;
3707 convmode = (handleValue >> 16) & 0x2;
3708 pwsync = (handleValue >> 16) & 0x4;
3709 smounts = (handleValue >> 16) & 0x8;
3710 export = handleValue & 0xff;
3713 /* Failed finding desired exporter; */
3717 handleValue = exporter->exp_states;
3718 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3719 *aoutSize = sizeof(afs_int32);
3721 if (!afs_osi_suser(*acred))
3722 return EACCES; /* Only superuser can do this */
3726 exporter->exp_states |= EXP_EXPORTED;
3728 exporter->exp_states &= ~EXP_EXPORTED;
3732 exporter->exp_states |= EXP_UNIXMODE;
3734 exporter->exp_states &= ~EXP_UNIXMODE;
3738 exporter->exp_states |= EXP_PWSYNC;
3740 exporter->exp_states &= ~EXP_PWSYNC;
3744 afs_NFSRootOnly = 0;
3745 exporter->exp_states |= EXP_SUBMOUNTS;
3747 afs_NFSRootOnly = 1;
3748 exporter->exp_states &= ~EXP_SUBMOUNTS;
3753 exporter->exp_states |= EXP_CLIPAGS;
3755 exporter->exp_states &= ~EXP_CLIPAGS;
3759 exporter->exp_states |= EXP_CALLBACK;
3761 exporter->exp_states &= ~EXP_CALLBACK;
3763 handleValue = exporter->exp_states;
3764 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3765 *aoutSize = sizeof(afs_int32);
3768 exporter->exp_states |= EXP_EXPORTED;
3770 exporter->exp_states &= ~EXP_EXPORTED;
3772 exporter->exp_states |= EXP_UNIXMODE;
3774 exporter->exp_states &= ~EXP_UNIXMODE;
3776 exporter->exp_states |= EXP_PWSYNC;
3778 exporter->exp_states &= ~EXP_PWSYNC;
3780 afs_NFSRootOnly = 0;
3781 exporter->exp_states |= EXP_SUBMOUNTS;
3783 afs_NFSRootOnly = 1;
3784 exporter->exp_states &= ~EXP_SUBMOUNTS;
3793 * VIOC_GAG (44) - Silence Cache Manager
3797 * \param[in] ain the flags to either gag or de-gag the cache manager
3798 * \param[out] aout not in use
3800 * \retval EACCES Error if the user doesn't have super-user credentials
3802 * \post set the gag flags, then show these flags
3806 struct gaginfo *gagflags;
3808 if (!afs_osi_suser(*acred))
3811 gagflags = (struct gaginfo *)ain;
3812 afs_showflags = gagflags->showflags;
3818 * VIOC_TWIDDLE (45) - Adjust RX knobs
3822 * \param[in] ain the previous settings of the 'knobs'
3823 * \param[out] aout not in use
3825 * \retval EACCES Error if the user doesn't have super-user credentials
3827 * \post build out the struct rxp, from a struct rx
3829 DECL_PIOCTL(PTwiddleRx)
3831 struct rxparams *rxp;
3833 if (!afs_osi_suser(*acred))
3836 rxp = (struct rxparams *)ain;
3838 if (rxp->rx_initReceiveWindow)
3839 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3840 if (rxp->rx_maxReceiveWindow)
3841 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3842 if (rxp->rx_initSendWindow)
3843 rx_initSendWindow = rxp->rx_initSendWindow;
3844 if (rxp->rx_maxSendWindow)
3845 rx_maxSendWindow = rxp->rx_maxSendWindow;
3846 if (rxp->rxi_nSendFrags)
3847 rxi_nSendFrags = rxp->rxi_nSendFrags;
3848 if (rxp->rxi_nRecvFrags)
3849 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3850 if (rxp->rxi_OrphanFragSize)
3851 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3852 if (rxp->rx_maxReceiveSize) {
3853 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3854 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3856 if (rxp->rx_MyMaxSendSize)
3857 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3863 * VIOC_GETINITPARAMS (49) - Get initial cache manager parameters
3867 * \param[in] ain not in use
3868 * \param[out] aout initial cache manager params
3870 * \retval E2BIG Error if the initial parameters are bigger than some PIGGYSIZE
3872 * \post return the initial cache manager parameters
3874 DECL_PIOCTL(PGetInitParams)
3876 if (sizeof(struct cm_initparams) > PIGGYSIZE)
3879 memcpy(aout, (char *)&cm_initParams, sizeof(struct cm_initparams));
3880 *aoutSize = sizeof(struct cm_initparams);
3884 #ifdef AFS_SGI65_ENV
3885 /* They took crget() from us, so fake it. */
3890 cr = crdup(get_current_cred());
3891 memset((char *)cr, 0, sizeof(cred_t));
3892 #if CELL || CELL_PREPARE
3900 * VIOC_GETRXKCRYPT (55) - Get rxkad encryption flag
3904 * \param[in] ain not in use
3905 * \param[out] aout value of cryptall
3907 * \post get the value of cryptall (presumably whether or not things should be encrypted)
3909 DECL_PIOCTL(PGetRxkcrypt)
3911 memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3912 *aoutSize = sizeof(afs_int32);
3917 * VIOC_SETRXKCRYPT (56) - Set rxkad encryption flag
3921 * \param[in] ain the argument whether or not things should be encrypted
3922 * \param[out] aout not in use
3924 * \retval EPERM Error if the user doesn't have super-user credentials
3925 * \retval EINVAL Error if the input is too big, or if the input is outside the bounds of what it can be set to
3927 * \post set whether or not things should be encrypted
3929 * \notes may need to be modified at a later date to take into account other values for cryptall (beyond true or false)
3931 DECL_PIOCTL(PSetRxkcrypt)
3935 if (!afs_osi_suser(*acred))
3937 if (ainSize != sizeof(afs_int32) || ain == NULL)
3939 memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3940 /* if new mappings added later this will need to be changed */
3941 if (tmpval != 0 && tmpval != 1)
3947 #ifdef AFS_NEED_CLIENTCONTEXT
3949 * Create new credentials to correspond to a remote user with given
3950 * <hostaddr, uid, g0, g1>. This allows a server running as root to
3951 * provide pioctl (and other) services to foreign clients (i.e. nfs
3952 * clients) by using this call to `become' the client.
3955 #define PIOCTL_HEADER 6
3957 HandleClientContext(struct afs_ioctl *ablob, int *com,
3958 struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3961 afs_uint32 hostaddr;
3962 afs_int32 uid, g0, g1, i, code, pag, exporter_type, isroot = 0;
3963 struct afs_exporter *exporter, *outexporter;
3964 struct AFS_UCRED *newcred;
3965 struct unixuser *au;
3966 afs_uint32 comp = *com & 0xff00;
3969 #if defined(AFS_SGIMP_ENV)
3970 osi_Assert(ISAFS_GLOCK());
3972 AFS_STATCNT(HandleClientContext);
3973 if (ablob->in_size < PIOCTL_HEADER * sizeof(afs_int32)) {
3974 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3975 return EINVAL; /* Too small to be good */
3977 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3978 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER * sizeof(afs_int32), code);
3980 osi_FreeLargeSpace(inData);
3984 /* Extract information for remote user */
3985 hostaddr = *((afs_uint32 *) ain);
3986 ain += sizeof(hostaddr);
3987 uid = *((afs_uint32 *) ain);
3989 g0 = *((afs_uint32 *) ain);
3991 g1 = *((afs_uint32 *) ain);
3993 *com = *((afs_uint32 *) ain);
3994 ain += sizeof(afs_int32);
3995 exporter_type = *((afs_uint32 *) ain); /* In case we support more than NFS */
3998 * Of course, one must be root for most of these functions, but
3999 * we'll allow (for knfs) you to set things if the pag is 0 and
4000 * you're setting tokens or unlogging.
4003 if (!afs_osi_suser(credp)) {
4004 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI64_ENV)
4005 /* Since SGI's suser() returns explicit failure after the call.. */
4008 /* check for acceptable opcodes for normal folks, which are, so far,
4009 * get/set tokens, sysname, and unlog.
4011 if (i != 9 && i != 3 && i != 38 && i != 8) {
4012 osi_FreeLargeSpace(inData);
4017 ablob->in_size -= PIOCTL_HEADER * sizeof(afs_int32);
4018 ablob->in += PIOCTL_HEADER * sizeof(afs_int32);
4019 osi_FreeLargeSpace(inData);
4022 * We map uid 0 to nobody to match the mapping that the nfs
4023 * server does and to ensure that the suser() calls in the afs
4024 * code fails for remote client roots.
4026 uid = afs_nobody; /* NFS_NOBODY == -2 */
4030 #ifdef AFS_AIX41_ENV
4033 newcred->cr_gid = isroot ? RMTUSER_REQ_PRIV : RMTUSER_REQ;
4034 #ifdef AFS_AIX51_ENV
4035 newcred->cr_groupset.gs_union.un_groups[0] = g0;
4036 newcred->cr_groupset.gs_union.un_groups[1] = g1;
4037 #elif defined(AFS_LINUX26_ENV)
4038 #ifdef AFS_LINUX26_ONEGROUP_ENV
4039 newcred->cr_group_info = groups_alloc(1); /* not that anything sets this */
4040 l = (((g0-0x3f00) & 0x3fff) << 14) | ((g1-0x3f00) & 0x3fff);
4041 h = ((g0-0x3f00) >> 14);
4042 h = ((g1-0x3f00) >> 14) + h + h + h;
4043 GROUP_AT(newcred->cr_group_info, 0) = ((h << 28) | l);
4045 newcred->cr_group_info = groups_alloc(2);
4046 GROUP_AT(newcred->cr_group_info, 0) = g0;
4047 GROUP_AT(newcred->cr_group_info, 1) = g1;
4050 newcred->cr_groups[0] = g0;
4051 newcred->cr_groups[1] = g1;
4054 newcred->cr_ngrps = 2;
4055 #elif !defined(AFS_LINUX26_ENV)
4056 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
4057 newcred->cr_ngroups = 2;
4059 for (i = 2; i < NGROUPS; i++)
4060 newcred->cr_groups[i] = NOGROUP;
4063 #if !defined(AFS_OSF_ENV)
4064 afs_nfsclient_init(); /* before looking for exporter, ensure one exists */
4066 if (!(exporter = exporter_find(exporter_type))) {
4067 /* Exporter wasn't initialized or an invalid exporter type */
4071 if (exporter->exp_states & EXP_PWSYNC) {
4072 if (uid != credp->cr_uid) {
4074 return ENOEXEC; /* XXX Find a better errno XXX */
4077 newcred->cr_uid = uid; /* Only temporary */
4078 code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
4079 /* The client's pag is the only unique identifier for it */
4080 newcred->cr_uid = pag;
4082 if (!code && *com == PSETPAG) {
4083 /* Special case for 'setpag' */
4084 afs_uint32 pagvalue = genpag();
4086 au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
4088 * Note that we leave the 'outexporter' struct held so it won't
4091 au->exporter = outexporter;
4092 if (ablob->out_size >= 4) {
4093 AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32),
4096 afs_PutUser(au, WRITE_LOCK);
4099 return PSETPAG; /* Special return for setpag */
4101 EXP_RELE(outexporter);
4104 *com = (*com) | comp;
4107 #endif /* AFS_NEED_CLIENTCONTEXT */
4111 * VIOC_GETCPREFS (50) - Get client interface
4115 * \param[in] ain sprefrequest input
4116 * \param[out] aout spref information
4118 * \retval EIO Error if the afs daemon hasn't started yet
4119 * \retval EINVAL Error if some of the standard args aren't set
4121 * \post get all interface addresses and other information of the client interface
4123 DECL_PIOCTL(PGetCPrefs)
4125 struct sprefrequest *spin; /* input */
4126 struct sprefinfo *spout; /* output */
4127 struct spref *srvout; /* one output component */
4131 AFS_STATCNT(PGetCPrefs);
4132 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4133 return EIO; /* Inappropriate ioctl for device */
4135 if (ainSize < sizeof(struct sprefrequest))
4138 spin = (struct sprefrequest *)ain;
4139 spout = (struct sprefinfo *)aout;
4141 maxNumber = spin->num_servers; /* max addrs this time */
4142 srvout = spout->servers;
4144 ObtainReadLock(&afs_xinterface);
4146 /* copy out the client interface information from the
4147 ** kernel data structure "interface" to the output buffer
4149 for (i = spin->offset, j = 0; (i < afs_cb_interface.numberOfInterfaces)
4150 && (j < maxNumber); i++, j++, srvout++)
4151 srvout->host.s_addr = afs_cb_interface.addr_in[i];
4153 spout->num_servers = j;
4154 *aoutSize = sizeof(struct sprefinfo) + (j - 1) * sizeof(struct spref);
4156 if (i >= afs_cb_interface.numberOfInterfaces)
4157 spout->next_offset = 0; /* start from beginning again */
4159 spout->next_offset = spin->offset + j;
4161 ReleaseReadLock(&afs_xinterface);
4166 * VIOC_SETCPREFS (51) - Set client interface
4170 * \param[in] ain the interfaces you want set
4171 * \param[out] aout not in use
4173 * \retval EIO Error if the afs daemon hasn't started yet
4174 * \retval EINVAL Error if the input is too large for the struct
4175 * \retval ENOMEM Error if there are too many servers
4177 * \post set the callbak interfaces addresses to those of the hosts
4179 DECL_PIOCTL(PSetCPrefs)
4181 struct setspref *sin;
4184 AFS_STATCNT(PSetCPrefs);
4185 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4186 return EIO; /* Inappropriate ioctl for device */
4188 sin = (struct setspref *)ain;
4190 if (ainSize < sizeof(struct setspref))
4192 #if 0 /* num_servers is unsigned */
4193 if (sin->num_servers < 0)
4196 if (sin->num_servers > AFS_MAX_INTERFACE_ADDR)
4199 ObtainWriteLock(&afs_xinterface, 412);
4200 afs_cb_interface.numberOfInterfaces = sin->num_servers;
4201 for (i = 0; (unsigned short)i < sin->num_servers; i++)
4202 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
4204 ReleaseWriteLock(&afs_xinterface);
4209 * VIOC_AFS_FLUSHMOUNT (52) - Flush mount symlink data
4213 * \param[in] ain the last part of a path to a mount point, which tells us what to flush
4214 * \param[out] aout not in use
4216 * \retval EINVAL Error if some of the initial arguments aren't set
4217 * \retval ENOTDIR Error if the initial argument for the mount point isn't a directory
4218 * \retval ENOENT Error if the dcache entry isn't set
4220 * \post remove all of the mount data from the dcache regarding a certain mount point
4222 DECL_PIOCTL(PFlushMount)
4224 register afs_int32 code;
4225 register struct vcache *tvc;
4226 register struct dcache *tdc;
4227 struct VenusFid tfid;
4229 struct sysname_info sysState;
4230 afs_size_t offset, len;
4232 AFS_STATCNT(PFlushMount);
4235 code = afs_VerifyVCache(avc, areq);
4238 if (vType(avc) != VDIR) {
4241 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
4244 Check_AtSys(avc, ain, &sysState, areq);
4245 ObtainReadLock(&tdc->lock);
4247 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
4248 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
4249 ReleaseReadLock(&tdc->lock);
4250 afs_PutDCache(tdc); /* we're done with the data */
4251 bufp = sysState.name;
4255 tfid.Cell = avc->fid.Cell;
4256 tfid.Fid.Volume = avc->fid.Fid.Volume;
4257 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
4258 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
4260 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4266 if (tvc->mvstat != 1) {
4271 #ifdef AFS_BOZONLOCK_ENV
4272 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
4274 ObtainWriteLock(&tvc->lock, 649);
4275 ObtainWriteLock(&afs_xcbhash, 650);
4276 afs_DequeueCallback(tvc);
4277 tvc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
4278 ReleaseWriteLock(&afs_xcbhash);
4279 /* now find the disk cache entries */
4280 afs_TryToSmush(tvc, *acred, 1);
4281 osi_dnlc_purgedp(tvc);
4282 if (tvc->linkData && !(tvc->states & CCore)) {
4283 afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
4284 tvc->linkData = NULL;
4286 ReleaseWriteLock(&tvc->lock);
4287 #ifdef AFS_BOZONLOCK_ENV
4288 afs_BozonUnlock(&tvc->pvnLock, tvc);
4292 if (sysState.allocked)
4293 osi_FreeLargeSpace(bufp);
4298 * VIOC_RXSTAT_PROC (53) - Control process RX statistics
4302 * \param[in] ain the flags that control which stats to use
4303 * \param[out] aout not in use
4305 * \retval EACCES Error if the user doesn't have super-user credentials
4306 * \retval EINVAL Error if the flag input is too long
4308 * \post either enable process RPCStats, disable process RPCStats, or clear the process RPCStats
4310 DECL_PIOCTL(PRxStatProc)
4315 if (!afs_osi_suser(*acred)) {
4319 if (ainSize != sizeof(afs_int32)) {
4323 memcpy((char *)&flags, ain, sizeof(afs_int32));
4324 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4328 if (flags & AFSCALL_RXSTATS_ENABLE) {
4329 rx_enableProcessRPCStats();
4331 if (flags & AFSCALL_RXSTATS_DISABLE) {
4332 rx_disableProcessRPCStats();
4334 if (flags & AFSCALL_RXSTATS_CLEAR) {
4335 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
4344 * VIOC_RXSTAT_PEER (54) - Control peer RX statistics
4348 * \param[in] ain the flags that control which statistics to use
4349 * \param[out] aout not in use
4351 * \retval EACCES Error if the user doesn't have super-user credentials
4352 * \retval EINVAL Error if the flag input is too long
4354 * \post either enable peer RPCStatws, disable peer RPCStats, or clear the peer RPCStats
4356 DECL_PIOCTL(PRxStatPeer)
4361 if (!afs_osi_suser(*acred)) {
4365 if (ainSize != sizeof(afs_int32)) {
4369 memcpy((char *)&flags, ain, sizeof(afs_int32));
4370 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4374 if (flags & AFSCALL_RXSTATS_ENABLE) {
4375 rx_enablePeerRPCStats();
4377 if (flags & AFSCALL_RXSTATS_DISABLE) {
4378 rx_disablePeerRPCStats();
4380 if (flags & AFSCALL_RXSTATS_CLEAR) {
4381 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
4388 DECL_PIOCTL(PPrefetchFromTape)
4390 register afs_int32 code, code1;
4393 struct rx_call *tcall;
4394 struct AFSVolSync tsync;
4395 struct AFSFetchStatus OutStatus;
4396 struct AFSCallBack CallBack;
4397 struct VenusFid tfid;
4401 AFS_STATCNT(PSetAcl);
4405 if (ain && (ainSize == 3 * sizeof(afs_int32)))
4406 Fid = (struct AFSFid *)ain;
4408 Fid = &avc->fid.Fid;
4409 tfid.Cell = avc->fid.Cell;
4410 tfid.Fid.Volume = Fid->Volume;
4411 tfid.Fid.Vnode = Fid->Vnode;
4412 tfid.Fid.Unique = Fid->Unique;
4414 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4416 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4417 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &avc->fid);
4420 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4421 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &tvc->fid);
4424 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
4428 tcall = rx_NewCall(tc->id);
4430 StartRXAFS_FetchData(tcall, (struct AFSFid *)&tvc->fid.Fid, 0,
4433 bytes = rx_Read(tcall, (char *)aout, sizeof(afs_int32));
4435 EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
4437 code1 = rx_EndCall(tcall, code);
4441 } while (afs_Analyze
4442 (tc, code, &tvc->fid, areq, AFS_STATS_FS_RPCIDX_RESIDENCYRPCS,
4443 SHARED_LOCK, NULL));
4444 /* This call is done only to have the callback things handled correctly */
4445 afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
4449 *aoutSize = sizeof(afs_int32);
4454 DECL_PIOCTL(PResidencyCmd)
4456 register afs_int32 code;
4459 struct ResidencyCmdInputs *Inputs;
4460 struct ResidencyCmdOutputs *Outputs;
4461 struct VenusFid tfid;
4464 Inputs = (struct ResidencyCmdInputs *)ain;
4465 Outputs = (struct ResidencyCmdOutputs *)aout;
4468 if (!ain || ainSize != sizeof(struct ResidencyCmdInputs))
4473 Fid = &avc->fid.Fid;
4475 tfid.Cell = avc->fid.Cell;
4476 tfid.Fid.Volume = Fid->Volume;
4477 tfid.Fid.Vnode = Fid->Vnode;
4478 tfid.Fid.Unique = Fid->Unique;
4480 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4481 afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD, ICL_TYPE_POINTER, tvc,
4482 ICL_TYPE_INT32, Inputs->command, ICL_TYPE_FID, &tfid);
4486 if (Inputs->command) {
4488 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
4492 RXAFS_ResidencyCmd(tc->id, Fid, Inputs,
4493 (struct ResidencyCmdOutputs *)aout);
4497 } while (afs_Analyze
4498 (tc, code, &tvc->fid, areq,
4499 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK, NULL));
4500 /* This call is done to have the callback things handled correctly */
4501 afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4502 } else { /* just a status request, return also link data */
4504 Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4505 Outputs->chars[0] = 0;
4506 if (vType(tvc) == VLNK) {
4507 ObtainWriteLock(&tvc->lock, 555);
4508 if (afs_HandleLink(tvc, areq) == 0)
4509 strncpy((char *)&Outputs->chars, tvc->linkData, MAXCMDCHARS);
4510 ReleaseWriteLock(&tvc->lock);
4517 *aoutSize = sizeof(struct ResidencyCmdOutputs);
4522 DECL_PIOCTL(PNewUuid)
4524 /*AFS_STATCNT(PNewUuid); */
4525 if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4526 return EIO; /* Inappropriate ioctl for device */
4528 if (!afs_osi_suser(acred))
4531 ObtainWriteLock(&afs_xinterface, 555);
4532 afs_uuid_create(&afs_cb_interface.uuid);
4533 ReleaseWriteLock(&afs_xinterface);
4534 ForceAllNewConnections();
4538 #if defined(AFS_CACHE_BYPASS)
4540 DECL_PIOCTL(PSetCachingThreshold)
4545 setting = getting = 1;
4547 if (ain == NULL || ainSize < sizeof(afs_int32))
4553 if (setting == 0 && getting == 0)
4557 * If setting, set first, and return the value now in effect
4560 afs_int32 threshold;
4562 if (!afs_osi_suser(*acred))
4564 memcpy((char *)&threshold, ain, sizeof(afs_int32));
4565 cache_bypass_threshold = threshold;
4566 afs_warn("Cache Bypass Threshold set to: %d\n", threshold);
4567 /* TODO: move to separate pioctl, or enhance pioctl */
4568 cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
4572 /* Return the current size threshold */
4573 afs_int32 oldThreshold = cache_bypass_threshold;
4574 memcpy(aout, (char *)&oldThreshold, sizeof(afs_int32));
4575 *aoutSize = sizeof(afs_int32);
4581 #endif /* defined(AFS_CACHE_BYPASS) */
4583 DECL_PIOCTL(PCallBackAddr)
4586 afs_uint32 addr, code;
4592 struct unixuser *tu;
4593 struct srvAddr **addrs;
4595 /*AFS_STATCNT(PCallBackAddr); */
4596 if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4597 return EIO; /* Inappropriate ioctl for device */
4599 if (!afs_osi_suser(acred))
4602 if (ainSize < sizeof(afs_int32))
4605 memcpy(&addr, ain, sizeof(afs_int32));
4607 ObtainReadLock(&afs_xinterface);
4608 for (i = 0; (unsigned short)i < afs_cb_interface.numberOfInterfaces; i++) {
4609 if (afs_cb_interface.addr_in[i] == addr)
4613 ReleaseWriteLock(&afs_xinterface);
4615 if (afs_cb_interface.addr_in[i] != addr)
4618 ObtainReadLock(&afs_xserver); /* Necessary? */
4619 ObtainReadLock(&afs_xsrvAddr);
4622 for (i = 0; i < NSERVERS; i++) {
4623 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4628 addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
4630 for (i = 0; i < NSERVERS; i++) {
4631 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4632 if (j >= srvAddrCount)
4638 ReleaseReadLock(&afs_xsrvAddr);
4639 ReleaseReadLock(&afs_xserver);
4641 for (i = 0; i < j; i++) {
4647 /* vlserver has no callback conn */
4648 if (sa->sa_portal == AFS_VLPORT) {
4652 if (!ts->cell) /* not really an active server, anyway, it must */
4653 continue; /* have just been added by setsprefs */
4655 /* get a connection, even if host is down; bumps conn ref count */
4656 tu = afs_GetUser(areq->uid, ts->cell->cellNum, SHARED_LOCK);
4657 tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
4658 1 /*force */ , 1 /*create */ , SHARED_LOCK);
4659 afs_PutUser(tu, SHARED_LOCK);
4663 if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(ts)) {
4664 if (sa->sa_flags & SRVADDR_ISDOWN) {
4665 rx_SetConnDeadTime(tc->id, 3);
4667 #ifdef RX_ENABLE_LOCKS
4669 #endif /* RX_ENABLE_LOCKS */
4670 code = RXAFS_CallBackRxConnAddr(tc->id, &addr);
4671 #ifdef RX_ENABLE_LOCKS
4673 #endif /* RX_ENABLE_LOCKS */
4675 afs_PutConn(tc, SHARED_LOCK); /* done with it now */
4676 } /* Outer loop over addrs */
4677 #endif /* UKERNEL */
4681 DECL_PIOCTL(PDiscon)
4683 #ifdef AFS_DISCON_ENV
4684 static afs_int32 mode = 1; /* Start up in 'off' */
4685 afs_int32 force = 0;
4690 if (!afs_osi_suser(*acred))
4696 afs_ConflictPolicy = ain[1] - 1;
4701 * All of these numbers are hard coded in fs.c. If they
4702 * change here, they should change there and vice versa
4705 case 0: /* Disconnect ("offline" mode), breaking all callbacks */
4706 if (!AFS_IS_DISCONNECTED) {
4707 ObtainWriteLock(&afs_discon_lock, 999);
4708 afs_DisconGiveUpCallbacks();
4709 afs_RemoveAllConns();
4710 afs_is_disconnected = 1;
4711 afs_is_discon_rw = 1;
4712 ReleaseWriteLock(&afs_discon_lock);
4715 case 1: /* Fully connected, ("online" mode). */
4716 ObtainWriteLock(&afs_discon_lock, 998);
4719 code = afs_ResyncDisconFiles(areq, *acred);
4722 if (code && !force) {
4723 printf("Files not synchronized properly, still in discon state. \
4724 Please retry or use \"force\".\n");
4726 afs_is_disconnected = 0;
4727 afs_is_discon_rw = 0;
4728 printf("\nSync succeeded. You are back online.\n");
4731 ReleaseWriteLock(&afs_discon_lock);
4740 memcpy(aout, &mode, sizeof(afs_int32));
4741 *aoutSize = sizeof(afs_int32);
4748 DECL_PIOCTL(PNFSNukeCreds)
4750 afs_uint32 addr, code;
4751 register afs_int32 i;
4752 register struct unixuser *tu;
4754 AFS_STATCNT(PUnlog);
4755 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4756 return EIO; /* Inappropriate ioctl for device */
4758 if (ainSize < sizeof(afs_int32))
4760 memcpy(&addr, ain, sizeof(afs_int32));
4762 if ((*acred)->cr_gid == RMTUSER_REQ_PRIV && !addr) {
4763 tu = afs_GetUser(areq->uid, -1, SHARED_LOCK);
4764 if (!tu->exporter || !(addr = EXP_GETHOST(tu->exporter))) {
4765 afs_PutUser(tu, SHARED_LOCK);
4768 afs_PutUser(tu, SHARED_LOCK);
4769 } else if (!afs_osi_suser(acred)) {
4773 ObtainWriteLock(&afs_xuser, 227);
4774 for (i = 0; i < NUSERS; i++) {
4775 for (tu = afs_users[i]; tu; tu = tu->next) {
4776 if (tu->exporter && EXP_CHECKHOST(tu->exporter, addr)) {
4778 tu->states &= ~UHasTokens;
4779 /* security is not having to say you're sorry */
4780 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
4782 ReleaseWriteLock(&afs_xuser);
4783 afs_ResetUserConns(tu);
4785 ObtainWriteLock(&afs_xuser, 228);
4787 /* set the expire times to 0, causes
4788 * afs_GCUserData to remove this entry
4790 tu->ct.EndTimestamp = 0;
4792 #endif /* UKERNEL */
4796 ReleaseWriteLock(&afs_xuser);