2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include "afs/param.h"
14 #include "afs/sysincludes.h" /* Standard vendor system headers */
16 #include "h/syscallargs.h"
19 #include "h/sysproto.h"
21 #include "afsincludes.h" /* Afs-based standard headers */
22 #include "afs/afs_stats.h" /* afs statistics */
24 #include "afs/afs_bypasscache.h"
25 #include "rx/rx_globals.h"
27 struct VenusFid afs_rootFid;
28 afs_int32 afs_waitForever = 0;
29 short afs_waitForeverCount = 0;
30 afs_int32 afs_showflags = GAGUSER | GAGCONSOLE; /* show all messages */
33 afs_int32 afs_is_disconnected;
34 afs_int32 afs_is_discon_rw;
35 /* On reconnection, turn this knob on until it finishes,
38 afs_int32 afs_in_sync = 0;
42 * \defgroup pioctl Path IOCTL functions
44 * DECL_PIOCTL is a macro defined to contain the following parameters for functions:
46 * \param[in] avc the AFS vcache structure in use by pioctl
47 * \param[in] afun not in use
48 * \param[in] areq the AFS vrequest structure
49 * \param[in] ain as defined by the function
50 * \param[in] aout as defined by the function
51 * \param[in] ainSize size of ain
52 * \param[in] aoutSize size of aout
53 * \param[in] acred UNIX credentials structure underlying the operation
56 #define DECL_PIOCTL(x) static int x(struct vcache *avc, int afun, struct vrequest *areq, \
57 char *ain, char *aout, afs_int32 ainSize, afs_int32 *aoutSize, \
60 /* Prototypes for pioctl routines */
63 DECL_PIOCTL(PStoreBehind);
68 DECL_PIOCTL(PGetFileCell);
69 DECL_PIOCTL(PGetWSCell);
70 DECL_PIOCTL(PGetUserCell);
71 DECL_PIOCTL(PSetTokens);
72 DECL_PIOCTL(PGetVolumeStatus);
73 DECL_PIOCTL(PSetVolumeStatus);
75 DECL_PIOCTL(PNewStatMount);
76 DECL_PIOCTL(PGetTokens);
78 DECL_PIOCTL(PMariner);
79 DECL_PIOCTL(PCheckServers);
80 DECL_PIOCTL(PCheckVolNames);
81 DECL_PIOCTL(PCheckAuth);
82 DECL_PIOCTL(PFindVolume);
83 DECL_PIOCTL(PViceAccess);
84 DECL_PIOCTL(PSetCacheSize);
85 DECL_PIOCTL(PGetCacheSize);
86 DECL_PIOCTL(PRemoveCallBack);
87 DECL_PIOCTL(PNewCell);
88 DECL_PIOCTL(PNewAlias);
89 DECL_PIOCTL(PListCells);
90 DECL_PIOCTL(PListAliases);
91 DECL_PIOCTL(PRemoveMount);
92 DECL_PIOCTL(PVenusLogging);
93 DECL_PIOCTL(PGetCellStatus);
94 DECL_PIOCTL(PSetCellStatus);
95 DECL_PIOCTL(PFlushVolumeData);
96 DECL_PIOCTL(PGetVnodeXStatus);
97 DECL_PIOCTL(PGetVnodeXStatus2);
98 DECL_PIOCTL(PSetSysName);
99 DECL_PIOCTL(PSetSPrefs);
100 DECL_PIOCTL(PSetSPrefs33);
101 DECL_PIOCTL(PGetSPrefs);
102 DECL_PIOCTL(PExportAfs);
104 DECL_PIOCTL(PTwiddleRx);
105 DECL_PIOCTL(PGetInitParams);
106 DECL_PIOCTL(PGetRxkcrypt);
107 DECL_PIOCTL(PSetRxkcrypt);
108 DECL_PIOCTL(PGetCPrefs);
109 DECL_PIOCTL(PSetCPrefs);
110 DECL_PIOCTL(PFlushMount);
111 DECL_PIOCTL(PRxStatProc);
112 DECL_PIOCTL(PRxStatPeer);
113 DECL_PIOCTL(PPrefetchFromTape);
115 DECL_PIOCTL(PCallBackAddr);
116 DECL_PIOCTL(PDiscon);
117 DECL_PIOCTL(PNFSNukeCreds);
118 DECL_PIOCTL(PNewUuid);
119 DECL_PIOCTL(PPrecache);
120 DECL_PIOCTL(PGetPAG);
121 #if defined(AFS_CACHE_BYPASS)
122 DECL_PIOCTL(PSetCachingThreshold);
123 DECL_PIOCTL(PSetCachingBlkSize);
127 * A macro that says whether we're going to need HandleClientContext().
128 * This is currently used only by the nfs translator.
130 #if !defined(AFS_NONFSTRANS) || defined(AFS_AIX_IAUTH_ENV)
131 #define AFS_NEED_CLIENTCONTEXT
134 /* Prototypes for private routines */
135 #ifdef AFS_NEED_CLIENTCONTEXT
136 static int HandleClientContext(struct afs_ioctl *ablob, int *com,
140 int HandleIoctl(register struct vcache *avc, register afs_int32 acom,
141 struct afs_ioctl *adata);
142 int afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
143 register struct afs_ioctl *ablob, int afollow,
145 static int Prefetch(iparmtype apath, struct afs_ioctl *adata, int afollow,
148 typedef int (*pioctlFunction) (struct vcache *, int, struct vrequest *,
149 char *, char *, afs_int32, afs_int32 *,
152 static pioctlFunction VpioctlSw[] = {
157 PGetVolumeStatus, /* 4 */
158 PSetVolumeStatus, /* 5 */
163 PCheckServers, /* 10 */
164 PCheckVolNames, /* 11 */
166 PBogus, /* 13 -- used to be quick check time */
167 PFindVolume, /* 14 */
168 PBogus, /* 15 -- prefetch is now special-cased; see pioctl code! */
169 PBogus, /* 16 -- used to be testing code */
170 PNoop, /* 17 -- used to be enable group */
171 PNoop, /* 18 -- used to be disable group */
172 PBogus, /* 19 -- used to be list group */
173 PViceAccess, /* 20 */
174 PUnlog, /* 21 -- unlog *is* unpag in this system */
175 PGetFID, /* 22 -- get file ID */
176 PBogus, /* 23 -- used to be waitforever */
177 PSetCacheSize, /* 24 */
178 PRemoveCallBack, /* 25 -- flush only the callback */
181 PRemoveMount, /* 28 -- delete mount point */
182 PNewStatMount, /* 29 -- new style mount point stat */
183 PGetFileCell, /* 30 -- get cell name for input file */
184 PGetWSCell, /* 31 -- get cell name for workstation */
185 PMariner, /* 32 - set/get mariner host */
186 PGetUserCell, /* 33 -- get cell name for user */
187 PVenusLogging, /* 34 -- Enable/Disable logging */
188 PGetCellStatus, /* 35 */
189 PSetCellStatus, /* 36 */
190 PFlushVolumeData, /* 37 -- flush all data from a volume */
191 PSetSysName, /* 38 - Set system name */
192 PExportAfs, /* 39 - Export Afs to remote nfs clients */
193 PGetCacheSize, /* 40 - get cache size and usage */
194 PGetVnodeXStatus, /* 41 - get vcache's special status */
195 PSetSPrefs33, /* 42 - Set CM Server preferences... */
196 PGetSPrefs, /* 43 - Get CM Server preferences... */
197 PGag, /* 44 - turn off/on all CM messages */
198 PTwiddleRx, /* 45 - adjust some RX params */
199 PSetSPrefs, /* 46 - Set CM Server preferences... */
200 PStoreBehind, /* 47 - set degree of store behind to be done */
201 PGCPAGs, /* 48 - disable automatic pag gc-ing */
202 PGetInitParams, /* 49 - get initial cm params */
203 PGetCPrefs, /* 50 - get client interface addresses */
204 PSetCPrefs, /* 51 - set client interface addresses */
205 PFlushMount, /* 52 - flush mount symlink data */
206 PRxStatProc, /* 53 - control process RX statistics */
207 PRxStatPeer, /* 54 - control peer RX statistics */
208 PGetRxkcrypt, /* 55 -- Get rxkad encryption flag */
209 PSetRxkcrypt, /* 56 -- Set rxkad encryption flag */
210 PBogus, /* 57 -- arla: set file prio */
211 PBogus, /* 58 -- arla: fallback getfh */
212 PBogus, /* 59 -- arla: fallback fhopen */
213 PBogus, /* 60 -- arla: controls xfsdebug */
214 PBogus, /* 61 -- arla: controls arla debug */
215 PBogus, /* 62 -- arla: debug interface */
216 PBogus, /* 63 -- arla: print xfs status */
217 PBogus, /* 64 -- arla: force cache check */
218 PBogus, /* 65 -- arla: break callback */
219 PPrefetchFromTape, /* 66 -- MR-AFS: prefetch file from tape */
220 PFsCmd, /* 67 -- RXOSD: generic commnd interface */
221 PBogus, /* 68 -- arla: fetch stats */
222 PGetVnodeXStatus2, /* 69 - get caller access and some vcache status */
225 static pioctlFunction CpioctlSw[] = {
227 PNewAlias, /* 1 -- create new cell alias */
228 PListAliases, /* 2 -- list cell aliases */
229 PCallBackAddr, /* 3 -- request addr for callback rxcon */
231 PDiscon, /* 5 -- get/set discon mode */
242 static pioctlFunction OpioctlSw[] = {
244 PNFSNukeCreds, /* 1 -- nuke all creds for NFS client */
245 #if defined(AFS_CACHE_BYPASS)
246 PSetCachingThreshold /* 2 -- get/set cache-bypass size threshold */
248 PNoop /* 2 -- get/set cache-bypass size threshold */
252 #define PSetClientContext 99 /* Special pioctl to setup caller's creds */
253 int afs_nobody = NFS_NOBODY;
256 HandleIoctl(register struct vcache *avc, register afs_int32 acom,
257 struct afs_ioctl *adata)
259 register afs_int32 code;
262 AFS_STATCNT(HandleIoctl);
264 switch (acom & 0xff) {
266 avc->f.states |= CSafeStore;
268 /* SXW - Should we force a MetaData flush for this flag setting */
271 /* case 2 used to be abort store, but this is no longer provided,
272 * since it is impossible to implement under normal Unix.
276 /* return the name of the cell this file is open on */
277 register struct cell *tcell;
278 register afs_int32 i;
280 tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
282 i = strlen(tcell->cellName) + 1; /* bytes to copy out */
284 if (i > adata->out_size) {
285 /* 0 means we're not interested in the output */
286 if (adata->out_size != 0)
290 AFS_COPYOUT(tcell->cellName, adata->out, i, code);
292 afs_PutCell(tcell, READ_LOCK);
298 case 49: /* VIOC_GETINITPARAMS */
299 if (adata->out_size < sizeof(struct cm_initparams)) {
302 AFS_COPYOUT(&cm_initParams, adata->out,
303 sizeof(struct cm_initparams), code);
315 return code; /* so far, none implemented */
319 /* For aix we don't temporarily bypass ioctl(2) but rather do our
320 * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
321 * is now called from afs_gn_ioctl.
324 afs_ioctl(struct vcache *tvc, int cmd, int arg)
326 struct afs_ioctl data;
329 AFS_STATCNT(afs_ioctl);
330 if (((cmd >> 8) & 0xff) == 'V') {
331 /* This is a VICEIOCTL call */
332 AFS_COPYIN(arg, (caddr_t) & data, sizeof(data), error);
335 error = HandleIoctl(tvc, cmd, &data);
338 /* No-op call; just return. */
342 #endif /* AFS_AIX_ENV */
344 #if defined(AFS_SGI_ENV)
345 afs_ioctl(OSI_VN_DECL(tvc), int cmd, void *arg, int flag, cred_t * cr,
348 , struct vopbd * vbds
352 struct afs_ioctl data;
358 AFS_STATCNT(afs_ioctl);
359 if (((cmd >> 8) & 0xff) == 'V') {
360 /* This is a VICEIOCTL call */
361 error = copyin_afs_ioctl(arg, &data);
364 locked = ISAFS_GLOCK();
367 error = HandleIoctl(tvc, cmd, &data);
372 /* No-op call; just return. */
376 #endif /* AFS_SGI_ENV */
378 /* unlike most calls here, this one uses u.u_error to return error conditions,
379 since this is really an intercepted chapter 2 call, rather than a vnode
382 /* AFS_HPUX102 and up uses VNODE ioctl instead */
383 #if !defined(AFS_HPUX102_ENV) && !defined(AFS_DARWIN80_ENV)
384 #if !defined(AFS_SGI_ENV)
389 kioctl(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
391 #else /* __64BIT__ */
393 kioctl32(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
395 #endif /* __64BIT__ */
398 kioctl(int fdes, int com, caddr_t arg, caddr_t ext)
407 } u_uap, *uap = &u_uap;
409 #if defined(AFS_SUN5_ENV)
411 struct afs_ioctl_sys {
418 afs_xioctl(struct afs_ioctl_sys *uap, rval_t *rvp)
420 #elif defined(AFS_OSF_ENV)
422 afs_xioctl(struct proc *p, void *args, long *retval)
428 } *uap = (struct a *)args;
429 #elif defined(AFS_FBSD50_ENV)
432 afs_xioctl(struct thread *td, register struct ioctl_args *uap,
435 struct proc *p = td->td_proc;
436 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
444 afs_xioctl(struct proc *p, register struct ioctl_args *uap, register_t *retval)
446 #elif defined(AFS_LINUX22_ENV)
447 struct afs_ioctl_sys {
452 afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
455 struct afs_ioctl_sys ua, *uap = &ua;
464 } *uap = (struct a *)u.u_ap;
465 #endif /* AFS_SUN5_ENV */
467 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
469 #elif !defined(AFS_LINUX22_ENV)
470 register struct file *fd;
472 #if defined(AFS_XBSD_ENV)
473 register struct filedesc *fdp;
475 register struct vcache *tvc;
476 register int ioctlDone = 0, code = 0;
478 AFS_STATCNT(afs_xioctl);
479 #if defined(AFS_DARWIN_ENV)
480 if ((code = fdgetf(p, uap->fd, &fd)))
482 #elif defined(AFS_XBSD_ENV)
484 if ((u_int) uap->fd >= fdp->fd_nfiles
485 || (fd = fdp->fd_ofiles[uap->fd]) == NULL)
487 if ((fd->f_flag & (FREAD | FWRITE)) == 0)
489 #elif defined(AFS_LINUX22_ENV)
492 #elif defined(AFS_AIX32_ENV)
500 if (setuerror(getf(uap->fd, &fd))) {
503 #elif defined(AFS_OSF_ENV)
505 if (code = getf(&fd, uap->fd, FILE_FLAGS_NULL, &u.u_file_state))
507 #elif defined(AFS_SUN5_ENV)
508 # if defined(AFS_SUN57_ENV)
512 # elif defined(AFS_SUN54_ENV)
517 if (code = getf(uap->fd, &fd)) {
520 # endif /* AFS_SUN57_ENV */
526 /* first determine whether this is any sort of vnode */
527 #if defined(AFS_LINUX22_ENV)
532 if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
534 if (fd->f_type == DTYPE_VNODE) {
536 /* good, this is a vnode; next see if it is an AFS vnode */
537 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
538 tvc = VTOAFS(fd->f_vnode); /* valid, given a vnode */
539 #elif defined(AFS_OBSD_ENV)
541 IsAfsVnode((struct vnode *)fd->
542 f_data) ? VTOAFS((struct vnode *)fd->f_data) : NULL;
544 tvc = VTOAFS((struct vnode *)fd->f_data); /* valid, given a vnode */
546 #endif /* AFS_LINUX22_ENV */
547 if (tvc && IsAfsVnode(AFSTOV(tvc))) {
548 /* This is an AFS vnode */
549 if (((uap->com >> 8) & 0xff) == 'V') {
550 register struct afs_ioctl *datap;
553 (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
554 code=copyin_afs_ioctl((char *)uap->arg, datap);
556 osi_FreeSmallSpace(datap);
558 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
561 #if defined(AFS_SUN5_ENV)
576 #else /* AFS_OSF_ENV */
580 #ifdef AFS_LINUX22_ENV
583 return (setuerror(code), code);
589 code = HandleIoctl(tvc, uap->com, datap);
590 osi_FreeSmallSpace(datap);
604 #if defined(AFS_LINUX22_ENV)
616 code = okioctl(fdes, com, arg, ext, arg2, arg3);
617 #else /* __64BIT__ */
618 code = okioctl32(fdes, com, arg, ext, arg2, arg3);
619 #endif /* __64BIT__ */
620 #else /* !AFS_AIX51_ENV */
621 code = okioctl(fdes, com, arg, ext);
622 #endif /* AFS_AIX51_ENV */
624 #else /* !AFS_AIX41_ENV */
626 okioctl(fdes, com, arg, ext);
627 #elif defined(AFS_SUN5_ENV)
628 #if defined(AFS_SUN57_ENV)
630 #elif defined(AFS_SUN54_ENV)
635 code = ioctl(uap, rvp);
636 #elif defined(AFS_FBSD50_ENV)
637 return ioctl(td, uap);
638 #elif defined(AFS_FBSD_ENV)
639 return ioctl(p, uap);
640 #elif defined(AFS_OBSD_ENV)
641 code = sys_ioctl(p, uap, retval);
642 #elif defined(AFS_DARWIN_ENV)
643 return ioctl(p, uap, retval);
644 #elif defined(AFS_OSF_ENV)
645 code = ioctl(p, args, retval);
652 #elif !defined(AFS_LINUX22_ENV)
666 #ifdef AFS_LINUX22_ENV
669 #if defined(KERNEL_HAVE_UERROR)
672 #if defined(AFS_AIX32_ENV) && !defined(AFS_AIX41_ENV)
673 return (getuerror()? -1 : u.u_ioctlrv);
675 return getuerror()? -1 : 0;
678 #endif /* AFS_LINUX22_ENV */
679 #endif /* AFS_SUN5_ENV */
680 #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
686 #endif /* AFS_SGI_ENV */
687 #endif /* AFS_HPUX102_ENV */
689 #if defined(AFS_SGI_ENV)
690 /* "pioctl" system call entry point; just pass argument to the parameterized
699 afs_pioctl(struct pioctlargs *uap, rval_t * rvp)
703 AFS_STATCNT(afs_pioctl);
705 code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
714 #elif defined(AFS_OSF_ENV)
715 afs_pioctl(struct proc *p, void *args, int *retval)
722 } *uap = (struct a *)args;
724 AFS_STATCNT(afs_pioctl);
725 return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow));
728 #elif defined(AFS_FBSD50_ENV)
730 afs_pioctl(struct thread *td, void *args, int *retval)
737 } *uap = (struct a *)args;
739 AFS_STATCNT(afs_pioctl);
740 return (afs_syscall_pioctl
741 (uap->path, uap->cmd, uap->cmarg, uap->follow, td->td_ucred));
744 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
746 afs_pioctl(struct proc *p, void *args, int *retval)
753 } *uap = (struct a *)args;
755 AFS_STATCNT(afs_pioctl);
756 #ifdef AFS_DARWIN80_ENV
757 return (afs_syscall_pioctl
758 (uap->path, uap->cmd, uap->cmarg, uap->follow,
761 return (afs_syscall_pioctl
762 (uap->path, uap->cmd, uap->cmarg, uap->follow,
763 p->p_cred->pc_ucred));
769 /* macro to avoid adding any more #ifdef's to pioctl code. */
770 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
771 #define PIOCTL_FREE_CRED() crfree(credp)
773 #define PIOCTL_FREE_CRED()
778 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
779 rval_t *vvp, AFS_UCRED *credp)
781 #ifdef AFS_DARWIN100_ENV
782 afs_syscall64_pioctl(user_addr_t path, unsigned int com, user_addr_t cmarg,
783 int follow, AFS_UCRED *credp)
784 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
785 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
788 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
792 struct afs_ioctl data;
793 #ifdef AFS_NEED_CLIENTCONTEXT
794 AFS_UCRED *tmpcred = NULL;
796 #if defined(AFS_NEED_CLIENTCONTEXT) || defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
797 AFS_UCRED *foreigncreds = NULL;
799 register afs_int32 code = 0;
800 struct vnode *vp = NULL;
802 struct ucred *credp = crref(); /* don't free until done! */
804 #ifdef AFS_LINUX22_ENV
805 cred_t *credp = crref(); /* don't free until done! */
809 AFS_STATCNT(afs_syscall_pioctl);
811 follow = 1; /* compat. with old venus */
812 code = copyin_afs_ioctl(cmarg, &data);
815 #if defined(KERNEL_HAVE_UERROR)
820 if ((com & 0xff) == PSetClientContext) {
821 #ifdef AFS_NEED_CLIENTCONTEXT
822 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
823 code = HandleClientContext(&data, &com, &foreigncreds, credp);
825 code = HandleClientContext(&data, &com, &foreigncreds, osi_curcred());
829 crfree(foreigncreds);
832 #if defined(KERNEL_HAVE_UERROR)
833 return (setuerror(code), code);
838 #else /* AFS_NEED_CLIENTCONTEXT */
840 #endif /* AFS_NEED_CLIENTCONTEXT */
842 #ifdef AFS_NEED_CLIENTCONTEXT
845 * We could have done without temporary setting the u.u_cred below
846 * (foreigncreds could be passed as param the pioctl modules)
847 * but calls such as afs_osi_suser() doesn't allow that since it
848 * references u.u_cred directly. We could, of course, do something
849 * like afs_osi_suser(cred) which, I think, is better since it
850 * generalizes and supports multi cred environments...
852 #if defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
854 credp = foreigncreds;
855 #elif defined(AFS_AIX41_ENV)
856 tmpcred = crref(); /* XXX */
858 #elif defined(AFS_HPUX101_ENV)
859 tmpcred = p_cred(u.u_procp);
860 set_p_cred(u.u_procp, foreigncreds);
861 #elif defined(AFS_SGI_ENV)
862 tmpcred = OSI_GET_CURRENT_CRED();
863 OSI_SET_CURRENT_CRED(foreigncreds);
866 u.u_cred = foreigncreds;
869 #endif /* AFS_NEED_CLIENTCONTEXT */
870 if ((com & 0xff) == 15) {
871 /* special case prefetch so entire pathname eval occurs in helper process.
872 * otherwise, the pioctl call is essentially useless */
873 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
875 Prefetch(path, &data, follow,
876 foreigncreds ? foreigncreds : credp);
878 code = Prefetch(path, &data, follow, osi_curcred());
881 #if defined(KERNEL_HAVE_UERROR)
890 lookupname(path, USR, follow, NULL, &vp,
891 foreigncreds ? foreigncreds : credp);
893 #ifdef AFS_LINUX22_ENV
894 code = gop_lookupname_user(path, AFS_UIOUSER, follow, &dp);
896 vp = (struct vnode *)dp->d_inode;
898 code = gop_lookupname_user(path, AFS_UIOUSER, follow, &vp);
899 #endif /* AFS_LINUX22_ENV */
900 #endif /* AFS_AIX41_ENV */
904 #if defined(KERNEL_HAVE_UERROR)
912 #if defined(AFS_SUN510_ENV)
913 if (vp && !IsAfsVnode(vp)) {
914 struct vnode *realvp;
916 #ifdef AFS_SUN511_ENV
917 (VOP_REALVP(vp, &realvp, NULL) == 0)
919 (VOP_REALVP(vp, &realvp) == 0)
922 struct vnode *oldvp = vp;
930 /* now make the call if we were passed no file, or were passed an AFS file */
931 if (!vp || IsAfsVnode(vp)) {
932 #if defined(AFS_SUN5_ENV)
933 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
934 #elif defined(AFS_AIX41_ENV)
936 struct ucred *cred1, *cred2;
939 cred1 = cred2 = foreigncreds;
941 cred1 = cred2 = credp;
943 code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
944 if (cred1 != cred2) {
945 /* something changed the creds */
949 #elif defined(AFS_HPUX101_ENV)
951 struct ucred *cred = p_cred(u.u_procp);
952 code = afs_HandlePioctl(vp, com, &data, follow, &cred);
954 #elif defined(AFS_SGI_ENV)
957 credp = OSI_GET_CURRENT_CRED();
958 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
960 #elif defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
961 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
963 code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
966 #if defined(KERNEL_HAVE_UERROR)
969 code = EINVAL; /* not in /afs */
974 #if defined(AFS_NEED_CLIENTCONTEXT)
977 crset(tmpcred); /* restore original credentials */
979 #if defined(AFS_HPUX101_ENV)
980 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
981 #elif defined(AFS_SGI_ENV)
982 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
983 #elif defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
984 credp = tmpcred; /* restore original credentials */
986 osi_curcred() = tmpcred; /* restore original credentials */
987 #endif /* AFS_HPUX101_ENV */
988 crfree(foreigncreds);
991 #endif /* AFS_NEED_CLIENTCONTEXT */
993 #ifdef AFS_LINUX22_ENV
996 AFS_RELE(vp); /* put vnode back */
1000 #if defined(KERNEL_HAVE_UERROR)
1003 return (getuerror());
1009 #ifdef AFS_DARWIN100_ENV
1011 afs_syscall_pioctl(char * path, unsigned int com, caddr_t cmarg,
1012 int follow, AFS_UCRED *credp)
1014 return afs_syscall64_pioctl(CAST_USER_ADDR_T(path), com,
1015 CAST_USER_ADDR_T((unsigned int)cmarg), follow,
1020 #define MAXPIOCTLTOKENLEN \
1021 (3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
1024 afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
1025 register struct afs_ioctl *ablob, int afollow,
1029 struct vrequest treq;
1030 register afs_int32 code;
1031 register afs_int32 function, device;
1032 afs_int32 inSize, outSize, outSizeMax;
1033 char *inData, *outData;
1034 pioctlFunction *pioctlSw;
1036 struct afs_fakestat_state fakestate;
1038 avc = avp ? VTOAFS(avp) : NULL;
1039 afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
1040 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
1041 AFS_STATCNT(HandlePioctl);
1042 if ((code = afs_InitReq(&treq, *acred)))
1044 afs_InitFakeStat(&fakestate);
1046 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
1048 afs_PutFakeStat(&fakestate);
1052 device = (acom & 0xff00) >> 8;
1054 case 'V': /* Original pioctls */
1055 pioctlSw = VpioctlSw;
1056 pioctlSwSize = sizeof(VpioctlSw);
1058 case 'C': /* Coordinated/common pioctls */
1059 pioctlSw = CpioctlSw;
1060 pioctlSwSize = sizeof(CpioctlSw);
1062 case 'O': /* Coordinated/common pioctls */
1063 pioctlSw = OpioctlSw;
1064 pioctlSwSize = sizeof(OpioctlSw);
1067 afs_PutFakeStat(&fakestate);
1070 function = acom & 0xff;
1071 if (function >= (pioctlSwSize / sizeof(char *))) {
1072 afs_PutFakeStat(&fakestate);
1073 return EINVAL; /* out of range */
1075 inSize = ablob->in_size;
1077 /* Do all range checking before continuing */
1078 if (inSize > MAXPIOCTLTOKENLEN || inSize < 0 || ablob->out_size < 0)
1081 /* Note that we use osi_Alloc for large allocs and osi_AllocLargeSpace for small ones */
1082 if (inSize > AFS_LRALLOCSIZ) {
1083 inData = osi_Alloc(inSize + 1);
1085 inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1090 AFS_COPYIN(ablob->in, inData, inSize, code);
1091 inData[inSize] = '\0';
1095 if (inSize > AFS_LRALLOCSIZ) {
1096 osi_Free(inData, inSize + 1);
1098 osi_FreeLargeSpace(inData);
1100 afs_PutFakeStat(&fakestate);
1103 if (function == 8 && device == 'V') { /* PGetTokens */
1104 outSizeMax = MAXPIOCTLTOKENLEN;
1105 outData = osi_Alloc(outSizeMax);
1107 outSizeMax = AFS_LRALLOCSIZ;
1108 outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1111 if (inSize > AFS_LRALLOCSIZ) {
1112 osi_Free(inData, inSize + 1);
1114 osi_FreeLargeSpace(inData);
1116 afs_PutFakeStat(&fakestate);
1121 (*pioctlSw[function]) (avc, function, &treq, inData, outData, inSize,
1123 if (inSize > AFS_LRALLOCSIZ) {
1124 osi_Free(inData, inSize + 1);
1126 osi_FreeLargeSpace(inData);
1128 if (code == 0 && ablob->out_size > 0) {
1129 if (outSize > ablob->out_size) {
1130 code = E2BIG; /* data wont fit in user buffer */
1131 } else if (outSize) {
1132 AFS_COPYOUT(outData, ablob->out, outSize, code);
1135 if (outSizeMax > AFS_LRALLOCSIZ) {
1136 osi_Free(outData, outSizeMax);
1138 osi_FreeLargeSpace(outData);
1140 afs_PutFakeStat(&fakestate);
1141 return afs_CheckCode(code, &treq, 41);
1145 * VIOCGETFID (22) - Get file ID quickly
1149 * \param[in] ain not in use
1150 * \param[out] aout fid of requested file
1152 * \retval EINVAL Error if some of the initial arguments aren't set
1154 * \post get the file id of some file
1156 DECL_PIOCTL(PGetFID)
1158 AFS_STATCNT(PGetFID);
1161 memcpy(aout, (char *)&avc->f.fid, sizeof(struct VenusFid));
1162 *aoutSize = sizeof(struct VenusFid);
1167 * VIOCSETAL (1) - Set access control list
1171 * \param[in] ain the ACL being set
1172 * \param[out] aout the ACL being set returned
1174 * \retval EINVAL Error if some of the standard args aren't set
1176 * \post Changed ACL, via direct writing to the wire
1178 int dummy_PSetAcl(char *ain, char *aout)
1183 DECL_PIOCTL(PSetAcl)
1185 register afs_int32 code;
1186 struct afs_conn *tconn;
1187 struct AFSOpaque acl;
1188 struct AFSVolSync tsync;
1189 struct AFSFetchStatus OutStatus;
1192 AFS_STATCNT(PSetAcl);
1195 if ((acl.AFSOpaque_len = strlen(ain) + 1) > 1024 /* AFSOPAQUEMAX */)
1198 acl.AFSOpaque_val = ain;
1200 tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1202 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1205 RXAFS_StoreACL(tconn->id, (struct AFSFid *)&avc->f.fid.Fid,
1206 &acl, &OutStatus, &tsync);
1211 } while (afs_Analyze
1212 (tconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_STOREACL,
1213 SHARED_LOCK, NULL));
1215 /* now we've forgotten all of the access info */
1216 ObtainWriteLock(&afs_xcbhash, 455);
1218 afs_DequeueCallback(avc);
1219 avc->f.states &= ~(CStatd | CUnique);
1220 ReleaseWriteLock(&afs_xcbhash);
1221 if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1222 osi_dnlc_purgedp(avc);
1224 /* SXW - Should we flush metadata here? */
1228 int afs_defaultAsynchrony = 0;
1231 * VIOC_STOREBEHIND (47) Adjust store asynchrony
1235 * \param[in] ain sbstruct (store behind structure) input
1236 * \param[out] aout resulting sbstruct
1238 * \retval EPERM Error if the user doesn't have super-user credentials
1239 * \retval EACCES Error if there isn't enough access to not check the mode bits
1241 * \post sets asynchrony based on a file, from a struct sbstruct "I THINK"
1243 DECL_PIOCTL(PStoreBehind)
1246 struct sbstruct *sbr;
1248 sbr = (struct sbstruct *)ain;
1249 if (sbr->sb_default != -1) {
1250 if (afs_osi_suser(*acred))
1251 afs_defaultAsynchrony = sbr->sb_default;
1256 if (avc && (sbr->sb_thisfile != -1)) {
1258 (avc, PRSFS_WRITE | PRSFS_ADMINISTER, areq, DONT_CHECK_MODE_BITS))
1259 avc->asynchrony = sbr->sb_thisfile;
1264 *aoutSize = sizeof(struct sbstruct);
1265 sbr = (struct sbstruct *)aout;
1266 sbr->sb_default = afs_defaultAsynchrony;
1268 sbr->sb_thisfile = avc->asynchrony;
1275 * VIOC_GCPAGS (48) - Disable automatic PAG gc'ing
1279 * \param[in] ain not in use
1280 * \param[out] aout not in use
1282 * \retval EACCES Error if the user doesn't have super-user credentials
1284 * \post set the gcpags to GCPAGS_USERDISABLED
1286 DECL_PIOCTL(PGCPAGs)
1288 if (!afs_osi_suser(*acred)) {
1291 afs_gcpags = AFS_GCPAGS_USERDISABLED;
1296 * VIOCGETAL (2) - Get access control list
1300 * \param[in] ain not in use
1301 * \param[out] aout the ACL
1303 * \retval EINVAL Error if some of the standard args aren't set
1304 * \retval ERANGE Error if the vnode of the file id is too large
1305 * \retval -1 Error if getting the ACL failed
1307 * \post Obtain the ACL, based on file ID
1309 * \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
1311 DECL_PIOCTL(PGetAcl)
1313 struct AFSOpaque acl;
1314 struct AFSVolSync tsync;
1315 struct AFSFetchStatus OutStatus;
1317 struct afs_conn *tconn;
1321 AFS_STATCNT(PGetAcl);
1324 Fid.Volume = avc->f.fid.Fid.Volume;
1325 Fid.Vnode = avc->f.fid.Fid.Vnode;
1326 Fid.Unique = avc->f.fid.Fid.Unique;
1327 if (avc->f.states & CForeign) {
1329 * For a dfs xlator acl we have a special hack so that the
1330 * xlator will distinguish which type of acl will return. So
1331 * we currently use the top 2-bytes (vals 0-4) to tell which
1332 * type of acl to bring back. Horrible hack but this will
1333 * cause the least number of changes to code size and interfaces.
1335 if (Fid.Vnode & 0xc0000000)
1337 Fid.Vnode |= (ainSize << 30);
1339 acl.AFSOpaque_val = aout;
1341 tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1344 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1346 code = RXAFS_FetchACL(tconn->id, &Fid, &acl, &OutStatus, &tsync);
1351 } while (afs_Analyze
1352 (tconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_FETCHACL,
1353 SHARED_LOCK, NULL));
1356 *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1362 * PNoop returns success. Used for functions which are not implemented or are no longer in use.
1366 * \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
1375 * PBogus returns fail. Used for functions which are not implemented or are no longer in use.
1379 * \retval EINVAL Error if some of the standard args aren't set
1381 * \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;
1385 AFS_STATCNT(PBogus);
1390 * VIOC_FILE_CELL_NAME (30) - Get cell in which file lives
1394 * \param[in] ain not in use (avc used to pass in file id)
1395 * \param[out] aout cell name
1397 * \retval EINVAL Error if some of the standard args aren't set
1398 * \retval ESRCH Error if the file isn't part of a cell
1400 * \post Get a cell based on a passed in file id
1402 DECL_PIOCTL(PGetFileCell)
1404 register struct cell *tcell;
1406 AFS_STATCNT(PGetFileCell);
1409 tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
1412 strcpy(aout, tcell->cellName);
1413 afs_PutCell(tcell, READ_LOCK);
1414 *aoutSize = strlen(aout) + 1;
1419 * VIOC_GET_WS_CELL (31) - Get cell in which workstation lives
1423 * \param[in] ain not in use
1424 * \param[out] aout cell name
1426 * \retval EIO Error if the afs daemon hasn't started yet
1427 * \retval ESRCH Error if the machine isn't part of a cell, for whatever reason
1429 * \post Get the primary cell that the machine is a part of.
1431 DECL_PIOCTL(PGetWSCell)
1433 struct cell *tcell = NULL;
1435 AFS_STATCNT(PGetWSCell);
1436 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1437 return EIO; /* Inappropriate ioctl for device */
1439 tcell = afs_GetPrimaryCell(READ_LOCK);
1440 if (!tcell) /* no primary cell? */
1442 strcpy(aout, tcell->cellName);
1443 *aoutSize = strlen(aout) + 1;
1444 afs_PutCell(tcell, READ_LOCK);
1449 * VIOC_GET_PRIMARY_CELL (33) - Get primary cell for caller
1453 * \param[in] ain not in use (user id found via areq)
1454 * \param[out] aout cell name
1456 * \retval ESRCH Error if the user id doesn't have a primary cell specified
1458 * \post Get the primary cell for a certain user, based on the user's uid
1460 DECL_PIOCTL(PGetUserCell)
1462 register afs_int32 i;
1463 register struct unixuser *tu;
1464 register struct cell *tcell;
1466 AFS_STATCNT(PGetUserCell);
1467 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1468 return EIO; /* Inappropriate ioctl for device */
1470 /* return the cell name of the primary cell for this user */
1471 i = UHash(areq->uid);
1472 ObtainWriteLock(&afs_xuser, 224);
1473 for (tu = afs_users[i]; tu; tu = tu->next) {
1474 if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1476 ReleaseWriteLock(&afs_xuser);
1481 tcell = afs_GetCell(tu->cell, READ_LOCK);
1482 afs_PutUser(tu, WRITE_LOCK);
1486 strcpy(aout, tcell->cellName);
1487 afs_PutCell(tcell, READ_LOCK);
1488 *aoutSize = strlen(aout) + 1; /* 1 for the null */
1491 ReleaseWriteLock(&afs_xuser);
1499 * VIOCSETTOK (3) - Set authentication tokens
1503 * \param[in] ain the krb tickets from which to set the afs tokens
1504 * \param[out] aout not in use
1506 * \retval EINVAL Error if the ticket is either too long or too short
1507 * \retval EIO Error if the AFS initState is below 101
1508 * \retval ESRCH Error if the cell for which the Token is being set can't be found
1510 * \post Set the Tokens for a specific cell name, unless there is none set, then default to primary
1513 DECL_PIOCTL(PSetTokens)
1516 register struct unixuser *tu;
1517 struct ClearToken clear;
1518 register struct cell *tcell;
1521 struct vrequest treq;
1522 afs_int32 flag, set_parent_pag = 0;
1524 AFS_STATCNT(PSetTokens);
1525 if (!afs_resourceinit_flag) {
1528 memcpy((char *)&i, ain, sizeof(afs_int32));
1529 ain += sizeof(afs_int32);
1530 stp = ain; /* remember where the ticket is */
1531 if (i < 0 || i > MAXKTCTICKETLEN)
1532 return EINVAL; /* malloc may fail */
1534 ain += i; /* skip over ticket */
1535 memcpy((char *)&i, ain, sizeof(afs_int32));
1536 ain += sizeof(afs_int32);
1537 if (i != sizeof(struct ClearToken)) {
1540 memcpy((char *)&clear, ain, sizeof(struct ClearToken));
1541 if (clear.AuthHandle == -1)
1542 clear.AuthHandle = 999; /* more rxvab compat stuff */
1543 ain += sizeof(struct ClearToken);
1544 if (ainSize != 2 * sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1545 /* still stuff left? we've got primary flag and cell name. Set these */
1546 memcpy((char *)&flag, ain, sizeof(afs_int32)); /* primary id flag */
1547 ain += sizeof(afs_int32); /* skip id field */
1548 /* rest is cell name, look it up */
1549 /* some versions of gcc appear to need != 0 in order to get this right */
1550 if ((flag & 0x8000) != 0) { /* XXX Use Constant XXX */
1554 tcell = afs_GetCellByName(ain, READ_LOCK);
1558 /* default to primary cell, primary id */
1559 flag = 1; /* primary id */
1560 tcell = afs_GetPrimaryCell(READ_LOCK);
1565 afs_PutCell(tcell, READ_LOCK);
1566 if (set_parent_pag) {
1568 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1569 #if defined(AFS_DARWIN_ENV)
1570 struct proc *p = current_proc(); /* XXX */
1572 struct proc *p = curproc; /* XXX */
1574 #ifndef AFS_DARWIN80_ENV
1575 uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1576 p->p_pid, p->p_comm);
1578 if (!setpag(p, acred, -1, &pag, 1)) {
1581 if (!setpag(u.u_procp, acred, -1, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
1583 if (!setpag(acred, -1, &pag, 1)) {
1586 afs_InitReq(&treq, *acred);
1590 /* now we just set the tokens */
1591 tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1592 tu->vid = clear.ViceId;
1593 if (tu->stp != NULL) {
1594 afs_osi_Free(tu->stp, tu->stLen);
1596 tu->stp = (char *)afs_osi_Alloc(stLen);
1597 if (tu->stp == NULL) {
1601 memcpy(tu->stp, stp, stLen);
1604 afs_stats_cmfullperf.authent.TicketUpdates++;
1605 afs_ComputePAGStats();
1606 #endif /* AFS_NOSTATS */
1607 tu->states |= UHasTokens;
1608 tu->states &= ~UTokensBad;
1609 afs_SetPrimary(tu, flag);
1610 tu->tokenTime = osi_Time();
1611 afs_ResetUserConns(tu);
1612 afs_PutUser(tu, WRITE_LOCK);
1628 * VIOCGETVOLSTAT (4) - Get volume status
1632 * \param[in] ain not in use
1633 * \param[out] aout status of the volume
1635 * \retval EINVAL Error if some of the standard args aren't set
1637 * \post The status of a volume (based on the FID of the volume), or an offline message /motd
1639 DECL_PIOCTL(PGetVolumeStatus)
1642 char *offLineMsg = afs_osi_Alloc(256);
1643 char *motd = afs_osi_Alloc(256);
1644 register struct afs_conn *tc;
1645 register afs_int32 code = 0;
1646 struct AFSFetchVolumeStatus volstat;
1648 char *Name, *OfflineMsg, *MOTD;
1651 AFS_STATCNT(PGetVolumeStatus);
1657 OfflineMsg = offLineMsg;
1660 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1662 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1665 RXAFS_GetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &volstat,
1666 &Name, &OfflineMsg, &MOTD);
1671 } while (afs_Analyze
1672 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1673 SHARED_LOCK, NULL));
1677 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1679 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1680 cp += sizeof(VolumeStatus);
1681 strcpy(cp, volName);
1682 cp += strlen(volName) + 1;
1683 strcpy(cp, offLineMsg);
1684 cp += strlen(offLineMsg) + 1;
1686 cp += strlen(motd) + 1;
1687 *aoutSize = (cp - aout);
1689 afs_osi_Free(offLineMsg, 256);
1690 afs_osi_Free(motd, 256);
1695 * VIOCSETVOLSTAT (5) - Set volume status
1699 * \param[in] ain values to set the status at, offline message, message of the day, volume name, minimum quota, maximum quota
1700 * \param[out] aout status of a volume, offlines messages, minimum quota, maximumm quota
1702 * \retval EINVAL Error if some of the standard args aren't set
1703 * \retval EROFS Error if the volume is read only, or a backup volume
1704 * \retval ENODEV Error if the volume can't be accessed
1705 * \retval E2BIG Error if the volume name, offline message, and motd are too big
1707 * \post Set the status of a volume, including any offline messages, a minimum quota, and a maximum quota
1709 DECL_PIOCTL(PSetVolumeStatus)
1712 char *offLineMsg = afs_osi_Alloc(256);
1713 char *motd = afs_osi_Alloc(256);
1714 register struct afs_conn *tc;
1715 register afs_int32 code = 0;
1716 struct AFSFetchVolumeStatus volstat;
1717 struct AFSStoreVolumeStatus storeStat;
1718 register struct volume *tvp;
1722 AFS_STATCNT(PSetVolumeStatus);
1728 tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
1730 if (tvp->states & (VRO | VBackup)) {
1731 afs_PutVolume(tvp, READ_LOCK);
1735 afs_PutVolume(tvp, READ_LOCK);
1740 /* Copy the junk out, using cp as a roving pointer. */
1742 memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
1743 cp += sizeof(AFSFetchVolumeStatus);
1744 if (strlen(cp) >= sizeof(volName)) {
1748 strcpy(volName, cp);
1749 cp += strlen(volName) + 1;
1750 if (strlen(cp) >= sizeof(offLineMsg)) {
1754 strcpy(offLineMsg, cp);
1755 cp += strlen(offLineMsg) + 1;
1756 if (strlen(cp) >= sizeof(motd)) {
1762 if (volstat.MinQuota != -1) {
1763 storeStat.MinQuota = volstat.MinQuota;
1764 storeStat.Mask |= AFS_SETMINQUOTA;
1766 if (volstat.MaxQuota != -1) {
1767 storeStat.MaxQuota = volstat.MaxQuota;
1768 storeStat.Mask |= AFS_SETMAXQUOTA;
1771 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1773 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1776 RXAFS_SetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &storeStat,
1777 volName, offLineMsg, motd);
1782 } while (afs_Analyze
1783 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1784 SHARED_LOCK, NULL));
1788 /* we are sending parms back to make compat. with prev system. should
1789 * change interface later to not ask for current status, just set new status */
1791 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1792 cp += sizeof(VolumeStatus);
1793 strcpy(cp, volName);
1794 cp += strlen(volName) + 1;
1795 strcpy(cp, offLineMsg);
1796 cp += strlen(offLineMsg) + 1;
1798 cp += strlen(motd) + 1;
1799 *aoutSize = cp - aout;
1801 afs_osi_Free(offLineMsg, 256);
1802 afs_osi_Free(motd, 256);
1807 * VIOCFLUSH (6) - Invalidate cache entry
1811 * \param[in] ain not in use
1812 * \param[out] aout not in use
1814 * \retval EINVAL Error if some of the standard args aren't set
1816 * \post Flush any information the cache manager has on an entry
1820 AFS_STATCNT(PFlush);
1823 #ifdef AFS_BOZONLOCK_ENV
1824 afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
1826 ObtainWriteLock(&avc->lock, 225);
1827 afs_ResetVCache(avc, *acred);
1828 ReleaseWriteLock(&avc->lock);
1829 #ifdef AFS_BOZONLOCK_ENV
1830 afs_BozonUnlock(&avc->pvnLock, avc);
1836 * VIOC_AFS_STAT_MT_PT (29) - Stat mount point
1840 * \param[in] ain the last component in a path, related to mountpoint that we're looking for information about
1841 * \param[out] aout volume, cell, link data
1843 * \retval EINVAL Error if some of the standard args aren't set
1844 * \retval ENOTDIR Error if the 'mount point' argument isn't a directory
1845 * \retval EIO Error if the link data can't be accessed
1847 * \post Get the volume, and cell, as well as the link data for a mount point
1849 DECL_PIOCTL(PNewStatMount)
1851 register afs_int32 code;
1852 register struct vcache *tvc;
1853 register struct dcache *tdc;
1854 struct VenusFid tfid;
1856 struct sysname_info sysState;
1857 afs_size_t offset, len;
1859 AFS_STATCNT(PNewStatMount);
1862 code = afs_VerifyVCache(avc, areq);
1865 if (vType(avc) != VDIR) {
1868 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
1871 Check_AtSys(avc, ain, &sysState, areq);
1872 ObtainReadLock(&tdc->lock);
1874 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
1875 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1876 ReleaseReadLock(&tdc->lock);
1877 afs_PutDCache(tdc); /* we're done with the data */
1878 bufp = sysState.name;
1882 tfid.Cell = avc->f.fid.Cell;
1883 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
1884 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
1885 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
1887 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
1893 if (tvc->mvstat != 1) {
1898 ObtainWriteLock(&tvc->lock, 226);
1899 code = afs_HandleLink(tvc, areq);
1901 if (tvc->linkData) {
1902 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1905 /* we have the data */
1906 strcpy(aout, tvc->linkData);
1907 *aoutSize = strlen(tvc->linkData) + 1;
1912 ReleaseWriteLock(&tvc->lock);
1915 if (sysState.allocked)
1916 osi_FreeLargeSpace(bufp);
1921 * VIOCGETTOK (8) - Get authentication tokens
1925 * \param[in] ain userid
1926 * \param[out] aout token
1928 * \retval EIO Error if the afs daemon hasn't started yet
1929 * \retval EDOM Error if the input parameter is out of the bounds of the available tokens
1930 * \retval ENOTCONN Error if there aren't tokens for this cell
1932 * \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
1934 * \notes "it's a weird interface (from comments in the code)"
1937 DECL_PIOCTL(PGetTokens)
1939 register struct cell *tcell;
1940 register afs_int32 i;
1941 register struct unixuser *tu;
1943 afs_int32 iterator = 0;
1946 AFS_STATCNT(PGetTokens);
1947 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1948 return EIO; /* Inappropriate ioctl for device */
1950 /* weird interface. If input parameter is present, it is an integer and
1951 * we're supposed to return the parm'th tokens for this unix uid.
1952 * If not present, we just return tokens for cell 1.
1953 * If counter out of bounds, return EDOM.
1954 * If no tokens for the particular cell, return ENOTCONN.
1955 * Also, if this mysterious parm is present, we return, along with the
1956 * tokens, the primary cell indicator (an afs_int32 0) and the cell name
1957 * at the end, in that order.
1959 if ((newStyle = (ainSize > 0))) {
1960 memcpy((char *)&iterator, ain, sizeof(afs_int32));
1962 i = UHash(areq->uid);
1963 ObtainReadLock(&afs_xuser);
1964 for (tu = afs_users[i]; tu; tu = tu->next) {
1966 if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1967 if (iterator-- == 0)
1968 break; /* are we done yet? */
1971 if (tu->uid == areq->uid && afs_IsPrimaryCellNum(tu->cell))
1977 * No need to hold a read lock on each user entry
1981 ReleaseReadLock(&afs_xuser);
1986 if (((tu->states & UHasTokens) == 0)
1987 || (tu->ct.EndTimestamp < osi_Time())) {
1988 tu->states |= (UTokensBad | UNeedsReset);
1989 afs_PutUser(tu, READ_LOCK);
1992 /* use iterator for temp */
1994 iterator = tu->stLen; /* for compat, we try to return 56 byte tix if they fit */
1996 iterator = 56; /* # of bytes we're returning */
1997 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1998 cp += sizeof(afs_int32);
1999 memcpy(cp, tu->stp, tu->stLen); /* copy out st */
2001 iterator = sizeof(struct ClearToken);
2002 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
2003 cp += sizeof(afs_int32);
2004 memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
2005 cp += sizeof(struct ClearToken);
2007 /* put out primary id and cell name, too */
2008 iterator = (tu->states & UPrimary ? 1 : 0);
2009 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
2010 cp += sizeof(afs_int32);
2011 tcell = afs_GetCell(tu->cell, READ_LOCK);
2013 strcpy(cp, tcell->cellName);
2014 cp += strlen(tcell->cellName) + 1;
2015 afs_PutCell(tcell, READ_LOCK);
2019 *aoutSize = cp - aout;
2020 afs_PutUser(tu, READ_LOCK);
2025 * VIOCUNLOG (9) - Invalidate tokens
2029 * \param[in] ain not in use
2030 * \param[out] aout not in use
2032 * \retval EIO Error if the afs daemon hasn't been started yet
2034 * \post remove tokens from a user, specified by the user id
2036 * \notes sets the token's time to 0, which then causes it to be removed
2037 * \notes Unlog is the same as un-pag in OpenAFS
2041 register afs_int32 i;
2042 register struct unixuser *tu;
2044 AFS_STATCNT(PUnlog);
2045 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2046 return EIO; /* Inappropriate ioctl for device */
2048 i = UHash(areq->uid);
2049 ObtainWriteLock(&afs_xuser, 227);
2050 for (tu = afs_users[i]; tu; tu = tu->next) {
2051 if (tu->uid == areq->uid) {
2053 tu->states &= ~UHasTokens;
2054 /* security is not having to say you're sorry */
2055 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
2057 ReleaseWriteLock(&afs_xuser);
2058 /* We have to drop the lock over the call to afs_ResetUserConns, since
2059 * it obtains the afs_xvcache lock. We could also keep the lock, and
2060 * modify ResetUserConns to take parm saying we obtained the lock
2061 * already, but that is overkill. By keeping the "tu" pointer
2062 * held over the released lock, we guarantee that we won't lose our
2063 * place, and that we'll pass over every user conn that existed when
2064 * we began this call.
2066 afs_ResetUserConns(tu);
2068 ObtainWriteLock(&afs_xuser, 228);
2070 /* set the expire times to 0, causes
2071 * afs_GCUserData to remove this entry
2073 tu->ct.EndTimestamp = 0;
2075 #endif /* UKERNEL */
2078 ReleaseWriteLock(&afs_xuser);
2083 * VIOC_AFS_MARINER_HOST (32) - Get/set mariner (cache manager monitor) host
2087 * \param[in] ain host address to be set
2088 * \param[out] aout old host address
2090 * \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
2092 * \notes Errors turn off mariner
2094 DECL_PIOCTL(PMariner)
2096 afs_int32 newHostAddr;
2097 afs_int32 oldHostAddr;
2099 AFS_STATCNT(PMariner);
2101 memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost,
2104 oldHostAddr = 0xffffffff; /* disabled */
2106 memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
2107 if (newHostAddr == 0xffffffff) {
2108 /* disable mariner operations */
2110 } else if (newHostAddr) {
2112 afs_marinerHost = newHostAddr;
2114 memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
2115 *aoutSize = sizeof(afs_int32);
2120 * VIOCCKSERV (10) - Check that servers are up
2124 * \param[in] ain name of the cell
2125 * \param[out] aout current down server list
2127 * \retval EIO Error if the afs daemon hasn't started yet
2128 * \retval EACCES Error if the user doesn't have super-user credentials
2129 * \retval ENOENT Error if we are unable to obtain the cell
2131 * \post Either a fast check (where it doesn't contact servers) or a local check (checks local cell only)
2133 DECL_PIOCTL(PCheckServers)
2135 register char *cp = 0;
2137 register struct server *ts;
2138 afs_int32 temp, *lp = (afs_int32 *) ain, havecell = 0;
2140 struct chservinfo *pcheck;
2142 AFS_STATCNT(PCheckServers);
2144 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2145 return EIO; /* Inappropriate ioctl for device */
2147 if (*lp == 0x12345678) { /* For afs3.3 version */
2148 pcheck = (struct chservinfo *)ain;
2149 if (pcheck->tinterval >= 0) {
2151 memcpy(cp, (char *)&afs_probe_interval, sizeof(afs_int32));
2152 *aoutSize = sizeof(afs_int32);
2153 if (pcheck->tinterval > 0) {
2154 if (!afs_osi_suser(*acred))
2156 afs_probe_interval = pcheck->tinterval;
2162 temp = pcheck->tflags;
2163 cp = pcheck->tbuffer;
2164 } else { /* For pre afs3.3 versions */
2165 memcpy((char *)&temp, ain, sizeof(afs_int32));
2166 cp = ain + sizeof(afs_int32);
2167 if (ainSize > sizeof(afs_int32))
2172 * 1: fast check, don't contact servers.
2173 * 2: local cell only.
2176 /* have cell name, too */
2177 cellp = afs_GetCellByName(cp, READ_LOCK);
2182 if (!cellp && (temp & 2)) {
2183 /* use local cell */
2184 cellp = afs_GetPrimaryCell(READ_LOCK);
2186 if (!(temp & 1)) { /* if not fast, call server checker routine */
2187 afs_CheckServers(1, cellp); /* check down servers */
2188 afs_CheckServers(0, cellp); /* check up servers */
2190 /* now return the current down server list */
2192 ObtainReadLock(&afs_xserver);
2193 for (i = 0; i < NSERVERS; i++) {
2194 for (ts = afs_servers[i]; ts; ts = ts->next) {
2195 if (cellp && ts->cell != cellp)
2196 continue; /* cell spec'd and wrong */
2197 if ((ts->flags & SRVR_ISDOWN)
2198 && ts->addr->sa_portal != ts->cell->vlport) {
2199 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2200 cp += sizeof(afs_int32);
2204 ReleaseReadLock(&afs_xserver);
2206 afs_PutCell(cellp, READ_LOCK);
2207 *aoutSize = cp - aout;
2212 * VIOCCKBACK (11) - Check backup volume mappings
2216 * \param[in] ain not in use
2217 * \param[out] aout not in use
2219 * \retval EIO Error if the afs daemon hasn't started yet
2221 * \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
2223 DECL_PIOCTL(PCheckVolNames)
2225 AFS_STATCNT(PCheckVolNames);
2226 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2227 return EIO; /* Inappropriate ioctl for device */
2229 afs_CheckRootVolume();
2230 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE | AFS_VOLCHECK_EXPIRED |
2231 AFS_VOLCHECK_BUSY | AFS_VOLCHECK_MTPTS);
2236 * VIOCCKCONN (12) - Check connections for a user
2240 * \param[in] ain not in use
2241 * \param[out] aout not in use
2243 * \retval EACCESS Error if no user is specififed, the user has no tokens set, or if the user's tokens are bad
2245 * \post check to see if a user has the correct authentication. If so, allow access.
2247 * \notes Check the connections to all the servers specified
2249 DECL_PIOCTL(PCheckAuth)
2253 struct afs_conn *tc;
2254 struct unixuser *tu;
2257 AFS_STATCNT(PCheckAuth);
2258 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2259 return EIO; /* Inappropriate ioctl for device */
2262 tu = afs_GetUser(areq->uid, 1, READ_LOCK); /* check local cell authentication */
2266 /* we have a user */
2267 ObtainReadLock(&afs_xsrvAddr);
2268 ObtainReadLock(&afs_xconn);
2270 /* any tokens set? */
2271 if ((tu->states & UHasTokens) == 0)
2273 /* all connections in cell 1 working? */
2274 for (i = 0; i < NSERVERS; i++) {
2275 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2276 for (tc = sa->conns; tc; tc = tc->next) {
2277 if (tc->user == tu && (tu->states & UTokensBad))
2282 ReleaseReadLock(&afs_xsrvAddr);
2283 ReleaseReadLock(&afs_xconn);
2284 afs_PutUser(tu, READ_LOCK);
2286 memcpy(aout, (char *)&retValue, sizeof(afs_int32));
2287 *aoutSize = sizeof(afs_int32);
2292 Prefetch(iparmtype apath, struct afs_ioctl *adata, int afollow,
2296 register afs_int32 code;
2297 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
2303 AFS_STATCNT(Prefetch);
2306 tp = osi_AllocLargeSpace(1024);
2307 AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2309 osi_FreeLargeSpace(tp);
2312 if (afs_BBusy()) { /* do this as late as possible */
2313 osi_FreeLargeSpace(tp);
2314 return EWOULDBLOCK; /* pretty close */
2316 afs_BQueue(BOP_PATH, (struct vcache *)0, 0, 0, acred, (afs_size_t) 0,
2317 (afs_size_t) 0, tp);
2322 * VIOCWHEREIS (14) - Find out where a volume is located
2326 * \param[in] ain not in use
2327 * \param[out] aout volume location
2329 * \retval EINVAL Error if some of the default arguments don't exist
2330 * \retval ENODEV Error if there is no such volume
2332 * \post fine a volume, based on a volume file id
2334 * \notes check each of the servers specified
2336 DECL_PIOCTL(PFindVolume)
2338 register struct volume *tvp;
2339 register struct server *ts;
2340 register afs_int32 i;
2343 AFS_STATCNT(PFindVolume);
2346 tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
2349 for (i = 0; i < MAXHOSTS; i++) {
2350 ts = tvp->serverHost[i];
2353 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2354 cp += sizeof(afs_int32);
2357 /* still room for terminating NULL, add it on */
2358 ainSize = 0; /* reuse vbl */
2359 memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
2360 cp += sizeof(afs_int32);
2362 *aoutSize = cp - aout;
2363 afs_PutVolume(tvp, READ_LOCK);
2370 * VIOCACCESS (20) - Access using PRS_FS bits
2374 * \param[in] ain PRS_FS bits
2375 * \param[out] aout not in use
2377 * \retval EINVAL Error if some of the initial arguments aren't set
2378 * \retval EACCES Error if access is denied
2380 * \post check to make sure access is allowed
2382 DECL_PIOCTL(PViceAccess)
2384 register afs_int32 code;
2387 AFS_STATCNT(PViceAccess);
2390 code = afs_VerifyVCache(avc, areq);
2393 memcpy((char *)&temp, ain, sizeof(afs_int32));
2394 code = afs_AccessOK(avc, temp, areq, CHECK_MODE_BITS);
2402 * VIOC_GETPAG (13) - Get PAG value
2406 * \param[in] ain not in use
2407 * \param[out] aout PAG value or NOPAG
2409 * \retval E2BIG Error not enough space to copy out value
2411 * \post get PAG value for the caller's cred
2413 DECL_PIOCTL(PGetPAG)
2417 if (*aoutSize < sizeof(afs_int32)) {
2421 pag = PagInCred(*acred);
2423 memcpy(aout, (char *)&pag, sizeof(afs_int32));
2424 *aoutSize = sizeof(afs_int32);
2428 DECL_PIOCTL(PPrecache)
2432 /*AFS_STATCNT(PPrecache);*/
2433 if (!afs_osi_suser(*acred))
2435 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2436 afs_preCache = newValue*1024;
2441 * VIOCSETCACHESIZE (24) - Set venus cache size in 1000 units
2445 * \param[in] ain the size the venus cache should be set to
2446 * \param[out] aout not in use
2448 * \retval EACCES Error if the user doesn't have super-user credentials
2449 * \retval EROFS Error if the cache is set to be in memory
2451 * \post Set the cache size based on user input. If no size is given, set it to the default OpenAFS cache size.
2453 * \notes recompute the general cache parameters for every single block allocated
2455 DECL_PIOCTL(PSetCacheSize)
2460 AFS_STATCNT(PSetCacheSize);
2461 if (!afs_osi_suser(*acred))
2463 /* too many things are setup initially in mem cache version */
2464 if (cacheDiskType == AFS_FCACHE_TYPE_MEM)
2466 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2468 afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2470 if (newValue < afs_min_cache)
2471 afs_cacheBlocks = afs_min_cache;
2473 afs_cacheBlocks = newValue;
2475 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2476 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2477 afs_MaybeWakeupTruncateDaemon();
2478 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2479 afs_osi_Wait(1000, 0, 0);
2480 afs_MaybeWakeupTruncateDaemon();
2485 #define MAXGCSTATS 16
2487 * VIOCGETCACHEPARMS (40) - Get cache stats
2491 * \param[in] ain afs index flags
2492 * \param[out] aout cache blocks, blocks used, blocks files (in an array)
2494 * \post Get the cache blocks, and how many of the cache blocks there are
2496 DECL_PIOCTL(PGetCacheSize)
2498 afs_int32 results[MAXGCSTATS];
2500 register struct dcache * tdc;
2503 AFS_STATCNT(PGetCacheSize);
2505 if (sizeof(afs_int32) == ainSize){
2506 memcpy((char *)&flags, ain, sizeof(afs_int32));
2507 } else if (0 == ainSize){
2513 memset((char *)results, 0, sizeof(results));
2514 results[0] = afs_cacheBlocks;
2515 results[1] = afs_blocksUsed;
2516 results[2] = afs_cacheFiles;
2519 for (i = 0; i < afs_cacheFiles; i++) {
2520 if (afs_indexFlags[i] & IFFree) results[3]++;
2522 } else if (2 == flags){
2523 for (i = 0; i < afs_cacheFiles; i++) {
2524 if (afs_indexFlags[i] & IFFree) results[3]++;
2525 if (afs_indexFlags[i] & IFEverUsed) results[4]++;
2526 if (afs_indexFlags[i] & IFDataMod) results[5]++;
2527 if (afs_indexFlags[i] & IFDirtyPages) results[6]++;
2528 if (afs_indexFlags[i] & IFAnyPages) results[7]++;
2529 if (afs_indexFlags[i] & IFDiscarded) results[8]++;
2531 tdc = afs_indexTable[i];
2534 size = tdc->validPos;
2535 if ( 0 < size && size < (1<<12) ) results[10]++;
2536 else if (size < (1<<14) ) results[11]++;
2537 else if (size < (1<<16) ) results[12]++;
2538 else if (size < (1<<18) ) results[13]++;
2539 else if (size < (1<<20) ) results[14]++;
2540 else if (size >= (1<<20) ) results[15]++;
2544 memcpy(aout, (char *)results, sizeof(results));
2545 *aoutSize = sizeof(results);
2550 * VIOCFLUSHCB (25) - Flush callback only
2554 * \param[in] ain not in use
2555 * \param[out] aout not in use
2557 * \retval EINVAL Error if some of the standard args aren't set
2558 * \retval 0 0 returned if the volume is set to read-only
2560 * \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.
2562 DECL_PIOCTL(PRemoveCallBack)
2564 register struct afs_conn *tc;
2565 register afs_int32 code = 0;
2566 struct AFSCallBack CallBacks_Array[1];
2567 struct AFSCBFids theFids;
2568 struct AFSCBs theCBs;
2571 AFS_STATCNT(PRemoveCallBack);
2574 if (avc->f.states & CRO)
2575 return 0; /* read-only-ness can't change */
2576 ObtainWriteLock(&avc->lock, 229);
2577 theFids.AFSCBFids_len = 1;
2578 theCBs.AFSCBs_len = 1;
2579 theFids.AFSCBFids_val = (struct AFSFid *)&avc->f.fid.Fid;
2580 theCBs.AFSCBs_val = CallBacks_Array;
2581 CallBacks_Array[0].CallBackType = CB_DROPPED;
2582 if (avc->callback) {
2584 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
2586 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2588 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2592 /* don't set code on failure since we wouldn't use it */
2593 } while (afs_Analyze
2594 (tc, code, &avc->f.fid, areq,
2595 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK, NULL));
2597 ObtainWriteLock(&afs_xcbhash, 457);
2598 afs_DequeueCallback(avc);
2600 avc->f.states &= ~(CStatd | CUnique);
2601 ReleaseWriteLock(&afs_xcbhash);
2602 if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2603 osi_dnlc_purgedp(avc);
2605 ReleaseWriteLock(&avc->lock);
2610 * VIOCNEWCELL (26) - Configure new cell
2614 * \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
2615 * \param[out] aout not in use
2617 * \retval EIO Error if the afs daemon hasn't started yet
2618 * \retval EACCES Error if the user doesn't have super-user cedentials
2619 * \retval EINVAL Error if some 'magic' var doesn't have a certain bit set
2621 * \post creates a new cell
2623 DECL_PIOCTL(PNewCell)
2625 /* create a new cell */
2626 afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic = 0;
2627 char *newcell = 0, *linkedcell = 0, *tp = ain;
2628 register afs_int32 code, linkedstate = 0, ls;
2629 u_short fsport = 0, vlport = 0;
2632 AFS_STATCNT(PNewCell);
2633 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2634 return EIO; /* Inappropriate ioctl for device */
2636 if (!afs_osi_suser(*acred))
2639 memcpy((char *)&magic, tp, sizeof(afs_int32));
2640 tp += sizeof(afs_int32);
2641 if (magic != 0x12345678)
2644 /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2645 * server addresses while the 3.5 fs newcell command passes
2646 * MAXHOSTS. To figure out which is which, check if the cellname
2649 newcell = tp + (MAXCELLHOSTS + 3) * sizeof(afs_int32);
2650 scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2652 /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2653 memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
2654 tp += (scount * sizeof(afs_int32));
2656 lp = (afs_int32 *) tp;
2660 fsport = 0; /* Privileged ports not allowed */
2662 vlport = 0; /* Privileged ports not allowed */
2663 tp += (3 * sizeof(afs_int32));
2665 if ((ls = *lp) & 1) {
2666 linkedcell = tp + strlen(newcell) + 1;
2667 linkedstate |= CLinkedCell;
2670 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2672 afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport,
2677 DECL_PIOCTL(PNewAlias)
2679 /* create a new cell alias */
2681 register afs_int32 code;
2682 char *realName, *aliasName;
2684 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2685 return EIO; /* Inappropriate ioctl for device */
2687 if (!afs_osi_suser(*acred))
2691 tp += strlen(aliasName) + 1;
2694 code = afs_NewCellAlias(aliasName, realName);
2700 * VIOCGETCELL (27) - Get cell info
2704 * \param[in] ain The cell index of a specific cell
2705 * \param[out] aout list of servers in the cell
2707 * \retval EIO Error if the afs daemon hasn't started yet
2708 * \retval EDOM Error if there is no cell asked about
2710 * \post Lists the cell's server names and and addresses
2712 DECL_PIOCTL(PListCells)
2714 afs_int32 whichCell;
2715 register struct cell *tcell = 0;
2716 register afs_int32 i;
2717 register char *cp, *tp = ain;
2719 AFS_STATCNT(PListCells);
2720 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2721 return EIO; /* Inappropriate ioctl for device */
2723 memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2724 tp += sizeof(afs_int32);
2725 tcell = afs_GetCellByIndex(whichCell, READ_LOCK);
2728 memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
2729 for (i = 0; i < MAXCELLHOSTS; i++) {
2730 if (tcell->cellHosts[i] == 0)
2732 memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip,
2734 cp += sizeof(afs_int32);
2736 cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2737 strcpy(cp, tcell->cellName);
2738 cp += strlen(tcell->cellName) + 1;
2739 *aoutSize = cp - aout;
2740 afs_PutCell(tcell, READ_LOCK);
2748 DECL_PIOCTL(PListAliases)
2750 afs_int32 whichAlias;
2751 register struct cell_alias *tcalias = 0;
2752 register char *cp, *tp = ain;
2754 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2755 return EIO; /* Inappropriate ioctl for device */
2756 if (ainSize < sizeof(afs_int32))
2759 memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2760 tp += sizeof(afs_int32);
2762 tcalias = afs_GetCellAlias(whichAlias);
2765 strcpy(cp, tcalias->alias);
2766 cp += strlen(tcalias->alias) + 1;
2767 strcpy(cp, tcalias->cell);
2768 cp += strlen(tcalias->cell) + 1;
2769 *aoutSize = cp - aout;
2770 afs_PutCellAlias(tcalias);
2779 * VIOC_AFS_DELETE_MT_PT (28) - Delete mount point
2783 * \param[in] ain the name of the file in this dir to remove
2784 * \param[out] aout not in use
2786 * \retval EINVAL Error if some of the standard args aren't set
2787 * \retval ENOTDIR Error if the argument to remove is not a directory
2788 * \retval ENOENT Error if there is no cache to remove the mount point from or if a vcache doesn't exist
2790 * \post Ensure that everything is OK before deleting the mountpoint. If not, don't delete. Delete a mount point based on a file id.
2792 DECL_PIOCTL(PRemoveMount)
2794 register afs_int32 code;
2796 struct sysname_info sysState;
2797 afs_size_t offset, len;
2798 register struct afs_conn *tc;
2799 register struct dcache *tdc;
2800 register struct vcache *tvc;
2801 struct AFSFetchStatus OutDirStatus;
2802 struct VenusFid tfid;
2803 struct AFSVolSync tsync;
2807 /* "ain" is the name of the file in this dir to remove */
2809 AFS_STATCNT(PRemoveMount);
2812 code = afs_VerifyVCache(avc, areq);
2815 if (vType(avc) != VDIR)
2818 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1); /* test for error below */
2821 Check_AtSys(avc, ain, &sysState, areq);
2822 ObtainReadLock(&tdc->lock);
2824 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
2825 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2826 ReleaseReadLock(&tdc->lock);
2827 bufp = sysState.name;
2832 tfid.Cell = avc->f.fid.Cell;
2833 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
2834 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
2835 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
2837 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
2844 if (tvc->mvstat != 1) {
2850 ObtainWriteLock(&tvc->lock, 230);
2851 code = afs_HandleLink(tvc, areq);
2853 if (tvc->linkData) {
2854 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2859 ReleaseWriteLock(&tvc->lock);
2860 osi_dnlc_purgedp(tvc);
2866 ObtainWriteLock(&avc->lock, 231);
2867 osi_dnlc_remove(avc, bufp, tvc);
2869 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
2871 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2874 RXAFS_RemoveFile(tc->id, (struct AFSFid *)&avc->f.fid.Fid, bufp,
2875 &OutDirStatus, &tsync);
2880 } while (afs_Analyze
2881 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_REMOVEFILE,
2882 SHARED_LOCK, NULL));
2887 ReleaseWriteLock(&avc->lock);
2891 /* we have the thing in the cache */
2892 ObtainWriteLock(&tdc->lock, 661);
2893 if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2894 /* we can do it locally */
2895 code = afs_dir_Delete(tdc, bufp);
2897 ZapDCE(tdc); /* surprise error -- invalid value */
2901 ReleaseWriteLock(&tdc->lock);
2902 afs_PutDCache(tdc); /* drop ref count */
2904 avc->f.states &= ~CUnique; /* For the dfs xlator */
2905 ReleaseWriteLock(&avc->lock);
2908 if (sysState.allocked)
2909 osi_FreeLargeSpace(bufp);
2914 * VIOC_VENUSLOG (34) - Enable/Disable venus logging
2918 * \retval EINVAL Error if some of the standard args aren't set
2920 * \notes Obsoleted, perhaps should be PBogus
2922 DECL_PIOCTL(PVenusLogging)
2924 return EINVAL; /* OBSOLETE */
2928 * VIOC_GETCELLSTATUS (35) - Get cell status info
2932 * \param[in] ain The cell you want status information on
2933 * \param[out] aout cell state (as a struct)
2935 * \retval EIO Error if the afs daemon hasn't started yet
2936 * \retval ENOENT Error if the cell doesn't exist
2938 * \post Returns the state of the cell as defined in a struct cell
2940 DECL_PIOCTL(PGetCellStatus)
2942 register struct cell *tcell;
2945 AFS_STATCNT(PGetCellStatus);
2946 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2947 return EIO; /* Inappropriate ioctl for device */
2949 tcell = afs_GetCellByName(ain, READ_LOCK);
2952 temp = tcell->states;
2953 afs_PutCell(tcell, READ_LOCK);
2954 memcpy(aout, (char *)&temp, sizeof(afs_int32));
2955 *aoutSize = sizeof(afs_int32);
2960 * VIOC_SETCELLSTATUS (36) - Set corresponding info
2964 * \param[in] ain The cell you want to set information about, and the values you want to set
2965 * \param[out] aout not in use
2967 * \retval EIO Error if the afs daemon hasn't started yet
2968 * \retval EACCES Error if the user doesn't have super-user credentials
2970 * \post Set the state of the cell in a defined struct cell, based on whether or not SetUID is allowed
2972 DECL_PIOCTL(PSetCellStatus)
2974 register struct cell *tcell;
2977 if (!afs_osi_suser(*acred))
2979 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2980 return EIO; /* Inappropriate ioctl for device */
2982 tcell = afs_GetCellByName(ain + 2 * sizeof(afs_int32), WRITE_LOCK);
2985 memcpy((char *)&temp, ain, sizeof(afs_int32));
2987 tcell->states |= CNoSUID;
2989 tcell->states &= ~CNoSUID;
2990 afs_PutCell(tcell, WRITE_LOCK);
2995 * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
2999 * \param[in] ain not in use (args in avc)
3000 * \param[out] aout not in use
3002 * \retval EINVAL Error if some of the standard args aren't set
3003 * \retval EIO Error if the afs daemon hasn't started yet
3005 * \post Wipe everything on the volume. This is done dependent on which platform this is for.
3007 * \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.
3009 DECL_PIOCTL(PFlushVolumeData)
3011 register afs_int32 i;
3012 register struct dcache *tdc;
3013 register struct vcache *tvc;
3014 register struct volume *tv;
3015 afs_int32 cell, volume;
3016 struct afs_q *tq, *uq;
3017 #ifdef AFS_DARWIN80_ENV
3021 AFS_STATCNT(PFlushVolumeData);
3024 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3025 return EIO; /* Inappropriate ioctl for device */
3027 volume = avc->f.fid.Fid.Volume; /* who to zap */
3028 cell = avc->f.fid.Cell;
3031 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
3032 * the vcaches associated with the volume.
3035 ObtainReadLock(&afs_xvcache);
3036 i = VCHashV(&avc->f.fid);
3037 for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
3040 if (tvc->f.fid.Fid.Volume == volume && tvc->f.fid.Cell == cell) {
3041 if (tvc->f.states & CVInit) {
3042 ReleaseReadLock(&afs_xvcache);
3043 afs_osi_Sleep(&tvc->f.states);
3046 #ifdef AFS_DARWIN80_ENV
3047 if (tvc->f.states & CDeadVnode) {
3048 ReleaseReadLock(&afs_xvcache);
3049 afs_osi_Sleep(&tvc->f.states);
3053 #if defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
3054 VN_HOLD(AFSTOV(tvc));
3056 #ifdef AFS_DARWIN80_ENV
3060 if (vnode_ref(vp)) {
3067 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
3070 VREFCOUNT_INC(tvc); /* AIX, apparently */
3074 ReleaseReadLock(&afs_xvcache);
3075 #ifdef AFS_BOZONLOCK_ENV
3076 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3078 ObtainWriteLock(&tvc->lock, 232);
3080 ObtainWriteLock(&afs_xcbhash, 458);
3081 afs_DequeueCallback(tvc);
3082 tvc->f.states &= ~(CStatd | CDirty);
3083 ReleaseWriteLock(&afs_xcbhash);
3084 if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
3085 osi_dnlc_purgedp(tvc);
3086 afs_TryToSmush(tvc, *acred, 1);
3087 ReleaseWriteLock(&tvc->lock);
3088 #ifdef AFS_BOZONLOCK_ENV
3089 afs_BozonUnlock(&tvc->pvnLock, tvc);
3091 #ifdef AFS_DARWIN80_ENV
3092 vnode_put(AFSTOV(tvc));
3094 ObtainReadLock(&afs_xvcache);
3096 /* our tvc ptr is still good until now */
3100 ReleaseReadLock(&afs_xvcache);
3103 MObtainWriteLock(&afs_xdcache, 328); /* needed if you're going to flush any stuff */
3104 for (i = 0; i < afs_cacheFiles; i++) {
3105 if (!(afs_indexFlags[i] & IFEverUsed))
3106 continue; /* never had any data */
3107 tdc = afs_GetDSlot(i, NULL);
3108 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
3109 ReleaseReadLock(&tdc->tlock);
3110 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
3111 if (!(afs_indexFlags[i] & IFDataMod)) {
3112 /* if the file is modified, but has a ref cnt of only 1, then
3113 * someone probably has the file open and is writing into it.
3114 * Better to skip flushing such a file, it will be brought back
3115 * immediately on the next write anyway.
3117 * If we *must* flush, then this code has to be rearranged to call
3118 * afs_storeAllSegments() first */
3119 afs_FlushDCache(tdc);
3123 ReleaseReadLock(&tdc->tlock);
3125 afs_PutDCache(tdc); /* bumped by getdslot */
3127 MReleaseWriteLock(&afs_xdcache);
3129 ObtainReadLock(&afs_xvolume);
3130 for (i = 0; i < NVOLS; i++) {
3131 for (tv = afs_volumes[i]; tv; tv = tv->next) {
3132 if (tv->volume == volume) {
3133 afs_ResetVolumeInfo(tv);
3138 ReleaseReadLock(&afs_xvolume);
3140 /* probably, a user is doing this, probably, because things are screwed up.
3141 * maybe it's the dnlc's fault? */
3148 * VIOCGETVCXSTATUS (41) - gets vnode x status
3152 * \param[in] ain not in use (avc used)
3153 * \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
3155 * \retval EINVAL Error if some of the initial default arguments aren't set
3156 * \retval EACCES Error if access to check the mode bits is denied
3158 * \post gets stats for the vnode, a struct listed in vcxstat
3160 DECL_PIOCTL(PGetVnodeXStatus)
3162 register afs_int32 code;
3163 struct vcxstat stat;
3166 /* AFS_STATCNT(PGetVnodeXStatus); */
3169 code = afs_VerifyVCache(avc, areq);
3172 if (vType(avc) == VDIR)
3173 mode = PRSFS_LOOKUP;
3176 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3179 memset(&stat, 0, sizeof(struct vcxstat));
3180 stat.fid = avc->f.fid;
3181 hset32(stat.DataVersion, hgetlo(avc->f.m.DataVersion));
3182 stat.lock = avc->lock;
3183 stat.parentVnode = avc->f.parent.vnode;
3184 stat.parentUnique = avc->f.parent.unique;
3185 hset(stat.flushDV, avc->flushDV);
3186 hset(stat.mapDV, avc->mapDV);
3187 stat.truncPos = avc->f.truncPos;
3188 { /* just grab the first two - won't break anything... */
3189 struct axscache *ac;
3191 for (i = 0, ac = avc->Access; ac && i < CPSIZE; i++, ac = ac->next) {
3192 stat.randomUid[i] = ac->uid;
3193 stat.randomAccess[i] = ac->axess;
3196 stat.callback = afs_data_pointer_to_int32(avc->callback);
3197 stat.cbExpires = avc->cbExpires;
3198 stat.anyAccess = avc->f.anyAccess;
3199 stat.opens = avc->opens;
3200 stat.execsOrWriters = avc->execsOrWriters;
3201 stat.flockCount = avc->flockCount;
3202 stat.mvstat = avc->mvstat;
3203 stat.states = avc->f.states;
3204 memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
3205 *aoutSize = sizeof(struct vcxstat);
3210 DECL_PIOCTL(PGetVnodeXStatus2)
3212 register afs_int32 code;
3213 struct vcxstat2 stat;
3218 code = afs_VerifyVCache(avc, areq);
3221 if (vType(avc) == VDIR)
3222 mode = PRSFS_LOOKUP;
3225 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3228 memset(&stat, 0, sizeof(struct vcxstat2));
3230 stat.cbExpires = avc->cbExpires;
3231 stat.anyAccess = avc->f.anyAccess;
3232 stat.mvstat = avc->mvstat;
3233 stat.callerAccess = afs_GetAccessBits(avc, ~0, areq);
3235 memcpy(aout, (char *)&stat, sizeof(struct vcxstat2));
3236 *aoutSize = sizeof(struct vcxstat2);
3242 * VIOC_AFS_SYSNAME (38) - Change @sys value
3246 * \param[in] ain new value for @sys
3247 * \param[out] aout count, entry, list (debug values?)
3249 * \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"
3250 * \retval ENODEV Error if there isn't already a system named that ("I THINK")
3251 * \retval EACCES Error if the user doesn't have super-user credentials
3253 * \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
3255 * \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.
3257 DECL_PIOCTL(PSetSysName)
3259 char *cp, *cp2 = NULL, inname[MAXSYSNAME], outname[MAXSYSNAME];
3260 afs_int32 setsysname;
3262 register struct afs_exporter *exporter;
3263 register struct unixuser *au;
3264 register afs_int32 pag, error;
3265 int t, count, num = 0, allpags = 0;
3268 AFS_STATCNT(PSetSysName);
3269 if (!afs_globalVFS) {
3270 /* Afsd is NOT running; disable it */
3271 #if defined(KERNEL_HAVE_UERROR)
3272 return (setuerror(EINVAL), EINVAL);
3277 memset(inname, 0, MAXSYSNAME);
3278 memcpy(&setsysname, ain, sizeof(afs_int32));
3279 ain += sizeof(afs_int32);
3280 if (setsysname & 0x8000) {
3282 setsysname &= ~0x8000;
3287 if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
3290 for (cp = ain, count = 0; count < setsysname; count++) {
3291 /* won't go past end of ain since maxsysname*num < ain length */
3293 if (t >= MAXSYSNAME || t <= 0)
3295 /* check for names that can shoot us in the foot */
3296 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
3302 /* inname gets first entry in case we're being a translator */
3304 memcpy(inname, ain, t + 1); /* include terminating null */
3308 if ((*acred)->cr_gid == RMTUSER_REQ ||
3309 (*acred)->cr_gid == RMTUSER_REQ_PRIV) { /* Handles all exporters */
3310 if (allpags && (*acred)->cr_gid != RMTUSER_REQ_PRIV) {
3313 pag = PagInCred(*acred);
3315 return EINVAL; /* Better than panicing */
3317 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
3318 return EINVAL; /* Better than panicing */
3320 if (!(exporter = au->exporter)) {
3321 afs_PutUser(au, READ_LOCK);
3322 return EINVAL; /* Better than panicing */
3324 error = EXP_SYSNAME(exporter, (setsysname ? cp2 : NULL), &sysnamelist,
3327 if (error == ENODEV)
3328 foundname = 0; /* sysname not set yet! */
3330 afs_PutUser(au, READ_LOCK);
3335 strcpy(outname, sysnamelist[0]);
3337 afs_PutUser(au, READ_LOCK);
3341 /* Not xlating, so local case */
3343 osi_Panic("PSetSysName: !afs_sysname\n");
3344 if (!setsysname) { /* user just wants the info */
3345 strcpy(outname, afs_sysname);
3346 foundname = afs_sysnamecount;
3347 sysnamelist = afs_sysnamelist;
3348 } else { /* Local guy; only root can change sysname */
3349 if (!afs_osi_suser(*acred))
3352 /* allpags makes no sense for local use */
3356 /* clear @sys entries from the dnlc, once afs_lookup can
3357 * do lookups of @sys entries and thinks it can trust them */
3358 /* privs ok, store the entry, ... */
3359 strcpy(afs_sysname, inname);
3360 if (setsysname > 1) { /* ... or list */
3362 for (count = 1; count < setsysname; ++count) {
3363 if (!afs_sysnamelist[count])
3365 ("PSetSysName: no afs_sysnamelist entry to write\n");
3367 memcpy(afs_sysnamelist[count], cp, t + 1); /* include null */
3371 afs_sysnamecount = setsysname;
3376 cp = aout; /* not changing so report back the count and ... */
3377 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
3378 cp += sizeof(afs_int32);
3380 strcpy(cp, outname); /* ... the entry, ... */
3381 cp += strlen(outname) + 1;
3382 for (count = 1; count < foundname; ++count) { /* ... or list. */
3383 if (!sysnamelist[count])
3385 ("PSetSysName: no afs_sysnamelist entry to read\n");
3386 t = strlen(sysnamelist[count]);
3387 if (t >= MAXSYSNAME)
3388 osi_Panic("PSetSysName: sysname entry garbled\n");
3389 strcpy(cp, sysnamelist[count]);
3393 *aoutSize = cp - aout;
3398 /* sequential search through the list of touched cells is not a good
3399 * long-term solution here. For small n, though, it should be just
3400 * fine. Should consider special-casing the local cell for large n.
3401 * Likewise for PSetSPrefs.
3403 * s - number of ids in array l[] -- NOT index of last id
3404 * l - array of cell ids which have volumes that need to be sorted
3405 * vlonly - sort vl servers or file servers?
3408 ReSortCells_cb(struct cell *cell, void *arg)
3410 afs_int32 *p = (afs_int32 *) arg;
3411 afs_int32 *l = p + 1;
3414 for (i = 0; i < s; i++) {
3415 if (l[i] == cell->cellNum) {
3416 ObtainWriteLock(&cell->lock, 690);
3417 afs_SortServers(cell->cellHosts, MAXCELLHOSTS);
3418 ReleaseWriteLock(&cell->lock);
3426 ReSortCells(int s, afs_int32 * l, int vlonly)
3434 p = (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * (s + 1));
3436 memcpy(p + 1, l, s * sizeof(afs_int32));
3437 afs_TraverseCells(&ReSortCells_cb, p);
3438 afs_osi_Free(p, sizeof(afs_int32) * (s + 1));
3442 ObtainReadLock(&afs_xvolume);
3443 for (i = 0; i < NVOLS; i++) {
3444 for (j = afs_volumes[i]; j; j = j->next) {
3445 for (k = 0; k < s; k++)
3446 if (j->cell == l[k]) {
3447 ObtainWriteLock(&j->lock, 233);
3448 afs_SortServers(j->serverHost, MAXHOSTS);
3449 ReleaseWriteLock(&j->lock);
3454 ReleaseReadLock(&afs_xvolume);
3458 static int debugsetsp = 0;
3460 afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
3463 int i, j, k, matches, touchedSize;
3464 struct server *srvr = NULL;
3465 afs_int32 touched[34];
3469 for (k = 0; k < num; sp++, k++) {
3471 printf("sp host=%x, rank=%d\n", sp->host.s_addr, sp->rank);
3474 ObtainReadLock(&afs_xserver);
3476 i = SHash(sp->host.s_addr);
3477 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
3478 if (sa->sa_ip == sp->host.s_addr) {
3480 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3481 || (sa->sa_portal == AFS_FSPORT);
3482 if ((!vlonly && isfs) || (vlonly && !isfs)) {
3489 if (sa && matches) { /* found one! */
3491 printf("sa ip=%x, ip_rank=%d\n", sa->sa_ip, sa->sa_iprank);
3493 sa->sa_iprank = sp->rank + afs_randomMod15();
3494 afs_SortOneServer(sa->server);
3497 /* if we don't know yet what cell it's in, this is moot */
3498 for (j = touchedSize - 1;
3499 j >= 0 && touched[j] != srvr->cell->cellNum; j--)
3500 /* is it in our list of touched cells ? */ ;
3501 if (j < 0) { /* no, it's not */
3502 touched[touchedSize++] = srvr->cell->cellNum;
3503 if (touchedSize >= 32) { /* watch for ovrflow */
3504 ReleaseReadLock(&afs_xserver);
3505 ReSortCells(touchedSize, touched, vlonly);
3507 ObtainReadLock(&afs_xserver);
3513 ReleaseReadLock(&afs_xserver);
3514 /* if we didn't find one, start to create one. */
3515 /* Note that it doesn't have a cell yet... */
3517 afs_uint32 temp = sp->host.s_addr;
3519 afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
3520 WRITE_LOCK, (afsUUID *) 0, 0);
3521 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3522 afs_PutServer(srvr, WRITE_LOCK);
3524 } /* for all cited preferences */
3526 ReSortCells(touchedSize, touched, vlonly);
3531 * VIOC_SETPREFS (46) - Set server ranks
3533 * \param[in] ain the sprefs value you want the sprefs to be set to
3534 * \param[out] aout not in use
3536 * \retval EIO Error if the afs daemon hasn't started yet
3537 * \retval EACCES Error if the user doesn't have super-user credentials
3538 * \retval EINVAL Error if the struct setsprefs is too large or if it multiplied by the number of servers is too large
3540 * \post set the sprefs using the afs_setsprefs() function
3542 DECL_PIOCTL(PSetSPrefs)
3544 struct setspref *ssp;
3545 AFS_STATCNT(PSetSPrefs);
3547 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3548 return EIO; /* Inappropriate ioctl for device */
3550 if (!afs_osi_suser(*acred))
3553 if (ainSize < sizeof(struct setspref))
3556 ssp = (struct setspref *)ain;
3557 if (ainSize < sizeof(struct spref) * ssp->num_servers)
3560 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
3561 (ssp->flags & DBservers));
3566 * VIOC_SETPREFS33 (42) - Set server ranks (deprecated)
3568 * \param[in] ain the server preferences to be set
3569 * \param[out] aout not in use
3571 * \retval EIO Error if the afs daemon hasn't started yet
3572 * \retval EACCES Error if the user doesn't have super-user credentials
3574 * \post set the server preferences, calling a function
3576 * \notes this may only be performed by the local root user.
3578 DECL_PIOCTL(PSetSPrefs33)
3581 AFS_STATCNT(PSetSPrefs);
3582 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3583 return EIO; /* Inappropriate ioctl for device */
3586 if (!afs_osi_suser(*acred))
3589 sp = (struct spref *)ain;
3590 afs_setsprefs(sp, ainSize / (sizeof(struct spref)), 0 /*!vlonly */ );
3595 * VIOC_GETSPREFS (43) - Get server ranks
3599 * \param[in] ain the server preferences to get
3600 * \param[out] aout the server preferences information
3602 * \retval EIO Error if the afs daemon hasn't started yet
3603 * \retval ENOENT Error if the sprefrequest is too large
3605 * \post Get the sprefs
3607 * \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.
3609 DECL_PIOCTL(PGetSPrefs)
3611 struct sprefrequest *spin; /* input */
3612 struct sprefinfo *spout; /* output */
3613 struct spref *srvout; /* one output component */
3614 int i, j; /* counters for hash table traversal */
3615 struct server *srvr; /* one of CM's server structs */
3617 int vlonly; /* just return vlservers ? */
3620 AFS_STATCNT(PGetSPrefs);
3621 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3622 return EIO; /* Inappropriate ioctl for device */
3625 if (ainSize < sizeof(struct sprefrequest_33)) {
3628 spin = ((struct sprefrequest *)ain);
3631 if (ainSize > sizeof(struct sprefrequest_33)) {
3632 vlonly = (spin->flags & DBservers);
3636 /* struct sprefinfo includes 1 server struct... that size gets added
3637 * in during the loop that follows.
3639 *aoutSize = sizeof(struct sprefinfo) - sizeof(struct spref);
3640 spout = (struct sprefinfo *)aout;
3641 spout->next_offset = spin->offset;
3642 spout->num_servers = 0;
3643 srvout = spout->servers;
3645 ObtainReadLock(&afs_xserver);
3646 for (i = 0, j = 0; j < NSERVERS; j++) { /* sift through hash table */
3647 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3648 if (spin->offset > (unsigned short)i) {
3649 continue; /* catch up to where we left off */
3651 spout->next_offset++;
3654 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3655 || (sa->sa_portal == AFS_FSPORT);
3657 if ((vlonly && isfs) || (!vlonly && !isfs)) {
3658 /* only report ranks for vl servers */
3662 srvout->host.s_addr = sa->sa_ip;
3663 srvout->rank = sa->sa_iprank;
3664 *aoutSize += sizeof(struct spref);
3665 spout->num_servers++;
3668 if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3669 ReleaseReadLock(&afs_xserver); /* no more room! */
3674 ReleaseReadLock(&afs_xserver);
3676 spout->next_offset = 0; /* start over from the beginning next time */
3680 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3681 int afs_NFSRootOnly = 1;
3683 * VIOC_EXPORTAFS (39) - Export afs to nfs clients
3687 * \param[in] ain a struct Vic * EIOctl containing export values needed to change between nfs and afs
3688 * \param[out] aout a struct of the exporter states (exporter->exp_states)
3690 * \retval ENODEV Error if the exporter doesn't exist
3691 * \retval EACCES Error if the user doesn't have super-user credentials
3693 * \post Changes the state of various values to reflect the change of the export values between nfs and afs.
3695 * \notes Legacy code obtained from IBM.
3697 DECL_PIOCTL(PExportAfs)
3699 afs_int32 export, newint =
3700 0, type, changestate, handleValue, convmode, pwsync, smounts;
3701 afs_int32 rempags = 0, pagcb = 0;
3702 register struct afs_exporter *exporter;
3704 AFS_STATCNT(PExportAfs);
3705 memcpy((char *)&handleValue, ain, sizeof(afs_int32));
3706 type = handleValue >> 24;
3711 exporter = exporter_find(type);
3713 export = handleValue & 3;
3714 changestate = handleValue & 0xfff;
3715 smounts = (handleValue >> 2) & 3;
3716 pwsync = (handleValue >> 4) & 3;
3717 convmode = (handleValue >> 6) & 3;
3718 rempags = (handleValue >> 8) & 3;
3719 pagcb = (handleValue >> 10) & 3;
3721 changestate = (handleValue >> 16) & 0x1;
3722 convmode = (handleValue >> 16) & 0x2;
3723 pwsync = (handleValue >> 16) & 0x4;
3724 smounts = (handleValue >> 16) & 0x8;
3725 export = handleValue & 0xff;
3728 /* Failed finding desired exporter; */
3732 handleValue = exporter->exp_states;
3733 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3734 *aoutSize = sizeof(afs_int32);
3736 if (!afs_osi_suser(*acred))
3737 return EACCES; /* Only superuser can do this */
3741 exporter->exp_states |= EXP_EXPORTED;
3743 exporter->exp_states &= ~EXP_EXPORTED;
3747 exporter->exp_states |= EXP_UNIXMODE;
3749 exporter->exp_states &= ~EXP_UNIXMODE;
3753 exporter->exp_states |= EXP_PWSYNC;
3755 exporter->exp_states &= ~EXP_PWSYNC;
3759 afs_NFSRootOnly = 0;
3760 exporter->exp_states |= EXP_SUBMOUNTS;
3762 afs_NFSRootOnly = 1;
3763 exporter->exp_states &= ~EXP_SUBMOUNTS;
3768 exporter->exp_states |= EXP_CLIPAGS;
3770 exporter->exp_states &= ~EXP_CLIPAGS;
3774 exporter->exp_states |= EXP_CALLBACK;
3776 exporter->exp_states &= ~EXP_CALLBACK;
3778 handleValue = exporter->exp_states;
3779 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3780 *aoutSize = sizeof(afs_int32);
3783 exporter->exp_states |= EXP_EXPORTED;
3785 exporter->exp_states &= ~EXP_EXPORTED;
3787 exporter->exp_states |= EXP_UNIXMODE;
3789 exporter->exp_states &= ~EXP_UNIXMODE;
3791 exporter->exp_states |= EXP_PWSYNC;
3793 exporter->exp_states &= ~EXP_PWSYNC;
3795 afs_NFSRootOnly = 0;
3796 exporter->exp_states |= EXP_SUBMOUNTS;
3798 afs_NFSRootOnly = 1;
3799 exporter->exp_states &= ~EXP_SUBMOUNTS;
3808 * VIOC_GAG (44) - Silence Cache Manager
3812 * \param[in] ain the flags to either gag or de-gag the cache manager
3813 * \param[out] aout not in use
3815 * \retval EACCES Error if the user doesn't have super-user credentials
3817 * \post set the gag flags, then show these flags
3821 struct gaginfo *gagflags;
3823 if (!afs_osi_suser(*acred))
3826 gagflags = (struct gaginfo *)ain;
3827 afs_showflags = gagflags->showflags;
3833 * VIOC_TWIDDLE (45) - Adjust RX knobs
3837 * \param[in] ain the previous settings of the 'knobs'
3838 * \param[out] aout not in use
3840 * \retval EACCES Error if the user doesn't have super-user credentials
3842 * \post build out the struct rxp, from a struct rx
3844 DECL_PIOCTL(PTwiddleRx)
3846 struct rxparams *rxp;
3848 if (!afs_osi_suser(*acred))
3851 rxp = (struct rxparams *)ain;
3853 if (rxp->rx_initReceiveWindow)
3854 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3855 if (rxp->rx_maxReceiveWindow)
3856 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3857 if (rxp->rx_initSendWindow)
3858 rx_initSendWindow = rxp->rx_initSendWindow;
3859 if (rxp->rx_maxSendWindow)
3860 rx_maxSendWindow = rxp->rx_maxSendWindow;
3861 if (rxp->rxi_nSendFrags)
3862 rxi_nSendFrags = rxp->rxi_nSendFrags;
3863 if (rxp->rxi_nRecvFrags)
3864 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3865 if (rxp->rxi_OrphanFragSize)
3866 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3867 if (rxp->rx_maxReceiveSize) {
3868 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3869 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3871 if (rxp->rx_MyMaxSendSize)
3872 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3878 * VIOC_GETINITPARAMS (49) - Get initial cache manager parameters
3882 * \param[in] ain not in use
3883 * \param[out] aout initial cache manager params
3885 * \retval E2BIG Error if the initial parameters are bigger than some PIGGYSIZE
3887 * \post return the initial cache manager parameters
3889 DECL_PIOCTL(PGetInitParams)
3891 if (sizeof(struct cm_initparams) > PIGGYSIZE)
3894 memcpy(aout, (char *)&cm_initParams, sizeof(struct cm_initparams));
3895 *aoutSize = sizeof(struct cm_initparams);
3899 #ifdef AFS_SGI65_ENV
3900 /* They took crget() from us, so fake it. */
3905 cr = crdup(get_current_cred());
3906 memset((char *)cr, 0, sizeof(cred_t));
3907 #if CELL || CELL_PREPARE
3915 * VIOC_GETRXKCRYPT (55) - Get rxkad encryption flag
3919 * \param[in] ain not in use
3920 * \param[out] aout value of cryptall
3922 * \post get the value of cryptall (presumably whether or not things should be encrypted)
3924 DECL_PIOCTL(PGetRxkcrypt)
3926 memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3927 *aoutSize = sizeof(afs_int32);
3932 * VIOC_SETRXKCRYPT (56) - Set rxkad encryption flag
3936 * \param[in] ain the argument whether or not things should be encrypted
3937 * \param[out] aout not in use
3939 * \retval EPERM Error if the user doesn't have super-user credentials
3940 * \retval EINVAL Error if the input is too big, or if the input is outside the bounds of what it can be set to
3942 * \post set whether or not things should be encrypted
3944 * \notes may need to be modified at a later date to take into account other values for cryptall (beyond true or false)
3946 DECL_PIOCTL(PSetRxkcrypt)
3950 if (!afs_osi_suser(*acred))
3952 if (ainSize != sizeof(afs_int32) || ain == NULL)
3954 memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3955 /* if new mappings added later this will need to be changed */
3956 if (tmpval != 0 && tmpval != 1)
3962 #ifdef AFS_NEED_CLIENTCONTEXT
3964 * Create new credentials to correspond to a remote user with given
3965 * <hostaddr, uid, g0, g1>. This allows a server running as root to
3966 * provide pioctl (and other) services to foreign clients (i.e. nfs
3967 * clients) by using this call to `become' the client.
3970 #define PIOCTL_HEADER 6
3972 HandleClientContext(struct afs_ioctl *ablob, int *com,
3973 AFS_UCRED **acred, struct AFS_UCRED *credp)
3976 afs_uint32 hostaddr;
3977 afs_int32 uid, g0, g1, i, code, pag, exporter_type, isroot = 0;
3978 struct afs_exporter *exporter, *outexporter;
3980 struct unixuser *au;
3981 afs_uint32 comp = *com & 0xff00;
3984 #if defined(AFS_SGIMP_ENV)
3985 osi_Assert(ISAFS_GLOCK());
3987 AFS_STATCNT(HandleClientContext);
3988 if (ablob->in_size < PIOCTL_HEADER * sizeof(afs_int32)) {
3989 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3990 return EINVAL; /* Too small to be good */
3992 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3993 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER * sizeof(afs_int32), code);
3995 osi_FreeLargeSpace(inData);
3999 /* Extract information for remote user */
4000 hostaddr = *((afs_uint32 *) ain);
4001 ain += sizeof(hostaddr);
4002 uid = *((afs_uint32 *) ain);
4004 g0 = *((afs_uint32 *) ain);
4006 g1 = *((afs_uint32 *) ain);
4008 *com = *((afs_uint32 *) ain);
4009 ain += sizeof(afs_int32);
4010 exporter_type = *((afs_uint32 *) ain); /* In case we support more than NFS */
4013 * Of course, one must be root for most of these functions, but
4014 * we'll allow (for knfs) you to set things if the pag is 0 and
4015 * you're setting tokens or unlogging.
4018 if (!afs_osi_suser(credp)) {
4019 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI64_ENV)
4020 /* Since SGI's suser() returns explicit failure after the call.. */
4023 /* check for acceptable opcodes for normal folks, which are, so far,
4024 * get/set tokens, sysname, and unlog.
4026 if (i != 9 && i != 3 && i != 38 && i != 8) {
4027 osi_FreeLargeSpace(inData);
4032 ablob->in_size -= PIOCTL_HEADER * sizeof(afs_int32);
4033 ablob->in += PIOCTL_HEADER * sizeof(afs_int32);
4034 osi_FreeLargeSpace(inData);
4037 * We map uid 0 to nobody to match the mapping that the nfs
4038 * server does and to ensure that the suser() calls in the afs
4039 * code fails for remote client roots.
4041 uid = afs_nobody; /* NFS_NOBODY == -2 */
4045 #ifdef AFS_AIX41_ENV
4048 newcred->cr_gid = isroot ? RMTUSER_REQ_PRIV : RMTUSER_REQ;
4049 #ifdef AFS_AIX51_ENV
4050 newcred->cr_groupset.gs_union.un_groups[0] = g0;
4051 newcred->cr_groupset.gs_union.un_groups[1] = g1;
4052 #elif defined(AFS_LINUX26_ENV)
4053 #ifdef AFS_LINUX26_ONEGROUP_ENV
4054 newcred->cr_group_info = groups_alloc(1); /* not that anything sets this */
4055 l = (((g0-0x3f00) & 0x3fff) << 14) | ((g1-0x3f00) & 0x3fff);
4056 h = ((g0-0x3f00) >> 14);
4057 h = ((g1-0x3f00) >> 14) + h + h + h;
4058 GROUP_AT(newcred->cr_group_info, 0) = ((h << 28) | l);
4060 newcred->cr_group_info = groups_alloc(2);
4061 GROUP_AT(newcred->cr_group_info, 0) = g0;
4062 GROUP_AT(newcred->cr_group_info, 1) = g1;
4065 newcred->cr_groups[0] = g0;
4066 newcred->cr_groups[1] = g1;
4069 newcred->cr_ngrps = 2;
4070 #elif !defined(AFS_LINUX26_ENV)
4071 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
4072 newcred->cr_ngroups = 2;
4074 for (i = 2; i < NGROUPS; i++)
4075 newcred->cr_groups[i] = NOGROUP;
4078 #if !defined(AFS_OSF_ENV)
4079 afs_nfsclient_init(); /* before looking for exporter, ensure one exists */
4081 if (!(exporter = exporter_find(exporter_type))) {
4082 /* Exporter wasn't initialized or an invalid exporter type */
4086 if (exporter->exp_states & EXP_PWSYNC) {
4087 if (uid != credp->cr_uid) {
4089 return ENOEXEC; /* XXX Find a better errno XXX */
4092 newcred->cr_uid = uid; /* Only temporary */
4093 code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
4094 /* The client's pag is the only unique identifier for it */
4095 newcred->cr_uid = pag;
4097 if (!code && *com == PSETPAG) {
4098 /* Special case for 'setpag' */
4099 afs_uint32 pagvalue = genpag();
4101 au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
4103 * Note that we leave the 'outexporter' struct held so it won't
4106 au->exporter = outexporter;
4107 if (ablob->out_size >= 4) {
4108 AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32),
4111 afs_PutUser(au, WRITE_LOCK);
4114 return PSETPAG; /* Special return for setpag */
4116 EXP_RELE(outexporter);
4119 *com = (*com) | comp;
4122 #endif /* AFS_NEED_CLIENTCONTEXT */
4126 * VIOC_GETCPREFS (50) - Get client interface
4130 * \param[in] ain sprefrequest input
4131 * \param[out] aout spref information
4133 * \retval EIO Error if the afs daemon hasn't started yet
4134 * \retval EINVAL Error if some of the standard args aren't set
4136 * \post get all interface addresses and other information of the client interface
4138 DECL_PIOCTL(PGetCPrefs)
4140 struct sprefrequest *spin; /* input */
4141 struct sprefinfo *spout; /* output */
4142 struct spref *srvout; /* one output component */
4146 AFS_STATCNT(PGetCPrefs);
4147 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4148 return EIO; /* Inappropriate ioctl for device */
4150 if (ainSize < sizeof(struct sprefrequest))
4153 spin = (struct sprefrequest *)ain;
4154 spout = (struct sprefinfo *)aout;
4156 maxNumber = spin->num_servers; /* max addrs this time */
4157 srvout = spout->servers;
4159 ObtainReadLock(&afs_xinterface);
4161 /* copy out the client interface information from the
4162 ** kernel data structure "interface" to the output buffer
4164 for (i = spin->offset, j = 0; (i < afs_cb_interface.numberOfInterfaces)
4165 && (j < maxNumber); i++, j++, srvout++)
4166 srvout->host.s_addr = afs_cb_interface.addr_in[i];
4168 spout->num_servers = j;
4169 *aoutSize = sizeof(struct sprefinfo) + (j - 1) * sizeof(struct spref);
4171 if (i >= afs_cb_interface.numberOfInterfaces)
4172 spout->next_offset = 0; /* start from beginning again */
4174 spout->next_offset = spin->offset + j;
4176 ReleaseReadLock(&afs_xinterface);
4181 * VIOC_SETCPREFS (51) - Set client interface
4185 * \param[in] ain the interfaces you want set
4186 * \param[out] aout not in use
4188 * \retval EIO Error if the afs daemon hasn't started yet
4189 * \retval EINVAL Error if the input is too large for the struct
4190 * \retval ENOMEM Error if there are too many servers
4192 * \post set the callbak interfaces addresses to those of the hosts
4194 DECL_PIOCTL(PSetCPrefs)
4196 struct setspref *sin;
4199 AFS_STATCNT(PSetCPrefs);
4200 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4201 return EIO; /* Inappropriate ioctl for device */
4203 sin = (struct setspref *)ain;
4205 if (ainSize < sizeof(struct setspref))
4207 #if 0 /* num_servers is unsigned */
4208 if (sin->num_servers < 0)
4211 if (sin->num_servers > AFS_MAX_INTERFACE_ADDR)
4214 ObtainWriteLock(&afs_xinterface, 412);
4215 afs_cb_interface.numberOfInterfaces = sin->num_servers;
4216 for (i = 0; (unsigned short)i < sin->num_servers; i++)
4217 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
4219 ReleaseWriteLock(&afs_xinterface);
4224 * VIOC_AFS_FLUSHMOUNT (52) - Flush mount symlink data
4228 * \param[in] ain the last part of a path to a mount point, which tells us what to flush
4229 * \param[out] aout not in use
4231 * \retval EINVAL Error if some of the initial arguments aren't set
4232 * \retval ENOTDIR Error if the initial argument for the mount point isn't a directory
4233 * \retval ENOENT Error if the dcache entry isn't set
4235 * \post remove all of the mount data from the dcache regarding a certain mount point
4237 DECL_PIOCTL(PFlushMount)
4239 register afs_int32 code;
4240 register struct vcache *tvc;
4241 register struct dcache *tdc;
4242 struct VenusFid tfid;
4244 struct sysname_info sysState;
4245 afs_size_t offset, len;
4247 AFS_STATCNT(PFlushMount);
4250 code = afs_VerifyVCache(avc, areq);
4253 if (vType(avc) != VDIR) {
4256 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
4259 Check_AtSys(avc, ain, &sysState, areq);
4260 ObtainReadLock(&tdc->lock);
4262 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
4263 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
4264 ReleaseReadLock(&tdc->lock);
4265 afs_PutDCache(tdc); /* we're done with the data */
4266 bufp = sysState.name;
4270 tfid.Cell = avc->f.fid.Cell;
4271 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
4272 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
4273 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
4275 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4281 if (tvc->mvstat != 1) {
4286 #ifdef AFS_BOZONLOCK_ENV
4287 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
4289 ObtainWriteLock(&tvc->lock, 649);
4290 ObtainWriteLock(&afs_xcbhash, 650);
4291 afs_DequeueCallback(tvc);
4292 tvc->f.states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
4293 ReleaseWriteLock(&afs_xcbhash);
4294 /* now find the disk cache entries */
4295 afs_TryToSmush(tvc, *acred, 1);
4296 osi_dnlc_purgedp(tvc);
4297 if (tvc->linkData && !(tvc->f.states & CCore)) {
4298 afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
4299 tvc->linkData = NULL;
4301 ReleaseWriteLock(&tvc->lock);
4302 #ifdef AFS_BOZONLOCK_ENV
4303 afs_BozonUnlock(&tvc->pvnLock, tvc);
4307 if (sysState.allocked)
4308 osi_FreeLargeSpace(bufp);
4313 * VIOC_RXSTAT_PROC (53) - Control process RX statistics
4317 * \param[in] ain the flags that control which stats to use
4318 * \param[out] aout not in use
4320 * \retval EACCES Error if the user doesn't have super-user credentials
4321 * \retval EINVAL Error if the flag input is too long
4323 * \post either enable process RPCStats, disable process RPCStats, or clear the process RPCStats
4325 DECL_PIOCTL(PRxStatProc)
4330 if (!afs_osi_suser(*acred)) {
4334 if (ainSize != sizeof(afs_int32)) {
4338 memcpy((char *)&flags, ain, sizeof(afs_int32));
4339 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4343 if (flags & AFSCALL_RXSTATS_ENABLE) {
4344 rx_enableProcessRPCStats();
4346 if (flags & AFSCALL_RXSTATS_DISABLE) {
4347 rx_disableProcessRPCStats();
4349 if (flags & AFSCALL_RXSTATS_CLEAR) {
4350 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
4359 * VIOC_RXSTAT_PEER (54) - Control peer RX statistics
4363 * \param[in] ain the flags that control which statistics to use
4364 * \param[out] aout not in use
4366 * \retval EACCES Error if the user doesn't have super-user credentials
4367 * \retval EINVAL Error if the flag input is too long
4369 * \post either enable peer RPCStatws, disable peer RPCStats, or clear the peer RPCStats
4371 DECL_PIOCTL(PRxStatPeer)
4376 if (!afs_osi_suser(*acred)) {
4380 if (ainSize != sizeof(afs_int32)) {
4384 memcpy((char *)&flags, ain, sizeof(afs_int32));
4385 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4389 if (flags & AFSCALL_RXSTATS_ENABLE) {
4390 rx_enablePeerRPCStats();
4392 if (flags & AFSCALL_RXSTATS_DISABLE) {
4393 rx_disablePeerRPCStats();
4395 if (flags & AFSCALL_RXSTATS_CLEAR) {
4396 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
4403 DECL_PIOCTL(PPrefetchFromTape)
4405 register afs_int32 code, code1;
4407 struct afs_conn *tc;
4408 struct rx_call *tcall;
4409 struct AFSVolSync tsync;
4410 struct AFSFetchStatus OutStatus;
4411 struct AFSCallBack CallBack;
4412 struct VenusFid tfid;
4416 AFS_STATCNT(PSetAcl);
4420 if (ain && (ainSize == 3 * sizeof(afs_int32)))
4421 Fid = (struct AFSFid *)ain;
4423 Fid = &avc->f.fid.Fid;
4424 tfid.Cell = avc->f.fid.Cell;
4425 tfid.Fid.Volume = Fid->Volume;
4426 tfid.Fid.Vnode = Fid->Vnode;
4427 tfid.Fid.Unique = Fid->Unique;
4429 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4431 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4432 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &avc->f.fid);
4435 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4436 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &tvc->f.fid);
4439 tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
4443 tcall = rx_NewCall(tc->id);
4445 StartRXAFS_FetchData(tcall, (struct AFSFid *)&tvc->f.fid.Fid, 0,
4448 bytes = rx_Read(tcall, (char *)aout, sizeof(afs_int32));
4450 EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
4452 code1 = rx_EndCall(tcall, code);
4456 } while (afs_Analyze
4457 (tc, code, &tvc->f.fid, areq, AFS_STATS_FS_RPCIDX_RESIDENCYRPCS,
4458 SHARED_LOCK, NULL));
4459 /* This call is done only to have the callback things handled correctly */
4460 afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
4464 *aoutSize = sizeof(afs_int32);
4471 register afs_int32 code;
4472 struct afs_conn *tc;
4474 struct FsCmdInputs *Inputs;
4475 struct FsCmdOutputs *Outputs;
4476 struct VenusFid tfid;
4479 Inputs = (struct FsCmdInputs *)ain;
4480 Outputs = (struct FsCmdOutputs *)aout;
4483 if (!ain || ainSize != sizeof(struct FsCmdInputs))
4488 Fid = &avc->f.fid.Fid;
4490 tfid.Cell = avc->f.fid.Cell;
4491 tfid.Fid.Volume = Fid->Volume;
4492 tfid.Fid.Vnode = Fid->Vnode;
4493 tfid.Fid.Unique = Fid->Unique;
4495 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4496 afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD, ICL_TYPE_POINTER, tvc,
4497 ICL_TYPE_INT32, Inputs->command, ICL_TYPE_FID, &tfid);
4501 if (Inputs->command) {
4503 tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
4507 RXAFS_FsCmd(tc->id, Fid, Inputs,
4508 (struct FsCmdOutputs *)aout);
4512 } while (afs_Analyze
4513 (tc, code, &tvc->f.fid, areq,
4514 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK, NULL));
4515 /* This call is done to have the callback things handled correctly */
4516 afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4517 } else { /* just a status request, return also link data */
4519 Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4520 Outputs->chars[0] = 0;
4521 if (vType(tvc) == VLNK) {
4522 ObtainWriteLock(&tvc->lock, 555);
4523 if (afs_HandleLink(tvc, areq) == 0)
4524 strncpy((char *)&Outputs->chars, tvc->linkData, MAXCMDCHARS);
4525 ReleaseWriteLock(&tvc->lock);
4532 *aoutSize = sizeof(struct FsCmdOutputs);
4537 DECL_PIOCTL(PNewUuid)
4539 /*AFS_STATCNT(PNewUuid); */
4540 if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4541 return EIO; /* Inappropriate ioctl for device */
4543 if (!afs_osi_suser(acred))
4546 ObtainWriteLock(&afs_xinterface, 555);
4547 afs_uuid_create(&afs_cb_interface.uuid);
4548 ReleaseWriteLock(&afs_xinterface);
4549 ForceAllNewConnections();
4553 #if defined(AFS_CACHE_BYPASS)
4555 DECL_PIOCTL(PSetCachingThreshold)
4560 setting = getting = 1;
4562 if (ain == NULL || ainSize < sizeof(afs_int32))
4568 if (setting == 0 && getting == 0)
4572 * If setting, set first, and return the value now in effect
4575 afs_int32 threshold;
4577 if (!afs_osi_suser(*acred))
4579 memcpy((char *)&threshold, ain, sizeof(afs_int32));
4580 cache_bypass_threshold = threshold;
4581 afs_warn("Cache Bypass Threshold set to: %d\n", threshold);
4582 /* TODO: move to separate pioctl, or enhance pioctl */
4583 cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
4587 /* Return the current size threshold */
4588 afs_int32 oldThreshold = cache_bypass_threshold;
4589 memcpy(aout, (char *)&oldThreshold, sizeof(afs_int32));
4590 *aoutSize = sizeof(afs_int32);
4596 #endif /* defined(AFS_CACHE_BYPASS) */
4598 DECL_PIOCTL(PCallBackAddr)
4601 afs_uint32 addr, code;
4605 struct afs_conn *tc;
4607 struct unixuser *tu;
4608 struct srvAddr **addrs;
4610 /*AFS_STATCNT(PCallBackAddr); */
4611 if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4612 return EIO; /* Inappropriate ioctl for device */
4614 if (!afs_osi_suser(acred))
4617 if (ainSize < sizeof(afs_int32))
4620 memcpy(&addr, ain, sizeof(afs_int32));
4622 ObtainReadLock(&afs_xinterface);
4623 for (i = 0; (unsigned short)i < afs_cb_interface.numberOfInterfaces; i++) {
4624 if (afs_cb_interface.addr_in[i] == addr)
4628 ReleaseWriteLock(&afs_xinterface);
4630 if (afs_cb_interface.addr_in[i] != addr)
4633 ObtainReadLock(&afs_xserver); /* Necessary? */
4634 ObtainReadLock(&afs_xsrvAddr);
4637 for (i = 0; i < NSERVERS; i++) {
4638 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4643 addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
4645 for (i = 0; i < NSERVERS; i++) {
4646 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4647 if (j >= srvAddrCount)
4653 ReleaseReadLock(&afs_xsrvAddr);
4654 ReleaseReadLock(&afs_xserver);
4656 for (i = 0; i < j; i++) {
4662 /* vlserver has no callback conn */
4663 if (sa->sa_portal == AFS_VLPORT) {
4667 if (!ts->cell) /* not really an active server, anyway, it must */
4668 continue; /* have just been added by setsprefs */
4670 /* get a connection, even if host is down; bumps conn ref count */
4671 tu = afs_GetUser(areq->uid, ts->cell->cellNum, SHARED_LOCK);
4672 tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
4673 1 /*force */ , 1 /*create */ , SHARED_LOCK);
4674 afs_PutUser(tu, SHARED_LOCK);
4678 if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(ts)) {
4679 if (sa->sa_flags & SRVADDR_ISDOWN) {
4680 rx_SetConnDeadTime(tc->id, 3);
4682 #ifdef RX_ENABLE_LOCKS
4684 #endif /* RX_ENABLE_LOCKS */
4685 code = RXAFS_CallBackRxConnAddr(tc->id, &addr);
4686 #ifdef RX_ENABLE_LOCKS
4688 #endif /* RX_ENABLE_LOCKS */
4690 afs_PutConn(tc, SHARED_LOCK); /* done with it now */
4691 } /* Outer loop over addrs */
4692 #endif /* UKERNEL */
4696 DECL_PIOCTL(PDiscon)
4698 #ifdef AFS_DISCON_ENV
4699 static afs_int32 mode = 1; /* Start up in 'off' */
4700 afs_int32 force = 0;
4705 if (!afs_osi_suser(*acred))
4711 afs_ConflictPolicy = ain[1] - 1;
4716 * All of these numbers are hard coded in fs.c. If they
4717 * change here, they should change there and vice versa
4720 case 0: /* Disconnect ("offline" mode), breaking all callbacks */
4721 if (!AFS_IS_DISCONNECTED) {
4722 ObtainWriteLock(&afs_discon_lock, 999);
4723 afs_DisconGiveUpCallbacks();
4724 afs_RemoveAllConns();
4725 afs_is_disconnected = 1;
4726 afs_is_discon_rw = 1;
4727 ReleaseWriteLock(&afs_discon_lock);
4730 case 1: /* Fully connected, ("online" mode). */
4731 ObtainWriteLock(&afs_discon_lock, 998);
4734 afs_MarkAllServersUp();
4735 code = afs_ResyncDisconFiles(areq, *acred);
4738 if (code && !force) {
4739 printf("Files not synchronized properly, still in discon state. \n"
4740 "Please retry or use \"force\".\n");
4744 afs_DisconDiscardAll(*acred);
4746 afs_ClearAllStatdFlag();
4747 afs_is_disconnected = 0;
4748 afs_is_discon_rw = 0;
4749 printf("\nSync succeeded. You are back online.\n");
4752 ReleaseWriteLock(&afs_discon_lock);
4761 memcpy(aout, &mode, sizeof(afs_int32));
4762 *aoutSize = sizeof(afs_int32);
4769 DECL_PIOCTL(PNFSNukeCreds)
4772 register afs_int32 i;
4773 register struct unixuser *tu;
4775 AFS_STATCNT(PUnlog);
4776 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4777 return EIO; /* Inappropriate ioctl for device */
4779 if (ainSize < sizeof(afs_int32))
4781 memcpy(&addr, ain, sizeof(afs_int32));
4783 if ((*acred)->cr_gid == RMTUSER_REQ_PRIV && !addr) {
4784 tu = afs_GetUser(areq->uid, -1, SHARED_LOCK);
4785 if (!tu->exporter || !(addr = EXP_GETHOST(tu->exporter))) {
4786 afs_PutUser(tu, SHARED_LOCK);
4789 afs_PutUser(tu, SHARED_LOCK);
4790 } else if (!afs_osi_suser(acred)) {
4794 ObtainWriteLock(&afs_xuser, 227);
4795 for (i = 0; i < NUSERS; i++) {
4796 for (tu = afs_users[i]; tu; tu = tu->next) {
4797 if (tu->exporter && EXP_CHECKHOST(tu->exporter, addr)) {
4799 tu->states &= ~UHasTokens;
4800 /* security is not having to say you're sorry */
4801 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
4803 ReleaseWriteLock(&afs_xuser);
4804 afs_ResetUserConns(tu);
4806 ObtainWriteLock(&afs_xuser, 228);
4808 /* set the expire times to 0, causes
4809 * afs_GCUserData to remove this entry
4811 tu->ct.EndTimestamp = 0;
4813 #endif /* UKERNEL */
4817 ReleaseWriteLock(&afs_xuser);