2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include "afs/param.h"
16 #include "afs/sysincludes.h" /* Standard vendor system headers */
18 #include "h/syscallargs.h"
21 #include "h/sysproto.h"
23 #include "afsincludes.h" /* Afs-based standard headers */
24 #include "afs/afs_stats.h" /* afs statistics */
26 #include "afs/afs_bypasscache.h"
27 #include "rx/rx_globals.h"
29 struct VenusFid afs_rootFid;
30 afs_int32 afs_waitForever = 0;
31 short afs_waitForeverCount = 0;
32 afs_int32 afs_showflags = GAGUSER | GAGCONSOLE; /* show all messages */
35 afs_int32 afs_is_disconnected;
36 afs_int32 afs_is_discon_rw;
37 /* On reconnection, turn this knob on until it finishes,
40 afs_int32 afs_in_sync = 0;
44 * \defgroup pioctl Path IOCTL functions
46 * DECL_PIOCTL is a macro defined to contain the following parameters for functions:
48 * \param[in] avc the AFS vcache structure in use by pioctl
49 * \param[in] afun not in use
50 * \param[in] areq the AFS vrequest structure
51 * \param[in] ain as defined by the function
52 * \param[in] aout as defined by the function
53 * \param[in] ainSize size of ain
54 * \param[in] aoutSize size of aout
55 * \param[in] acred UNIX credentials structure underlying the operation
58 #define DECL_PIOCTL(x) static int x(struct vcache *avc, int afun, struct vrequest *areq, \
59 char *ain, char *aout, afs_int32 ainSize, afs_int32 *aoutSize, \
60 struct AFS_UCRED **acred)
62 /* Prototypes for pioctl routines */
65 DECL_PIOCTL(PStoreBehind);
70 DECL_PIOCTL(PGetFileCell);
71 DECL_PIOCTL(PGetWSCell);
72 DECL_PIOCTL(PGetUserCell);
73 DECL_PIOCTL(PSetTokens);
74 DECL_PIOCTL(PGetVolumeStatus);
75 DECL_PIOCTL(PSetVolumeStatus);
77 DECL_PIOCTL(PNewStatMount);
78 DECL_PIOCTL(PGetTokens);
80 DECL_PIOCTL(PMariner);
81 DECL_PIOCTL(PCheckServers);
82 DECL_PIOCTL(PCheckVolNames);
83 DECL_PIOCTL(PCheckAuth);
84 DECL_PIOCTL(PFindVolume);
85 DECL_PIOCTL(PViceAccess);
86 DECL_PIOCTL(PSetCacheSize);
87 DECL_PIOCTL(PGetCacheSize);
88 DECL_PIOCTL(PRemoveCallBack);
89 DECL_PIOCTL(PNewCell);
90 DECL_PIOCTL(PNewAlias);
91 DECL_PIOCTL(PListCells);
92 DECL_PIOCTL(PListAliases);
93 DECL_PIOCTL(PRemoveMount);
94 DECL_PIOCTL(PVenusLogging);
95 DECL_PIOCTL(PGetCellStatus);
96 DECL_PIOCTL(PSetCellStatus);
97 DECL_PIOCTL(PFlushVolumeData);
98 DECL_PIOCTL(PGetVnodeXStatus);
99 DECL_PIOCTL(PGetVnodeXStatus2);
100 DECL_PIOCTL(PSetSysName);
101 DECL_PIOCTL(PSetSPrefs);
102 DECL_PIOCTL(PSetSPrefs33);
103 DECL_PIOCTL(PGetSPrefs);
104 DECL_PIOCTL(PExportAfs);
106 DECL_PIOCTL(PTwiddleRx);
107 DECL_PIOCTL(PGetInitParams);
108 DECL_PIOCTL(PGetRxkcrypt);
109 DECL_PIOCTL(PSetRxkcrypt);
110 DECL_PIOCTL(PGetCPrefs);
111 DECL_PIOCTL(PSetCPrefs);
112 DECL_PIOCTL(PFlushMount);
113 DECL_PIOCTL(PRxStatProc);
114 DECL_PIOCTL(PRxStatPeer);
115 DECL_PIOCTL(PPrefetchFromTape);
117 DECL_PIOCTL(PCallBackAddr);
118 DECL_PIOCTL(PDiscon);
119 DECL_PIOCTL(PNFSNukeCreds);
120 DECL_PIOCTL(PNewUuid);
121 DECL_PIOCTL(PPrecache);
122 DECL_PIOCTL(PGetPAG);
123 #if defined(AFS_CACHE_BYPASS)
124 DECL_PIOCTL(PSetCachingThreshold);
125 DECL_PIOCTL(PSetCachingBlkSize);
129 * A macro that says whether we're going to need HandleClientContext().
130 * This is currently used only by the nfs translator.
132 #if !defined(AFS_NONFSTRANS) || defined(AFS_AIX_IAUTH_ENV)
133 #define AFS_NEED_CLIENTCONTEXT
136 /* Prototypes for private routines */
137 #ifdef AFS_NEED_CLIENTCONTEXT
138 static int HandleClientContext(struct afs_ioctl *ablob, int *com,
139 struct AFS_UCRED **acred,
140 struct AFS_UCRED *credp);
142 int HandleIoctl(register struct vcache *avc, register afs_int32 acom,
143 struct afs_ioctl *adata);
144 int afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
145 register struct afs_ioctl *ablob, int afollow,
146 struct AFS_UCRED **acred);
147 static int Prefetch(char *apath, struct afs_ioctl *adata, int afollow,
148 struct AFS_UCRED *acred);
150 typedef int (*pioctlFunction) (struct vcache *, int, struct vrequest *,
151 char *, char *, afs_int32, afs_int32 *,
152 struct AFS_UCRED **);
154 static pioctlFunction VpioctlSw[] = {
159 PGetVolumeStatus, /* 4 */
160 PSetVolumeStatus, /* 5 */
165 PCheckServers, /* 10 */
166 PCheckVolNames, /* 11 */
168 PBogus, /* 13 -- used to be quick check time */
169 PFindVolume, /* 14 */
170 PBogus, /* 15 -- prefetch is now special-cased; see pioctl code! */
171 PBogus, /* 16 -- used to be testing code */
172 PNoop, /* 17 -- used to be enable group */
173 PNoop, /* 18 -- used to be disable group */
174 PBogus, /* 19 -- used to be list group */
175 PViceAccess, /* 20 */
176 PUnlog, /* 21 -- unlog *is* unpag in this system */
177 PGetFID, /* 22 -- get file ID */
178 PBogus, /* 23 -- used to be waitforever */
179 PSetCacheSize, /* 24 */
180 PRemoveCallBack, /* 25 -- flush only the callback */
183 PRemoveMount, /* 28 -- delete mount point */
184 PNewStatMount, /* 29 -- new style mount point stat */
185 PGetFileCell, /* 30 -- get cell name for input file */
186 PGetWSCell, /* 31 -- get cell name for workstation */
187 PMariner, /* 32 - set/get mariner host */
188 PGetUserCell, /* 33 -- get cell name for user */
189 PVenusLogging, /* 34 -- Enable/Disable logging */
190 PGetCellStatus, /* 35 */
191 PSetCellStatus, /* 36 */
192 PFlushVolumeData, /* 37 -- flush all data from a volume */
193 PSetSysName, /* 38 - Set system name */
194 PExportAfs, /* 39 - Export Afs to remote nfs clients */
195 PGetCacheSize, /* 40 - get cache size and usage */
196 PGetVnodeXStatus, /* 41 - get vcache's special status */
197 PSetSPrefs33, /* 42 - Set CM Server preferences... */
198 PGetSPrefs, /* 43 - Get CM Server preferences... */
199 PGag, /* 44 - turn off/on all CM messages */
200 PTwiddleRx, /* 45 - adjust some RX params */
201 PSetSPrefs, /* 46 - Set CM Server preferences... */
202 PStoreBehind, /* 47 - set degree of store behind to be done */
203 PGCPAGs, /* 48 - disable automatic pag gc-ing */
204 PGetInitParams, /* 49 - get initial cm params */
205 PGetCPrefs, /* 50 - get client interface addresses */
206 PSetCPrefs, /* 51 - set client interface addresses */
207 PFlushMount, /* 52 - flush mount symlink data */
208 PRxStatProc, /* 53 - control process RX statistics */
209 PRxStatPeer, /* 54 - control peer RX statistics */
210 PGetRxkcrypt, /* 55 -- Get rxkad encryption flag */
211 PSetRxkcrypt, /* 56 -- Set rxkad encryption flag */
212 PBogus, /* 57 -- arla: set file prio */
213 PBogus, /* 58 -- arla: fallback getfh */
214 PBogus, /* 59 -- arla: fallback fhopen */
215 PBogus, /* 60 -- arla: controls xfsdebug */
216 PBogus, /* 61 -- arla: controls arla debug */
217 PBogus, /* 62 -- arla: debug interface */
218 PBogus, /* 63 -- arla: print xfs status */
219 PBogus, /* 64 -- arla: force cache check */
220 PBogus, /* 65 -- arla: break callback */
221 PPrefetchFromTape, /* 66 -- MR-AFS: prefetch file from tape */
222 PFsCmd, /* 67 -- RXOSD: generic commnd interface */
223 PBogus, /* 68 -- arla: fetch stats */
224 PGetVnodeXStatus2, /* 69 - get caller access and some vcache status */
227 static pioctlFunction CpioctlSw[] = {
229 PNewAlias, /* 1 -- create new cell alias */
230 PListAliases, /* 2 -- list cell aliases */
231 PCallBackAddr, /* 3 -- request addr for callback rxcon */
233 PDiscon, /* 5 -- get/set discon mode */
244 static int (*(OpioctlSw[])) () = {
246 PNFSNukeCreds, /* 1 -- nuke all creds for NFS client */
247 #if defined(AFS_CACHE_BYPASS)
248 PSetCachingThreshold /* 2 -- get/set cache-bypass size threshold */
250 PNoop /* 2 -- get/set cache-bypass size threshold */
254 #define PSetClientContext 99 /* Special pioctl to setup caller's creds */
255 int afs_nobody = NFS_NOBODY;
258 HandleIoctl(register struct vcache *avc, register afs_int32 acom,
259 struct afs_ioctl *adata)
261 register afs_int32 code;
264 AFS_STATCNT(HandleIoctl);
266 switch (acom & 0xff) {
268 avc->f.states |= CSafeStore;
270 /* SXW - Should we force a MetaData flush for this flag setting */
273 /* case 2 used to be abort store, but this is no longer provided,
274 * since it is impossible to implement under normal Unix.
278 /* return the name of the cell this file is open on */
279 register struct cell *tcell;
280 register afs_int32 i;
282 tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
284 i = strlen(tcell->cellName) + 1; /* bytes to copy out */
286 if (i > adata->out_size) {
287 /* 0 means we're not interested in the output */
288 if (adata->out_size != 0)
292 AFS_COPYOUT(tcell->cellName, adata->out, i, code);
294 afs_PutCell(tcell, READ_LOCK);
300 case 49: /* VIOC_GETINITPARAMS */
301 if (adata->out_size < sizeof(struct cm_initparams)) {
304 AFS_COPYOUT(&cm_initParams, adata->out,
305 sizeof(struct cm_initparams), code);
317 return code; /* so far, none implemented */
322 /* For aix we don't temporarily bypass ioctl(2) but rather do our
323 * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
324 * is now called from afs_gn_ioctl.
327 afs_ioctl(struct vcache *tvc, int cmd, int arg)
329 struct afs_ioctl data;
332 AFS_STATCNT(afs_ioctl);
333 if (((cmd >> 8) & 0xff) == 'V') {
334 /* This is a VICEIOCTL call */
335 AFS_COPYIN(arg, (caddr_t) & data, sizeof(data), error);
338 error = HandleIoctl(tvc, cmd, &data);
341 /* No-op call; just return. */
345 #endif /* AFS_AIX_ENV */
347 #if defined(AFS_SGI_ENV)
348 afs_ioctl(OSI_VN_DECL(tvc), int cmd, void *arg, int flag, cred_t * cr,
351 , struct vopbd * vbds
355 struct afs_ioctl data;
361 AFS_STATCNT(afs_ioctl);
362 if (((cmd >> 8) & 0xff) == 'V') {
363 /* This is a VICEIOCTL call */
364 error = copyin_afs_ioctl(arg, &data);
367 locked = ISAFS_GLOCK();
370 error = HandleIoctl(tvc, cmd, &data);
375 /* No-op call; just return. */
379 #endif /* AFS_SGI_ENV */
381 /* unlike most calls here, this one uses u.u_error to return error conditions,
382 since this is really an intercepted chapter 2 call, rather than a vnode
385 /* AFS_HPUX102 and up uses VNODE ioctl instead */
386 #if !defined(AFS_HPUX102_ENV) && !defined(AFS_DARWIN80_ENV)
387 #if !defined(AFS_SGI_ENV)
392 kioctl(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
394 #else /* __64BIT__ */
396 kioctl32(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
398 #endif /* __64BIT__ */
401 kioctl(int fdes, int com, caddr_t arg, caddr_t ext)
410 } u_uap, *uap = &u_uap;
412 #if defined(AFS_SUN5_ENV)
414 struct afs_ioctl_sys {
421 afs_xioctl(struct afs_ioctl_sys *uap, rval_t *rvp)
423 #elif defined(AFS_OSF_ENV)
425 afs_xioctl(struct proc *p, void *args, long *retval)
431 } *uap = (struct a *)args;
432 #elif defined(AFS_FBSD50_ENV)
435 afs_xioctl(struct thread *td, register struct ioctl_args *uap,
438 struct proc *p = td->td_proc;
439 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
447 afs_xioctl(struct proc *p, register struct ioctl_args *uap, register_t *retval)
449 #elif defined(AFS_LINUX22_ENV)
450 struct afs_ioctl_sys {
455 afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
458 struct afs_ioctl_sys ua, *uap = &ua;
467 } *uap = (struct a *)u.u_ap;
468 #endif /* AFS_SUN5_ENV */
470 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
472 #elif !defined(AFS_LINUX22_ENV)
473 register struct file *fd;
475 #if defined(AFS_XBSD_ENV)
476 register struct filedesc *fdp;
478 register struct vcache *tvc;
479 register int ioctlDone = 0, code = 0;
481 AFS_STATCNT(afs_xioctl);
482 #if defined(AFS_DARWIN_ENV)
483 if ((code = fdgetf(p, uap->fd, &fd)))
485 #elif defined(AFS_XBSD_ENV)
487 if ((u_int) uap->fd >= fdp->fd_nfiles
488 || (fd = fdp->fd_ofiles[uap->fd]) == NULL)
490 if ((fd->f_flag & (FREAD | FWRITE)) == 0)
492 #elif defined(AFS_LINUX22_ENV)
495 #elif defined(AFS_AIX32_ENV)
503 if (setuerror(getf(uap->fd, &fd))) {
506 #elif defined(AFS_OSF_ENV)
508 if (code = getf(&fd, uap->fd, FILE_FLAGS_NULL, &u.u_file_state))
510 #elif defined(AFS_SUN5_ENV)
511 # if defined(AFS_SUN57_ENV)
515 # elif defined(AFS_SUN54_ENV)
520 if (code = getf(uap->fd, &fd)) {
523 # endif /* AFS_SUN57_ENV */
529 /* first determine whether this is any sort of vnode */
530 #if defined(AFS_LINUX22_ENV)
535 if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
537 if (fd->f_type == DTYPE_VNODE) {
539 /* good, this is a vnode; next see if it is an AFS vnode */
540 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
541 tvc = VTOAFS(fd->f_vnode); /* valid, given a vnode */
542 #elif defined(AFS_OBSD_ENV)
544 IsAfsVnode((struct vnode *)fd->
545 f_data) ? VTOAFS((struct vnode *)fd->f_data) : NULL;
547 tvc = VTOAFS((struct vnode *)fd->f_data); /* valid, given a vnode */
549 #endif /* AFS_LINUX22_ENV */
550 if (tvc && IsAfsVnode(AFSTOV(tvc))) {
551 /* This is an AFS vnode */
552 if (((uap->com >> 8) & 0xff) == 'V') {
553 register struct afs_ioctl *datap;
556 (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
557 code=copyin_afs_ioctl((char *)uap->arg, datap);
559 osi_FreeSmallSpace(datap);
561 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
564 #if defined(AFS_SUN5_ENV)
579 #else /* AFS_OSF_ENV */
583 #ifdef AFS_LINUX22_ENV
586 return (setuerror(code), code);
592 code = HandleIoctl(tvc, uap->com, datap);
593 osi_FreeSmallSpace(datap);
607 #if defined(AFS_LINUX22_ENV)
619 code = okioctl(fdes, com, arg, ext, arg2, arg3);
620 #else /* __64BIT__ */
621 code = okioctl32(fdes, com, arg, ext, arg2, arg3);
622 #endif /* __64BIT__ */
623 #else /* !AFS_AIX51_ENV */
624 code = okioctl(fdes, com, arg, ext);
625 #endif /* AFS_AIX51_ENV */
627 #else /* !AFS_AIX41_ENV */
629 okioctl(fdes, com, arg, ext);
630 #elif defined(AFS_SUN5_ENV)
631 #if defined(AFS_SUN57_ENV)
633 #elif defined(AFS_SUN54_ENV)
638 code = ioctl(uap, rvp);
639 #elif defined(AFS_FBSD50_ENV)
640 return ioctl(td, uap);
641 #elif defined(AFS_FBSD_ENV)
642 return ioctl(p, uap);
643 #elif defined(AFS_OBSD_ENV)
644 code = sys_ioctl(p, uap, retval);
645 #elif defined(AFS_DARWIN_ENV)
646 return ioctl(p, uap, retval);
647 #elif defined(AFS_OSF_ENV)
648 code = ioctl(p, args, retval);
655 #elif !defined(AFS_LINUX22_ENV)
669 #ifdef AFS_LINUX22_ENV
672 #if defined(KERNEL_HAVE_UERROR)
675 #if defined(AFS_AIX32_ENV) && !defined(AFS_AIX41_ENV)
676 return (getuerror()? -1 : u.u_ioctlrv);
678 return getuerror()? -1 : 0;
681 #endif /* AFS_LINUX22_ENV */
682 #endif /* AFS_SUN5_ENV */
683 #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
687 #endif /* AFS_SGI_ENV */
688 #endif /* AFS_HPUX102_ENV */
690 #if defined(AFS_SGI_ENV)
691 /* "pioctl" system call entry point; just pass argument to the parameterized
700 afs_pioctl(struct pioctlargs *uap, rval_t * rvp)
704 AFS_STATCNT(afs_pioctl);
706 code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
715 #elif defined(AFS_OSF_ENV)
716 afs_pioctl(struct proc *p, void *args, int *retval)
723 } *uap = (struct a *)args;
725 AFS_STATCNT(afs_pioctl);
726 return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow));
729 #elif defined(AFS_FBSD50_ENV)
731 afs_pioctl(struct thread *td, void *args, int *retval)
738 } *uap = (struct a *)args;
740 AFS_STATCNT(afs_pioctl);
741 return (afs_syscall_pioctl
742 (uap->path, uap->cmd, uap->cmarg, uap->follow, td->td_ucred));
745 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
747 afs_pioctl(struct proc *p, void *args, int *retval)
754 } *uap = (struct a *)args;
756 AFS_STATCNT(afs_pioctl);
757 #ifdef AFS_DARWIN80_ENV
758 return (afs_syscall_pioctl
759 (uap->path, uap->cmd, uap->cmarg, uap->follow,
762 return (afs_syscall_pioctl
763 (uap->path, uap->cmd, uap->cmarg, uap->follow,
764 p->p_cred->pc_ucred));
770 /* macro to avoid adding any more #ifdef's to pioctl code. */
771 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
772 #define PIOCTL_FREE_CRED() crfree(credp)
774 #define PIOCTL_FREE_CRED()
779 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
780 rval_t *vvp, struct AFS_UCRED *credp)
782 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
783 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
784 struct AFS_UCRED *credp)
786 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
790 struct afs_ioctl data;
791 #ifdef AFS_NEED_CLIENTCONTEXT
792 struct AFS_UCRED *tmpcred = NULL;
794 struct AFS_UCRED *foreigncreds = NULL;
795 register afs_int32 code = 0;
796 struct vnode *vp = NULL;
798 struct ucred *credp = crref(); /* don't free until done! */
800 #ifdef AFS_LINUX22_ENV
801 cred_t *credp = crref(); /* don't free until done! */
805 AFS_STATCNT(afs_syscall_pioctl);
807 follow = 1; /* compat. with old venus */
808 code = copyin_afs_ioctl(cmarg, &data);
811 #if defined(KERNEL_HAVE_UERROR)
816 if ((com & 0xff) == PSetClientContext) {
817 #ifdef AFS_NEED_CLIENTCONTEXT
818 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
819 code = HandleClientContext(&data, &com, &foreigncreds, credp);
821 code = HandleClientContext(&data, &com, &foreigncreds, osi_curcred());
825 crfree(foreigncreds);
828 #if defined(KERNEL_HAVE_UERROR)
829 return (setuerror(code), code);
834 #else /* AFS_NEED_CLIENTCONTEXT */
836 #endif /* AFS_NEED_CLIENTCONTEXT */
838 #ifdef AFS_NEED_CLIENTCONTEXT
841 * We could have done without temporary setting the u.u_cred below
842 * (foreigncreds could be passed as param the pioctl modules)
843 * but calls such as afs_osi_suser() doesn't allow that since it
844 * references u.u_cred directly. We could, of course, do something
845 * like afs_osi_suser(cred) which, I think, is better since it
846 * generalizes and supports multi cred environments...
848 #if defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
850 credp = foreigncreds;
851 #elif defined(AFS_AIX41_ENV)
852 tmpcred = crref(); /* XXX */
854 #elif defined(AFS_HPUX101_ENV)
855 tmpcred = p_cred(u.u_procp);
856 set_p_cred(u.u_procp, foreigncreds);
857 #elif defined(AFS_SGI_ENV)
858 tmpcred = OSI_GET_CURRENT_CRED();
859 OSI_SET_CURRENT_CRED(foreigncreds);
862 u.u_cred = foreigncreds;
865 #endif /* AFS_NEED_CLIENTCONTEXT */
866 if ((com & 0xff) == 15) {
867 /* special case prefetch so entire pathname eval occurs in helper process.
868 * otherwise, the pioctl call is essentially useless */
869 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
871 Prefetch(path, &data, follow,
872 foreigncreds ? foreigncreds : credp);
874 code = Prefetch(path, &data, follow, osi_curcred());
877 #if defined(KERNEL_HAVE_UERROR)
886 lookupname(path, USR, follow, NULL, &vp,
887 foreigncreds ? foreigncreds : credp);
889 #ifdef AFS_LINUX22_ENV
890 code = gop_lookupname(path, AFS_UIOUSER, follow, &dp);
892 vp = (struct vnode *)dp->d_inode;
894 code = gop_lookupname(path, AFS_UIOUSER, follow, &vp);
895 #endif /* AFS_LINUX22_ENV */
896 #endif /* AFS_AIX41_ENV */
900 #if defined(KERNEL_HAVE_UERROR)
908 #if defined(AFS_SUN510_ENV)
909 if (vp && !IsAfsVnode(vp)) {
910 struct vnode *realvp;
912 #ifdef AFS_SUN511_ENV
913 (VOP_REALVP(vp, &realvp, NULL) == 0)
915 (VOP_REALVP(vp, &realvp) == 0)
918 struct vnode *oldvp = vp;
926 /* now make the call if we were passed no file, or were passed an AFS file */
927 if (!vp || IsAfsVnode(vp)) {
928 #if defined(AFS_SUN5_ENV)
929 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
930 #elif defined(AFS_AIX41_ENV)
932 struct ucred *cred1, *cred2;
935 cred1 = cred2 = foreigncreds;
937 cred1 = cred2 = credp;
939 code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
940 if (cred1 != cred2) {
941 /* something changed the creds */
945 #elif defined(AFS_HPUX101_ENV)
947 struct ucred *cred = p_cred(u.u_procp);
948 code = afs_HandlePioctl(vp, com, &data, follow, &cred);
950 #elif defined(AFS_SGI_ENV)
953 credp = OSI_GET_CURRENT_CRED();
954 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
956 #elif defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
957 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
959 code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
962 #if defined(KERNEL_HAVE_UERROR)
965 code = EINVAL; /* not in /afs */
970 #if defined(AFS_NEED_CLIENTCONTEXT)
973 crset(tmpcred); /* restore original credentials */
975 #if defined(AFS_HPUX101_ENV)
976 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
977 #elif defined(AFS_SGI_ENV)
978 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
979 #elif defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
980 credp = tmpcred; /* restore original credentials */
982 osi_curcred() = tmpcred; /* restore original credentials */
983 #endif /* AFS_HPUX101_ENV */
984 crfree(foreigncreds);
987 #endif /* AFS_NEED_CLIENTCONTEXT */
989 #ifdef AFS_LINUX22_ENV
992 AFS_RELE(vp); /* put vnode back */
996 #if defined(KERNEL_HAVE_UERROR)
999 return (getuerror());
1005 #define MAXPIOCTLTOKENLEN \
1006 (3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
1009 afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
1010 register struct afs_ioctl *ablob, int afollow,
1011 struct AFS_UCRED **acred)
1014 struct vrequest treq;
1015 register afs_int32 code;
1016 register afs_int32 function, device;
1017 afs_int32 inSize, outSize, outSizeMax;
1018 char *inData, *outData;
1019 pioctlFunction *pioctlSw;
1021 struct afs_fakestat_state fakestate;
1023 avc = avp ? VTOAFS(avp) : NULL;
1024 afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
1025 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
1026 AFS_STATCNT(HandlePioctl);
1027 if ((code = afs_InitReq(&treq, *acred)))
1029 afs_InitFakeStat(&fakestate);
1031 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
1033 afs_PutFakeStat(&fakestate);
1037 device = (acom & 0xff00) >> 8;
1039 case 'V': /* Original pioctls */
1040 pioctlSw = VpioctlSw;
1041 pioctlSwSize = sizeof(VpioctlSw);
1043 case 'C': /* Coordinated/common pioctls */
1044 pioctlSw = CpioctlSw;
1045 pioctlSwSize = sizeof(CpioctlSw);
1047 case 'O': /* Coordinated/common pioctls */
1048 pioctlSw = OpioctlSw;
1049 pioctlSwSize = sizeof(OpioctlSw);
1052 afs_PutFakeStat(&fakestate);
1055 function = acom & 0xff;
1056 if (function >= (pioctlSwSize / sizeof(char *))) {
1057 afs_PutFakeStat(&fakestate);
1058 return EINVAL; /* out of range */
1060 inSize = ablob->in_size;
1062 /* Do all range checking before continuing */
1063 if (inSize > MAXPIOCTLTOKENLEN || inSize < 0 || ablob->out_size < 0)
1066 /* Note that we use osi_Alloc for large allocs and osi_AllocLargeSpace for small ones */
1067 if (inSize > AFS_LRALLOCSIZ) {
1068 inData = osi_Alloc(inSize + 1);
1070 inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1075 AFS_COPYIN(ablob->in, inData, inSize, code);
1076 inData[inSize] = '\0';
1080 if (inSize > AFS_LRALLOCSIZ) {
1081 osi_Free(inData, inSize + 1);
1083 osi_FreeLargeSpace(inData);
1085 afs_PutFakeStat(&fakestate);
1088 if (function == 8 && device == 'V') { /* PGetTokens */
1089 outSizeMax = MAXPIOCTLTOKENLEN;
1090 outData = osi_Alloc(outSizeMax);
1092 outSizeMax = AFS_LRALLOCSIZ;
1093 outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1096 if (inSize > AFS_LRALLOCSIZ) {
1097 osi_Free(inData, inSize + 1);
1099 osi_FreeLargeSpace(inData);
1101 afs_PutFakeStat(&fakestate);
1106 (*pioctlSw[function]) (avc, function, &treq, inData, outData, inSize,
1108 if (inSize > AFS_LRALLOCSIZ) {
1109 osi_Free(inData, inSize + 1);
1111 osi_FreeLargeSpace(inData);
1113 if (code == 0 && ablob->out_size > 0) {
1114 if (outSize > ablob->out_size) {
1115 code = E2BIG; /* data wont fit in user buffer */
1116 } else if (outSize) {
1117 AFS_COPYOUT(outData, ablob->out, outSize, code);
1120 if (outSizeMax > AFS_LRALLOCSIZ) {
1121 osi_Free(outData, outSizeMax);
1123 osi_FreeLargeSpace(outData);
1125 afs_PutFakeStat(&fakestate);
1126 return afs_CheckCode(code, &treq, 41);
1130 * VIOCGETFID (22) - Get file ID quickly
1134 * \param[in] ain not in use
1135 * \param[out] aout fid of requested file
1137 * \retval EINVAL Error if some of the initial arguments aren't set
1139 * \post get the file id of some file
1141 DECL_PIOCTL(PGetFID)
1143 AFS_STATCNT(PGetFID);
1146 memcpy(aout, (char *)&avc->f.fid, sizeof(struct VenusFid));
1147 *aoutSize = sizeof(struct VenusFid);
1152 * VIOCSETAL (1) - Set access control list
1156 * \param[in] ain the ACL being set
1157 * \param[out] aout the ACL being set returned
1159 * \retval EINVAL Error if some of the standard args aren't set
1161 * \post Changed ACL, via direct writing to the wire
1163 int dummy_PSetAcl(char *ain, char *aout)
1168 DECL_PIOCTL(PSetAcl)
1170 register afs_int32 code;
1171 struct afs_conn *tconn;
1172 struct AFSOpaque acl;
1173 struct AFSVolSync tsync;
1174 struct AFSFetchStatus OutStatus;
1177 AFS_STATCNT(PSetAcl);
1180 if ((acl.AFSOpaque_len = strlen(ain) + 1) > 1024 /* AFSOPAQUEMAX */)
1183 acl.AFSOpaque_val = ain;
1185 tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1187 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1190 RXAFS_StoreACL(tconn->id, (struct AFSFid *)&avc->f.fid.Fid,
1191 &acl, &OutStatus, &tsync);
1196 } while (afs_Analyze
1197 (tconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_STOREACL,
1198 SHARED_LOCK, NULL));
1200 /* now we've forgotten all of the access info */
1201 ObtainWriteLock(&afs_xcbhash, 455);
1203 afs_DequeueCallback(avc);
1204 avc->f.states &= ~(CStatd | CUnique);
1205 ReleaseWriteLock(&afs_xcbhash);
1206 if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1207 osi_dnlc_purgedp(avc);
1209 /* SXW - Should we flush metadata here? */
1213 int afs_defaultAsynchrony = 0;
1216 * VIOC_STOREBEHIND (47) Adjust store asynchrony
1220 * \param[in] ain sbstruct (store behind structure) input
1221 * \param[out] aout resulting sbstruct
1223 * \retval EPERM Error if the user doesn't have super-user credentials
1224 * \retval EACCES Error if there isn't enough access to not check the mode bits
1226 * \post sets asynchrony based on a file, from a struct sbstruct "I THINK"
1228 DECL_PIOCTL(PStoreBehind)
1231 struct sbstruct *sbr;
1233 sbr = (struct sbstruct *)ain;
1234 if (sbr->sb_default != -1) {
1235 if (afs_osi_suser(*acred))
1236 afs_defaultAsynchrony = sbr->sb_default;
1241 if (avc && (sbr->sb_thisfile != -1)) {
1243 (avc, PRSFS_WRITE | PRSFS_ADMINISTER, areq, DONT_CHECK_MODE_BITS))
1244 avc->asynchrony = sbr->sb_thisfile;
1249 *aoutSize = sizeof(struct sbstruct);
1250 sbr = (struct sbstruct *)aout;
1251 sbr->sb_default = afs_defaultAsynchrony;
1253 sbr->sb_thisfile = avc->asynchrony;
1260 * VIOC_GCPAGS (48) - Disable automatic PAG gc'ing
1264 * \param[in] ain not in use
1265 * \param[out] aout not in use
1267 * \retval EACCES Error if the user doesn't have super-user credentials
1269 * \post set the gcpags to GCPAGS_USERDISABLED
1271 DECL_PIOCTL(PGCPAGs)
1273 if (!afs_osi_suser(*acred)) {
1276 afs_gcpags = AFS_GCPAGS_USERDISABLED;
1281 * VIOCGETAL (2) - Get access control list
1285 * \param[in] ain not in use
1286 * \param[out] aout the ACL
1288 * \retval EINVAL Error if some of the standard args aren't set
1289 * \retval ERANGE Error if the vnode of the file id is too large
1290 * \retval -1 Error if getting the ACL failed
1292 * \post Obtain the ACL, based on file ID
1294 * \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
1296 DECL_PIOCTL(PGetAcl)
1298 struct AFSOpaque acl;
1299 struct AFSVolSync tsync;
1300 struct AFSFetchStatus OutStatus;
1302 struct afs_conn *tconn;
1306 AFS_STATCNT(PGetAcl);
1309 Fid.Volume = avc->f.fid.Fid.Volume;
1310 Fid.Vnode = avc->f.fid.Fid.Vnode;
1311 Fid.Unique = avc->f.fid.Fid.Unique;
1312 if (avc->f.states & CForeign) {
1314 * For a dfs xlator acl we have a special hack so that the
1315 * xlator will distinguish which type of acl will return. So
1316 * we currently use the top 2-bytes (vals 0-4) to tell which
1317 * type of acl to bring back. Horrible hack but this will
1318 * cause the least number of changes to code size and interfaces.
1320 if (Fid.Vnode & 0xc0000000)
1322 Fid.Vnode |= (ainSize << 30);
1324 acl.AFSOpaque_val = aout;
1326 tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1329 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1331 code = RXAFS_FetchACL(tconn->id, &Fid, &acl, &OutStatus, &tsync);
1336 } while (afs_Analyze
1337 (tconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_FETCHACL,
1338 SHARED_LOCK, NULL));
1341 *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1347 * PNoop returns success. Used for functions which are not implemented or are no longer in use.
1351 * \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
1360 * PBogus returns fail. Used for functions which are not implemented or are no longer in use.
1364 * \retval EINVAL Error if some of the standard args aren't set
1366 * \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;
1370 AFS_STATCNT(PBogus);
1375 * VIOC_FILE_CELL_NAME (30) - Get cell in which file lives
1379 * \param[in] ain not in use (avc used to pass in file id)
1380 * \param[out] aout cell name
1382 * \retval EINVAL Error if some of the standard args aren't set
1383 * \retval ESRCH Error if the file isn't part of a cell
1385 * \post Get a cell based on a passed in file id
1387 DECL_PIOCTL(PGetFileCell)
1389 register struct cell *tcell;
1391 AFS_STATCNT(PGetFileCell);
1394 tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
1397 strcpy(aout, tcell->cellName);
1398 afs_PutCell(tcell, READ_LOCK);
1399 *aoutSize = strlen(aout) + 1;
1404 * VIOC_GET_WS_CELL (31) - Get cell in which workstation lives
1408 * \param[in] ain not in use
1409 * \param[out] aout cell name
1411 * \retval EIO Error if the afs daemon hasn't started yet
1412 * \retval ESRCH Error if the machine isn't part of a cell, for whatever reason
1414 * \post Get the primary cell that the machine is a part of.
1416 DECL_PIOCTL(PGetWSCell)
1418 struct cell *tcell = NULL;
1420 AFS_STATCNT(PGetWSCell);
1421 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1422 return EIO; /* Inappropriate ioctl for device */
1424 tcell = afs_GetPrimaryCell(READ_LOCK);
1425 if (!tcell) /* no primary cell? */
1427 strcpy(aout, tcell->cellName);
1428 *aoutSize = strlen(aout) + 1;
1429 afs_PutCell(tcell, READ_LOCK);
1434 * VIOC_GET_PRIMARY_CELL (33) - Get primary cell for caller
1438 * \param[in] ain not in use (user id found via areq)
1439 * \param[out] aout cell name
1441 * \retval ESRCH Error if the user id doesn't have a primary cell specified
1443 * \post Get the primary cell for a certain user, based on the user's uid
1445 DECL_PIOCTL(PGetUserCell)
1447 register afs_int32 i;
1448 register struct unixuser *tu;
1449 register struct cell *tcell;
1451 AFS_STATCNT(PGetUserCell);
1452 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1453 return EIO; /* Inappropriate ioctl for device */
1455 /* return the cell name of the primary cell for this user */
1456 i = UHash(areq->uid);
1457 ObtainWriteLock(&afs_xuser, 224);
1458 for (tu = afs_users[i]; tu; tu = tu->next) {
1459 if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1461 ReleaseWriteLock(&afs_xuser);
1466 tcell = afs_GetCell(tu->cell, READ_LOCK);
1467 afs_PutUser(tu, WRITE_LOCK);
1471 strcpy(aout, tcell->cellName);
1472 afs_PutCell(tcell, READ_LOCK);
1473 *aoutSize = strlen(aout) + 1; /* 1 for the null */
1476 ReleaseWriteLock(&afs_xuser);
1484 * VIOCSETTOK (3) - Set authentication tokens
1488 * \param[in] ain the krb tickets from which to set the afs tokens
1489 * \param[out] aout not in use
1491 * \retval EINVAL Error if the ticket is either too long or too short
1492 * \retval EIO Error if the AFS initState is below 101
1493 * \retval ESRCH Error if the cell for which the Token is being set can't be found
1495 * \post Set the Tokens for a specific cell name, unless there is none set, then default to primary
1498 DECL_PIOCTL(PSetTokens)
1501 register struct unixuser *tu;
1502 struct ClearToken clear;
1503 register struct cell *tcell;
1506 struct vrequest treq;
1507 afs_int32 flag, set_parent_pag = 0;
1509 AFS_STATCNT(PSetTokens);
1510 if (!afs_resourceinit_flag) {
1513 memcpy((char *)&i, ain, sizeof(afs_int32));
1514 ain += sizeof(afs_int32);
1515 stp = ain; /* remember where the ticket is */
1516 if (i < 0 || i > MAXKTCTICKETLEN)
1517 return EINVAL; /* malloc may fail */
1519 ain += i; /* skip over ticket */
1520 memcpy((char *)&i, ain, sizeof(afs_int32));
1521 ain += sizeof(afs_int32);
1522 if (i != sizeof(struct ClearToken)) {
1525 memcpy((char *)&clear, ain, sizeof(struct ClearToken));
1526 if (clear.AuthHandle == -1)
1527 clear.AuthHandle = 999; /* more rxvab compat stuff */
1528 ain += sizeof(struct ClearToken);
1529 if (ainSize != 2 * sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1530 /* still stuff left? we've got primary flag and cell name. Set these */
1531 memcpy((char *)&flag, ain, sizeof(afs_int32)); /* primary id flag */
1532 ain += sizeof(afs_int32); /* skip id field */
1533 /* rest is cell name, look it up */
1534 /* some versions of gcc appear to need != 0 in order to get this right */
1535 if ((flag & 0x8000) != 0) { /* XXX Use Constant XXX */
1539 tcell = afs_GetCellByName(ain, READ_LOCK);
1543 /* default to primary cell, primary id */
1544 flag = 1; /* primary id */
1545 tcell = afs_GetPrimaryCell(READ_LOCK);
1550 afs_PutCell(tcell, READ_LOCK);
1551 if (set_parent_pag) {
1553 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1554 #if defined(AFS_DARWIN_ENV)
1555 struct proc *p = current_proc(); /* XXX */
1557 struct proc *p = curproc; /* XXX */
1559 #ifndef AFS_DARWIN80_ENV
1560 uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1561 p->p_pid, p->p_comm);
1563 if (!setpag(p, acred, -1, &pag, 1)) {
1566 if (!setpag(u.u_procp, acred, -1, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
1568 if (!setpag(acred, -1, &pag, 1)) {
1571 afs_InitReq(&treq, *acred);
1575 /* now we just set the tokens */
1576 tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1577 tu->vid = clear.ViceId;
1578 if (tu->stp != NULL) {
1579 afs_osi_Free(tu->stp, tu->stLen);
1581 tu->stp = (char *)afs_osi_Alloc(stLen);
1582 if (tu->stp == NULL) {
1586 memcpy(tu->stp, stp, stLen);
1589 afs_stats_cmfullperf.authent.TicketUpdates++;
1590 afs_ComputePAGStats();
1591 #endif /* AFS_NOSTATS */
1592 tu->states |= UHasTokens;
1593 tu->states &= ~UTokensBad;
1594 afs_SetPrimary(tu, flag);
1595 tu->tokenTime = osi_Time();
1596 afs_ResetUserConns(tu);
1597 afs_PutUser(tu, WRITE_LOCK);
1613 * VIOCGETVOLSTAT (4) - Get volume status
1617 * \param[in] ain not in use
1618 * \param[out] aout status of the volume
1620 * \retval EINVAL Error if some of the standard args aren't set
1622 * \post The status of a volume (based on the FID of the volume), or an offline message /motd
1624 DECL_PIOCTL(PGetVolumeStatus)
1627 char *offLineMsg = afs_osi_Alloc(256);
1628 char *motd = afs_osi_Alloc(256);
1629 register struct afs_conn *tc;
1630 register afs_int32 code = 0;
1631 struct AFSFetchVolumeStatus volstat;
1633 char *Name, *OfflineMsg, *MOTD;
1636 AFS_STATCNT(PGetVolumeStatus);
1642 OfflineMsg = offLineMsg;
1645 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1647 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1650 RXAFS_GetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &volstat,
1651 &Name, &OfflineMsg, &MOTD);
1656 } while (afs_Analyze
1657 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1658 SHARED_LOCK, NULL));
1662 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1664 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1665 cp += sizeof(VolumeStatus);
1666 strcpy(cp, volName);
1667 cp += strlen(volName) + 1;
1668 strcpy(cp, offLineMsg);
1669 cp += strlen(offLineMsg) + 1;
1671 cp += strlen(motd) + 1;
1672 *aoutSize = (cp - aout);
1674 afs_osi_Free(offLineMsg, 256);
1675 afs_osi_Free(motd, 256);
1680 * VIOCSETVOLSTAT (5) - Set volume status
1684 * \param[in] ain values to set the status at, offline message, message of the day, volume name, minimum quota, maximum quota
1685 * \param[out] aout status of a volume, offlines messages, minimum quota, maximumm quota
1687 * \retval EINVAL Error if some of the standard args aren't set
1688 * \retval EROFS Error if the volume is read only, or a backup volume
1689 * \retval ENODEV Error if the volume can't be accessed
1690 * \retval E2BIG Error if the volume name, offline message, and motd are too big
1692 * \post Set the status of a volume, including any offline messages, a minimum quota, and a maximum quota
1694 DECL_PIOCTL(PSetVolumeStatus)
1697 char *offLineMsg = afs_osi_Alloc(256);
1698 char *motd = afs_osi_Alloc(256);
1699 register struct afs_conn *tc;
1700 register afs_int32 code = 0;
1701 struct AFSFetchVolumeStatus volstat;
1702 struct AFSStoreVolumeStatus storeStat;
1703 register struct volume *tvp;
1707 AFS_STATCNT(PSetVolumeStatus);
1713 tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
1715 if (tvp->states & (VRO | VBackup)) {
1716 afs_PutVolume(tvp, READ_LOCK);
1720 afs_PutVolume(tvp, READ_LOCK);
1725 /* Copy the junk out, using cp as a roving pointer. */
1727 memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
1728 cp += sizeof(AFSFetchVolumeStatus);
1729 if (strlen(cp) >= sizeof(volName)) {
1733 strcpy(volName, cp);
1734 cp += strlen(volName) + 1;
1735 if (strlen(cp) >= sizeof(offLineMsg)) {
1739 strcpy(offLineMsg, cp);
1740 cp += strlen(offLineMsg) + 1;
1741 if (strlen(cp) >= sizeof(motd)) {
1747 if (volstat.MinQuota != -1) {
1748 storeStat.MinQuota = volstat.MinQuota;
1749 storeStat.Mask |= AFS_SETMINQUOTA;
1751 if (volstat.MaxQuota != -1) {
1752 storeStat.MaxQuota = volstat.MaxQuota;
1753 storeStat.Mask |= AFS_SETMAXQUOTA;
1756 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1758 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1761 RXAFS_SetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &storeStat,
1762 volName, offLineMsg, motd);
1767 } while (afs_Analyze
1768 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1769 SHARED_LOCK, NULL));
1773 /* we are sending parms back to make compat. with prev system. should
1774 * change interface later to not ask for current status, just set new status */
1776 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1777 cp += sizeof(VolumeStatus);
1778 strcpy(cp, volName);
1779 cp += strlen(volName) + 1;
1780 strcpy(cp, offLineMsg);
1781 cp += strlen(offLineMsg) + 1;
1783 cp += strlen(motd) + 1;
1784 *aoutSize = cp - aout;
1786 afs_osi_Free(offLineMsg, 256);
1787 afs_osi_Free(motd, 256);
1792 * VIOCFLUSH (6) - Invalidate cache entry
1796 * \param[in] ain not in use
1797 * \param[out] aout not in use
1799 * \retval EINVAL Error if some of the standard args aren't set
1801 * \post Flush any information the cache manager has on an entry
1805 AFS_STATCNT(PFlush);
1808 #ifdef AFS_BOZONLOCK_ENV
1809 afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
1811 ObtainWriteLock(&avc->lock, 225);
1812 afs_ResetVCache(avc, *acred);
1813 ReleaseWriteLock(&avc->lock);
1814 #ifdef AFS_BOZONLOCK_ENV
1815 afs_BozonUnlock(&avc->pvnLock, avc);
1821 * VIOC_AFS_STAT_MT_PT (29) - Stat mount point
1825 * \param[in] ain the last component in a path, related to mountpoint that we're looking for information about
1826 * \param[out] aout volume, cell, link data
1828 * \retval EINVAL Error if some of the standard args aren't set
1829 * \retval ENOTDIR Error if the 'mount point' argument isn't a directory
1830 * \retval EIO Error if the link data can't be accessed
1832 * \post Get the volume, and cell, as well as the link data for a mount point
1834 DECL_PIOCTL(PNewStatMount)
1836 register afs_int32 code;
1837 register struct vcache *tvc;
1838 register struct dcache *tdc;
1839 struct VenusFid tfid;
1841 struct sysname_info sysState;
1842 afs_size_t offset, len;
1844 AFS_STATCNT(PNewStatMount);
1847 code = afs_VerifyVCache(avc, areq);
1850 if (vType(avc) != VDIR) {
1853 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
1856 Check_AtSys(avc, ain, &sysState, areq);
1857 ObtainReadLock(&tdc->lock);
1859 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
1860 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1861 ReleaseReadLock(&tdc->lock);
1862 afs_PutDCache(tdc); /* we're done with the data */
1863 bufp = sysState.name;
1867 tfid.Cell = avc->f.fid.Cell;
1868 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
1869 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
1870 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
1872 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
1878 if (tvc->mvstat != 1) {
1883 ObtainWriteLock(&tvc->lock, 226);
1884 code = afs_HandleLink(tvc, areq);
1886 if (tvc->linkData) {
1887 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1890 /* we have the data */
1891 strcpy(aout, tvc->linkData);
1892 *aoutSize = strlen(tvc->linkData) + 1;
1897 ReleaseWriteLock(&tvc->lock);
1900 if (sysState.allocked)
1901 osi_FreeLargeSpace(bufp);
1906 * VIOCGETTOK (8) - Get authentication tokens
1910 * \param[in] ain userid
1911 * \param[out] aout token
1913 * \retval EIO Error if the afs daemon hasn't started yet
1914 * \retval EDOM Error if the input parameter is out of the bounds of the available tokens
1915 * \retval ENOTCONN Error if there aren't tokens for this cell
1917 * \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
1919 * \notes "it's a weird interface (from comments in the code)"
1922 DECL_PIOCTL(PGetTokens)
1924 register struct cell *tcell;
1925 register afs_int32 i;
1926 register struct unixuser *tu;
1928 afs_int32 iterator = 0;
1931 AFS_STATCNT(PGetTokens);
1932 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1933 return EIO; /* Inappropriate ioctl for device */
1935 /* weird interface. If input parameter is present, it is an integer and
1936 * we're supposed to return the parm'th tokens for this unix uid.
1937 * If not present, we just return tokens for cell 1.
1938 * If counter out of bounds, return EDOM.
1939 * If no tokens for the particular cell, return ENOTCONN.
1940 * Also, if this mysterious parm is present, we return, along with the
1941 * tokens, the primary cell indicator (an afs_int32 0) and the cell name
1942 * at the end, in that order.
1944 if ((newStyle = (ainSize > 0))) {
1945 memcpy((char *)&iterator, ain, sizeof(afs_int32));
1947 i = UHash(areq->uid);
1948 ObtainReadLock(&afs_xuser);
1949 for (tu = afs_users[i]; tu; tu = tu->next) {
1951 if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1952 if (iterator-- == 0)
1953 break; /* are we done yet? */
1956 if (tu->uid == areq->uid && afs_IsPrimaryCellNum(tu->cell))
1962 * No need to hold a read lock on each user entry
1966 ReleaseReadLock(&afs_xuser);
1971 if (((tu->states & UHasTokens) == 0)
1972 || (tu->ct.EndTimestamp < osi_Time())) {
1973 tu->states |= (UTokensBad | UNeedsReset);
1974 afs_PutUser(tu, READ_LOCK);
1977 /* use iterator for temp */
1979 iterator = tu->stLen; /* for compat, we try to return 56 byte tix if they fit */
1981 iterator = 56; /* # of bytes we're returning */
1982 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1983 cp += sizeof(afs_int32);
1984 memcpy(cp, tu->stp, tu->stLen); /* copy out st */
1986 iterator = sizeof(struct ClearToken);
1987 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1988 cp += sizeof(afs_int32);
1989 memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
1990 cp += sizeof(struct ClearToken);
1992 /* put out primary id and cell name, too */
1993 iterator = (tu->states & UPrimary ? 1 : 0);
1994 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1995 cp += sizeof(afs_int32);
1996 tcell = afs_GetCell(tu->cell, READ_LOCK);
1998 strcpy(cp, tcell->cellName);
1999 cp += strlen(tcell->cellName) + 1;
2000 afs_PutCell(tcell, READ_LOCK);
2004 *aoutSize = cp - aout;
2005 afs_PutUser(tu, READ_LOCK);
2010 * VIOCUNLOG (9) - Invalidate tokens
2014 * \param[in] ain not in use
2015 * \param[out] aout not in use
2017 * \retval EIO Error if the afs daemon hasn't been started yet
2019 * \post remove tokens from a user, specified by the user id
2021 * \notes sets the token's time to 0, which then causes it to be removed
2022 * \notes Unlog is the same as un-pag in OpenAFS
2026 register afs_int32 i;
2027 register struct unixuser *tu;
2029 AFS_STATCNT(PUnlog);
2030 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2031 return EIO; /* Inappropriate ioctl for device */
2033 i = UHash(areq->uid);
2034 ObtainWriteLock(&afs_xuser, 227);
2035 for (tu = afs_users[i]; tu; tu = tu->next) {
2036 if (tu->uid == areq->uid) {
2038 tu->states &= ~UHasTokens;
2039 /* security is not having to say you're sorry */
2040 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
2042 ReleaseWriteLock(&afs_xuser);
2043 /* We have to drop the lock over the call to afs_ResetUserConns, since
2044 * it obtains the afs_xvcache lock. We could also keep the lock, and
2045 * modify ResetUserConns to take parm saying we obtained the lock
2046 * already, but that is overkill. By keeping the "tu" pointer
2047 * held over the released lock, we guarantee that we won't lose our
2048 * place, and that we'll pass over every user conn that existed when
2049 * we began this call.
2051 afs_ResetUserConns(tu);
2053 ObtainWriteLock(&afs_xuser, 228);
2055 /* set the expire times to 0, causes
2056 * afs_GCUserData to remove this entry
2058 tu->ct.EndTimestamp = 0;
2060 #endif /* UKERNEL */
2063 ReleaseWriteLock(&afs_xuser);
2068 * VIOC_AFS_MARINER_HOST (32) - Get/set mariner (cache manager monitor) host
2072 * \param[in] ain host address to be set
2073 * \param[out] aout old host address
2075 * \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
2077 * \notes Errors turn off mariner
2079 DECL_PIOCTL(PMariner)
2081 afs_int32 newHostAddr;
2082 afs_int32 oldHostAddr;
2084 AFS_STATCNT(PMariner);
2086 memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost,
2089 oldHostAddr = 0xffffffff; /* disabled */
2091 memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
2092 if (newHostAddr == 0xffffffff) {
2093 /* disable mariner operations */
2095 } else if (newHostAddr) {
2097 afs_marinerHost = newHostAddr;
2099 memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
2100 *aoutSize = sizeof(afs_int32);
2105 * VIOCCKSERV (10) - Check that servers are up
2109 * \param[in] ain name of the cell
2110 * \param[out] aout current down server list
2112 * \retval EIO Error if the afs daemon hasn't started yet
2113 * \retval EACCES Error if the user doesn't have super-user credentials
2114 * \retval ENOENT Error if we are unable to obtain the cell
2116 * \post Either a fast check (where it doesn't contact servers) or a local check (checks local cell only)
2118 DECL_PIOCTL(PCheckServers)
2120 register char *cp = 0;
2122 register struct server *ts;
2123 afs_int32 temp, *lp = (afs_int32 *) ain, havecell = 0;
2125 struct chservinfo *pcheck;
2127 AFS_STATCNT(PCheckServers);
2129 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2130 return EIO; /* Inappropriate ioctl for device */
2132 if (*lp == 0x12345678) { /* For afs3.3 version */
2133 pcheck = (struct chservinfo *)ain;
2134 if (pcheck->tinterval >= 0) {
2136 memcpy(cp, (char *)&afs_probe_interval, sizeof(afs_int32));
2137 *aoutSize = sizeof(afs_int32);
2138 if (pcheck->tinterval > 0) {
2139 if (!afs_osi_suser(*acred))
2141 afs_probe_interval = pcheck->tinterval;
2147 temp = pcheck->tflags;
2148 cp = pcheck->tbuffer;
2149 } else { /* For pre afs3.3 versions */
2150 memcpy((char *)&temp, ain, sizeof(afs_int32));
2151 cp = ain + sizeof(afs_int32);
2152 if (ainSize > sizeof(afs_int32))
2157 * 1: fast check, don't contact servers.
2158 * 2: local cell only.
2161 /* have cell name, too */
2162 cellp = afs_GetCellByName(cp, READ_LOCK);
2167 if (!cellp && (temp & 2)) {
2168 /* use local cell */
2169 cellp = afs_GetPrimaryCell(READ_LOCK);
2171 if (!(temp & 1)) { /* if not fast, call server checker routine */
2172 afs_CheckServers(1, cellp); /* check down servers */
2173 afs_CheckServers(0, cellp); /* check up servers */
2175 /* now return the current down server list */
2177 ObtainReadLock(&afs_xserver);
2178 for (i = 0; i < NSERVERS; i++) {
2179 for (ts = afs_servers[i]; ts; ts = ts->next) {
2180 if (cellp && ts->cell != cellp)
2181 continue; /* cell spec'd and wrong */
2182 if ((ts->flags & SRVR_ISDOWN)
2183 && ts->addr->sa_portal != ts->cell->vlport) {
2184 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2185 cp += sizeof(afs_int32);
2189 ReleaseReadLock(&afs_xserver);
2191 afs_PutCell(cellp, READ_LOCK);
2192 *aoutSize = cp - aout;
2197 * VIOCCKBACK (11) - Check backup volume mappings
2201 * \param[in] ain not in use
2202 * \param[out] aout not in use
2204 * \retval EIO Error if the afs daemon hasn't started yet
2206 * \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
2208 DECL_PIOCTL(PCheckVolNames)
2210 AFS_STATCNT(PCheckVolNames);
2211 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2212 return EIO; /* Inappropriate ioctl for device */
2214 afs_CheckRootVolume();
2215 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE | AFS_VOLCHECK_EXPIRED |
2216 AFS_VOLCHECK_BUSY | AFS_VOLCHECK_MTPTS);
2221 * VIOCCKCONN (12) - Check connections for a user
2225 * \param[in] ain not in use
2226 * \param[out] aout not in use
2228 * \retval EACCESS Error if no user is specififed, the user has no tokens set, or if the user's tokens are bad
2230 * \post check to see if a user has the correct authentication. If so, allow access.
2232 * \notes Check the connections to all the servers specified
2234 DECL_PIOCTL(PCheckAuth)
2238 struct afs_conn *tc;
2239 struct unixuser *tu;
2242 AFS_STATCNT(PCheckAuth);
2243 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2244 return EIO; /* Inappropriate ioctl for device */
2247 tu = afs_GetUser(areq->uid, 1, READ_LOCK); /* check local cell authentication */
2251 /* we have a user */
2252 ObtainReadLock(&afs_xsrvAddr);
2253 ObtainReadLock(&afs_xconn);
2255 /* any tokens set? */
2256 if ((tu->states & UHasTokens) == 0)
2258 /* all connections in cell 1 working? */
2259 for (i = 0; i < NSERVERS; i++) {
2260 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2261 for (tc = sa->conns; tc; tc = tc->next) {
2262 if (tc->user == tu && (tu->states & UTokensBad))
2267 ReleaseReadLock(&afs_xsrvAddr);
2268 ReleaseReadLock(&afs_xconn);
2269 afs_PutUser(tu, READ_LOCK);
2271 memcpy(aout, (char *)&retValue, sizeof(afs_int32));
2272 *aoutSize = sizeof(afs_int32);
2277 Prefetch(char *apath, struct afs_ioctl *adata, int afollow,
2278 struct AFS_UCRED *acred)
2281 register afs_int32 code;
2282 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
2288 AFS_STATCNT(Prefetch);
2291 tp = osi_AllocLargeSpace(1024);
2292 AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2294 osi_FreeLargeSpace(tp);
2297 if (afs_BBusy()) { /* do this as late as possible */
2298 osi_FreeLargeSpace(tp);
2299 return EWOULDBLOCK; /* pretty close */
2301 afs_BQueue(BOP_PATH, (struct vcache *)0, 0, 0, acred, (afs_size_t) 0,
2302 (afs_size_t) 0, tp);
2307 * VIOCWHEREIS (14) - Find out where a volume is located
2311 * \param[in] ain not in use
2312 * \param[out] aout volume location
2314 * \retval EINVAL Error if some of the default arguments don't exist
2315 * \retval ENODEV Error if there is no such volume
2317 * \post fine a volume, based on a volume file id
2319 * \notes check each of the servers specified
2321 DECL_PIOCTL(PFindVolume)
2323 register struct volume *tvp;
2324 register struct server *ts;
2325 register afs_int32 i;
2328 AFS_STATCNT(PFindVolume);
2331 tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
2334 for (i = 0; i < MAXHOSTS; i++) {
2335 ts = tvp->serverHost[i];
2338 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2339 cp += sizeof(afs_int32);
2342 /* still room for terminating NULL, add it on */
2343 ainSize = 0; /* reuse vbl */
2344 memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
2345 cp += sizeof(afs_int32);
2347 *aoutSize = cp - aout;
2348 afs_PutVolume(tvp, READ_LOCK);
2355 * VIOCACCESS (20) - Access using PRS_FS bits
2359 * \param[in] ain PRS_FS bits
2360 * \param[out] aout not in use
2362 * \retval EINVAL Error if some of the initial arguments aren't set
2363 * \retval EACCES Error if access is denied
2365 * \post check to make sure access is allowed
2367 DECL_PIOCTL(PViceAccess)
2369 register afs_int32 code;
2372 AFS_STATCNT(PViceAccess);
2375 code = afs_VerifyVCache(avc, areq);
2378 memcpy((char *)&temp, ain, sizeof(afs_int32));
2379 code = afs_AccessOK(avc, temp, areq, CHECK_MODE_BITS);
2387 * VIOC_GETPAG (13) - Get PAG value
2391 * \param[in] ain not in use
2392 * \param[out] aout PAG value or NOPAG
2394 * \retval E2BIG Error not enough space to copy out value
2396 * \post get PAG value for the caller's cred
2398 DECL_PIOCTL(PGetPAG)
2402 if (*aoutSize < sizeof(afs_int32)) {
2406 pag = PagInCred(*acred);
2408 memcpy(aout, (char *)&pag, sizeof(afs_int32));
2409 *aoutSize = sizeof(afs_int32);
2413 DECL_PIOCTL(PPrecache)
2417 /*AFS_STATCNT(PPrecache);*/
2418 if (!afs_osi_suser(*acred))
2420 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2421 afs_preCache = newValue*1024;
2426 * VIOCSETCACHESIZE (24) - Set venus cache size in 1000 units
2430 * \param[in] ain the size the venus cache should be set to
2431 * \param[out] aout not in use
2433 * \retval EACCES Error if the user doesn't have super-user credentials
2434 * \retval EROFS Error if the cache is set to be in memory
2436 * \post Set the cache size based on user input. If no size is given, set it to the default OpenAFS cache size.
2438 * \notes recompute the general cache parameters for every single block allocated
2440 DECL_PIOCTL(PSetCacheSize)
2445 AFS_STATCNT(PSetCacheSize);
2446 if (!afs_osi_suser(*acred))
2448 /* too many things are setup initially in mem cache version */
2449 if (cacheDiskType == AFS_FCACHE_TYPE_MEM)
2451 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2453 afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2455 if (newValue < afs_min_cache)
2456 afs_cacheBlocks = afs_min_cache;
2458 afs_cacheBlocks = newValue;
2460 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2461 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2462 afs_MaybeWakeupTruncateDaemon();
2463 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2464 afs_osi_Wait(1000, 0, 0);
2465 afs_MaybeWakeupTruncateDaemon();
2470 #define MAXGCSTATS 16
2472 * VIOCGETCACHEPARMS (40) - Get cache stats
2476 * \param[in] ain afs index flags
2477 * \param[out] aout cache blocks, blocks used, blocks files (in an array)
2479 * \post Get the cache blocks, and how many of the cache blocks there are
2481 DECL_PIOCTL(PGetCacheSize)
2483 afs_int32 results[MAXGCSTATS];
2485 register struct dcache * tdc;
2488 AFS_STATCNT(PGetCacheSize);
2490 if (sizeof(afs_int32) == ainSize){
2491 memcpy((char *)&flags, ain, sizeof(afs_int32));
2492 } else if (0 == ainSize){
2498 memset((char *)results, 0, sizeof(results));
2499 results[0] = afs_cacheBlocks;
2500 results[1] = afs_blocksUsed;
2501 results[2] = afs_cacheFiles;
2504 for (i = 0; i < afs_cacheFiles; i++) {
2505 if (afs_indexFlags[i] & IFFree) results[3]++;
2507 } else if (2 == flags){
2508 for (i = 0; i < afs_cacheFiles; i++) {
2509 if (afs_indexFlags[i] & IFFree) results[3]++;
2510 if (afs_indexFlags[i] & IFEverUsed) results[4]++;
2511 if (afs_indexFlags[i] & IFDataMod) results[5]++;
2512 if (afs_indexFlags[i] & IFDirtyPages) results[6]++;
2513 if (afs_indexFlags[i] & IFAnyPages) results[7]++;
2514 if (afs_indexFlags[i] & IFDiscarded) results[8]++;
2516 tdc = afs_indexTable[i];
2519 size = tdc->validPos;
2520 if ( 0 < size && size < (1<<12) ) results[10]++;
2521 else if (size < (1<<14) ) results[11]++;
2522 else if (size < (1<<16) ) results[12]++;
2523 else if (size < (1<<18) ) results[13]++;
2524 else if (size < (1<<20) ) results[14]++;
2525 else if (size >= (1<<20) ) results[15]++;
2529 memcpy(aout, (char *)results, sizeof(results));
2530 *aoutSize = sizeof(results);
2535 * VIOCFLUSHCB (25) - Flush callback only
2539 * \param[in] ain not in use
2540 * \param[out] aout not in use
2542 * \retval EINVAL Error if some of the standard args aren't set
2543 * \retval 0 0 returned if the volume is set to read-only
2545 * \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.
2547 DECL_PIOCTL(PRemoveCallBack)
2549 register struct afs_conn *tc;
2550 register afs_int32 code = 0;
2551 struct AFSCallBack CallBacks_Array[1];
2552 struct AFSCBFids theFids;
2553 struct AFSCBs theCBs;
2556 AFS_STATCNT(PRemoveCallBack);
2559 if (avc->f.states & CRO)
2560 return 0; /* read-only-ness can't change */
2561 ObtainWriteLock(&avc->lock, 229);
2562 theFids.AFSCBFids_len = 1;
2563 theCBs.AFSCBs_len = 1;
2564 theFids.AFSCBFids_val = (struct AFSFid *)&avc->f.fid.Fid;
2565 theCBs.AFSCBs_val = CallBacks_Array;
2566 CallBacks_Array[0].CallBackType = CB_DROPPED;
2567 if (avc->callback) {
2569 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
2571 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2573 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2577 /* don't set code on failure since we wouldn't use it */
2578 } while (afs_Analyze
2579 (tc, code, &avc->f.fid, areq,
2580 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK, NULL));
2582 ObtainWriteLock(&afs_xcbhash, 457);
2583 afs_DequeueCallback(avc);
2585 avc->f.states &= ~(CStatd | CUnique);
2586 ReleaseWriteLock(&afs_xcbhash);
2587 if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2588 osi_dnlc_purgedp(avc);
2590 ReleaseWriteLock(&avc->lock);
2595 * VIOCNEWCELL (26) - Configure new cell
2599 * \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
2600 * \param[out] aout not in use
2602 * \retval EIO Error if the afs daemon hasn't started yet
2603 * \retval EACCES Error if the user doesn't have super-user cedentials
2604 * \retval EINVAL Error if some 'magic' var doesn't have a certain bit set
2606 * \post creates a new cell
2608 DECL_PIOCTL(PNewCell)
2610 /* create a new cell */
2611 afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic = 0;
2612 char *newcell = 0, *linkedcell = 0, *tp = ain;
2613 register afs_int32 code, linkedstate = 0, ls;
2614 u_short fsport = 0, vlport = 0;
2617 AFS_STATCNT(PNewCell);
2618 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2619 return EIO; /* Inappropriate ioctl for device */
2621 if (!afs_osi_suser(*acred))
2624 memcpy((char *)&magic, tp, sizeof(afs_int32));
2625 tp += sizeof(afs_int32);
2626 if (magic != 0x12345678)
2629 /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2630 * server addresses while the 3.5 fs newcell command passes
2631 * MAXHOSTS. To figure out which is which, check if the cellname
2634 newcell = tp + (MAXCELLHOSTS + 3) * sizeof(afs_int32);
2635 scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2637 /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2638 memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
2639 tp += (scount * sizeof(afs_int32));
2641 lp = (afs_int32 *) tp;
2645 fsport = 0; /* Privileged ports not allowed */
2647 vlport = 0; /* Privileged ports not allowed */
2648 tp += (3 * sizeof(afs_int32));
2650 if ((ls = *lp) & 1) {
2651 linkedcell = tp + strlen(newcell) + 1;
2652 linkedstate |= CLinkedCell;
2655 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2657 afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport,
2662 DECL_PIOCTL(PNewAlias)
2664 /* create a new cell alias */
2666 register afs_int32 code;
2667 char *realName, *aliasName;
2669 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2670 return EIO; /* Inappropriate ioctl for device */
2672 if (!afs_osi_suser(*acred))
2676 tp += strlen(aliasName) + 1;
2679 code = afs_NewCellAlias(aliasName, realName);
2685 * VIOCGETCELL (27) - Get cell info
2689 * \param[in] ain The cell index of a specific cell
2690 * \param[out] aout list of servers in the cell
2692 * \retval EIO Error if the afs daemon hasn't started yet
2693 * \retval EDOM Error if there is no cell asked about
2695 * \post Lists the cell's server names and and addresses
2697 DECL_PIOCTL(PListCells)
2699 afs_int32 whichCell;
2700 register struct cell *tcell = 0;
2701 register afs_int32 i;
2702 register char *cp, *tp = ain;
2704 AFS_STATCNT(PListCells);
2705 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2706 return EIO; /* Inappropriate ioctl for device */
2708 memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2709 tp += sizeof(afs_int32);
2710 tcell = afs_GetCellByIndex(whichCell, READ_LOCK);
2713 memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
2714 for (i = 0; i < MAXCELLHOSTS; i++) {
2715 if (tcell->cellHosts[i] == 0)
2717 memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip,
2719 cp += sizeof(afs_int32);
2721 cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2722 strcpy(cp, tcell->cellName);
2723 cp += strlen(tcell->cellName) + 1;
2724 *aoutSize = cp - aout;
2725 afs_PutCell(tcell, READ_LOCK);
2733 DECL_PIOCTL(PListAliases)
2735 afs_int32 whichAlias;
2736 register struct cell_alias *tcalias = 0;
2737 register char *cp, *tp = ain;
2739 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2740 return EIO; /* Inappropriate ioctl for device */
2741 if (ainSize < sizeof(afs_int32))
2744 memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2745 tp += sizeof(afs_int32);
2747 tcalias = afs_GetCellAlias(whichAlias);
2750 strcpy(cp, tcalias->alias);
2751 cp += strlen(tcalias->alias) + 1;
2752 strcpy(cp, tcalias->cell);
2753 cp += strlen(tcalias->cell) + 1;
2754 *aoutSize = cp - aout;
2755 afs_PutCellAlias(tcalias);
2764 * VIOC_AFS_DELETE_MT_PT (28) - Delete mount point
2768 * \param[in] ain the name of the file in this dir to remove
2769 * \param[out] aout not in use
2771 * \retval EINVAL Error if some of the standard args aren't set
2772 * \retval ENOTDIR Error if the argument to remove is not a directory
2773 * \retval ENOENT Error if there is no cache to remove the mount point from or if a vcache doesn't exist
2775 * \post Ensure that everything is OK before deleting the mountpoint. If not, don't delete. Delete a mount point based on a file id.
2777 DECL_PIOCTL(PRemoveMount)
2779 register afs_int32 code;
2781 struct sysname_info sysState;
2782 afs_size_t offset, len;
2783 register struct afs_conn *tc;
2784 register struct dcache *tdc;
2785 register struct vcache *tvc;
2786 struct AFSFetchStatus OutDirStatus;
2787 struct VenusFid tfid;
2788 struct AFSVolSync tsync;
2792 /* "ain" is the name of the file in this dir to remove */
2794 AFS_STATCNT(PRemoveMount);
2797 code = afs_VerifyVCache(avc, areq);
2800 if (vType(avc) != VDIR)
2803 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1); /* test for error below */
2806 Check_AtSys(avc, ain, &sysState, areq);
2807 ObtainReadLock(&tdc->lock);
2809 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
2810 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2811 ReleaseReadLock(&tdc->lock);
2812 bufp = sysState.name;
2817 tfid.Cell = avc->f.fid.Cell;
2818 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
2819 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
2820 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
2822 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
2829 if (tvc->mvstat != 1) {
2835 ObtainWriteLock(&tvc->lock, 230);
2836 code = afs_HandleLink(tvc, areq);
2838 if (tvc->linkData) {
2839 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2844 ReleaseWriteLock(&tvc->lock);
2845 osi_dnlc_purgedp(tvc);
2851 ObtainWriteLock(&avc->lock, 231);
2852 osi_dnlc_remove(avc, bufp, tvc);
2854 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
2856 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2859 RXAFS_RemoveFile(tc->id, (struct AFSFid *)&avc->f.fid.Fid, bufp,
2860 &OutDirStatus, &tsync);
2865 } while (afs_Analyze
2866 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_REMOVEFILE,
2867 SHARED_LOCK, NULL));
2872 ReleaseWriteLock(&avc->lock);
2876 /* we have the thing in the cache */
2877 ObtainWriteLock(&tdc->lock, 661);
2878 if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2879 /* we can do it locally */
2880 code = afs_dir_Delete(tdc, bufp);
2882 ZapDCE(tdc); /* surprise error -- invalid value */
2886 ReleaseWriteLock(&tdc->lock);
2887 afs_PutDCache(tdc); /* drop ref count */
2889 avc->f.states &= ~CUnique; /* For the dfs xlator */
2890 ReleaseWriteLock(&avc->lock);
2893 if (sysState.allocked)
2894 osi_FreeLargeSpace(bufp);
2899 * VIOC_VENUSLOG (34) - Enable/Disable venus logging
2903 * \retval EINVAL Error if some of the standard args aren't set
2905 * \notes Obsoleted, perhaps should be PBogus
2907 DECL_PIOCTL(PVenusLogging)
2909 return EINVAL; /* OBSOLETE */
2913 * VIOC_GETCELLSTATUS (35) - Get cell status info
2917 * \param[in] ain The cell you want status information on
2918 * \param[out] aout cell state (as a struct)
2920 * \retval EIO Error if the afs daemon hasn't started yet
2921 * \retval ENOENT Error if the cell doesn't exist
2923 * \post Returns the state of the cell as defined in a struct cell
2925 DECL_PIOCTL(PGetCellStatus)
2927 register struct cell *tcell;
2930 AFS_STATCNT(PGetCellStatus);
2931 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2932 return EIO; /* Inappropriate ioctl for device */
2934 tcell = afs_GetCellByName(ain, READ_LOCK);
2937 temp = tcell->states;
2938 afs_PutCell(tcell, READ_LOCK);
2939 memcpy(aout, (char *)&temp, sizeof(afs_int32));
2940 *aoutSize = sizeof(afs_int32);
2945 * VIOC_SETCELLSTATUS (36) - Set corresponding info
2949 * \param[in] ain The cell you want to set information about, and the values you want to set
2950 * \param[out] aout not in use
2952 * \retval EIO Error if the afs daemon hasn't started yet
2953 * \retval EACCES Error if the user doesn't have super-user credentials
2955 * \post Set the state of the cell in a defined struct cell, based on whether or not SetUID is allowed
2957 DECL_PIOCTL(PSetCellStatus)
2959 register struct cell *tcell;
2962 if (!afs_osi_suser(*acred))
2964 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2965 return EIO; /* Inappropriate ioctl for device */
2967 tcell = afs_GetCellByName(ain + 2 * sizeof(afs_int32), WRITE_LOCK);
2970 memcpy((char *)&temp, ain, sizeof(afs_int32));
2972 tcell->states |= CNoSUID;
2974 tcell->states &= ~CNoSUID;
2975 afs_PutCell(tcell, WRITE_LOCK);
2980 * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
2984 * \param[in] ain not in use (args in avc)
2985 * \param[out] aout not in use
2987 * \retval EINVAL Error if some of the standard args aren't set
2988 * \retval EIO Error if the afs daemon hasn't started yet
2990 * \post Wipe everything on the volume. This is done dependent on which platform this is for.
2992 * \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.
2994 DECL_PIOCTL(PFlushVolumeData)
2996 register afs_int32 i;
2997 register struct dcache *tdc;
2998 register struct vcache *tvc;
2999 register struct volume *tv;
3000 afs_int32 cell, volume;
3001 struct afs_q *tq, *uq;
3002 #ifdef AFS_DARWIN80_ENV
3006 AFS_STATCNT(PFlushVolumeData);
3009 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3010 return EIO; /* Inappropriate ioctl for device */
3012 volume = avc->f.fid.Fid.Volume; /* who to zap */
3013 cell = avc->f.fid.Cell;
3016 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
3017 * the vcaches associated with the volume.
3020 ObtainReadLock(&afs_xvcache);
3021 i = VCHashV(&avc->f.fid);
3022 for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
3025 if (tvc->f.fid.Fid.Volume == volume && tvc->f.fid.Cell == cell) {
3026 if (tvc->f.states & CVInit) {
3027 ReleaseReadLock(&afs_xvcache);
3028 afs_osi_Sleep(&tvc->f.states);
3031 #ifdef AFS_DARWIN80_ENV
3032 if (tvc->f.states & CDeadVnode) {
3033 ReleaseReadLock(&afs_xvcache);
3034 afs_osi_Sleep(&tvc->f.states);
3038 #if defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
3039 VN_HOLD(AFSTOV(tvc));
3041 #ifdef AFS_DARWIN80_ENV
3045 if (vnode_ref(vp)) {
3052 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
3055 VREFCOUNT_INC(tvc); /* AIX, apparently */
3059 ReleaseReadLock(&afs_xvcache);
3060 #ifdef AFS_BOZONLOCK_ENV
3061 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3063 ObtainWriteLock(&tvc->lock, 232);
3065 ObtainWriteLock(&afs_xcbhash, 458);
3066 afs_DequeueCallback(tvc);
3067 tvc->f.states &= ~(CStatd | CDirty);
3068 ReleaseWriteLock(&afs_xcbhash);
3069 if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
3070 osi_dnlc_purgedp(tvc);
3071 afs_TryToSmush(tvc, *acred, 1);
3072 ReleaseWriteLock(&tvc->lock);
3073 #ifdef AFS_BOZONLOCK_ENV
3074 afs_BozonUnlock(&tvc->pvnLock, tvc);
3076 #ifdef AFS_DARWIN80_ENV
3077 vnode_put(AFSTOV(tvc));
3079 ObtainReadLock(&afs_xvcache);
3081 /* our tvc ptr is still good until now */
3085 ReleaseReadLock(&afs_xvcache);
3088 MObtainWriteLock(&afs_xdcache, 328); /* needed if you're going to flush any stuff */
3089 for (i = 0; i < afs_cacheFiles; i++) {
3090 if (!(afs_indexFlags[i] & IFEverUsed))
3091 continue; /* never had any data */
3092 tdc = afs_GetDSlot(i, NULL);
3093 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
3094 ReleaseReadLock(&tdc->tlock);
3095 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
3096 if (!(afs_indexFlags[i] & IFDataMod)) {
3097 /* if the file is modified, but has a ref cnt of only 1, then
3098 * someone probably has the file open and is writing into it.
3099 * Better to skip flushing such a file, it will be brought back
3100 * immediately on the next write anyway.
3102 * If we *must* flush, then this code has to be rearranged to call
3103 * afs_storeAllSegments() first */
3104 afs_FlushDCache(tdc);
3108 ReleaseReadLock(&tdc->tlock);
3110 afs_PutDCache(tdc); /* bumped by getdslot */
3112 MReleaseWriteLock(&afs_xdcache);
3114 ObtainReadLock(&afs_xvolume);
3115 for (i = 0; i < NVOLS; i++) {
3116 for (tv = afs_volumes[i]; tv; tv = tv->next) {
3117 if (tv->volume == volume) {
3118 afs_ResetVolumeInfo(tv);
3123 ReleaseReadLock(&afs_xvolume);
3125 /* probably, a user is doing this, probably, because things are screwed up.
3126 * maybe it's the dnlc's fault? */
3133 * VIOCGETVCXSTATUS (41) - gets vnode x status
3137 * \param[in] ain not in use (avc used)
3138 * \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
3140 * \retval EINVAL Error if some of the initial default arguments aren't set
3141 * \retval EACCES Error if access to check the mode bits is denied
3143 * \post gets stats for the vnode, a struct listed in vcxstat
3145 DECL_PIOCTL(PGetVnodeXStatus)
3147 register afs_int32 code;
3148 struct vcxstat stat;
3151 /* AFS_STATCNT(PGetVnodeXStatus); */
3154 code = afs_VerifyVCache(avc, areq);
3157 if (vType(avc) == VDIR)
3158 mode = PRSFS_LOOKUP;
3161 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3164 memset(&stat, 0, sizeof(struct vcxstat));
3165 stat.fid = avc->f.fid;
3166 hset32(stat.DataVersion, hgetlo(avc->f.m.DataVersion));
3167 stat.lock = avc->lock;
3168 stat.parentVnode = avc->f.parent.vnode;
3169 stat.parentUnique = avc->f.parent.unique;
3170 hset(stat.flushDV, avc->flushDV);
3171 hset(stat.mapDV, avc->mapDV);
3172 stat.truncPos = avc->f.truncPos;
3173 { /* just grab the first two - won't break anything... */
3174 struct axscache *ac;
3176 for (i = 0, ac = avc->Access; ac && i < CPSIZE; i++, ac = ac->next) {
3177 stat.randomUid[i] = ac->uid;
3178 stat.randomAccess[i] = ac->axess;
3181 stat.callback = afs_data_pointer_to_int32(avc->callback);
3182 stat.cbExpires = avc->cbExpires;
3183 stat.anyAccess = avc->f.anyAccess;
3184 stat.opens = avc->opens;
3185 stat.execsOrWriters = avc->execsOrWriters;
3186 stat.flockCount = avc->flockCount;
3187 stat.mvstat = avc->mvstat;
3188 stat.states = avc->f.states;
3189 memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
3190 *aoutSize = sizeof(struct vcxstat);
3195 DECL_PIOCTL(PGetVnodeXStatus2)
3197 register afs_int32 code;
3198 struct vcxstat2 stat;
3203 code = afs_VerifyVCache(avc, areq);
3206 if (vType(avc) == VDIR)
3207 mode = PRSFS_LOOKUP;
3210 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3213 memset(&stat, 0, sizeof(struct vcxstat2));
3215 stat.cbExpires = avc->cbExpires;
3216 stat.anyAccess = avc->f.anyAccess;
3217 stat.mvstat = avc->mvstat;
3218 stat.callerAccess = afs_GetAccessBits(avc, ~0, areq);
3220 memcpy(aout, (char *)&stat, sizeof(struct vcxstat2));
3221 *aoutSize = sizeof(struct vcxstat2);
3227 * VIOC_AFS_SYSNAME (38) - Change @sys value
3231 * \param[in] ain new value for @sys
3232 * \param[out] aout count, entry, list (debug values?)
3234 * \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"
3235 * \retval ENODEV Error if there isn't already a system named that ("I THINK")
3236 * \retval EACCES Error if the user doesn't have super-user credentials
3238 * \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
3240 * \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.
3242 DECL_PIOCTL(PSetSysName)
3244 char *cp, *cp2 = NULL, inname[MAXSYSNAME], outname[MAXSYSNAME];
3245 afs_int32 setsysname;
3247 register struct afs_exporter *exporter;
3248 register struct unixuser *au;
3249 register afs_int32 pag, error;
3250 int t, count, num = 0, allpags = 0;
3253 AFS_STATCNT(PSetSysName);
3254 if (!afs_globalVFS) {
3255 /* Afsd is NOT running; disable it */
3256 #if defined(KERNEL_HAVE_UERROR)
3257 return (setuerror(EINVAL), EINVAL);
3262 memset(inname, 0, MAXSYSNAME);
3263 memcpy(&setsysname, ain, sizeof(afs_int32));
3264 ain += sizeof(afs_int32);
3265 if (setsysname & 0x8000) {
3267 setsysname &= ~0x8000;
3272 if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
3275 for (cp = ain, count = 0; count < setsysname; count++) {
3276 /* won't go past end of ain since maxsysname*num < ain length */
3278 if (t >= MAXSYSNAME || t <= 0)
3280 /* check for names that can shoot us in the foot */
3281 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
3287 /* inname gets first entry in case we're being a translator */
3289 memcpy(inname, ain, t + 1); /* include terminating null */
3293 if ((*acred)->cr_gid == RMTUSER_REQ ||
3294 (*acred)->cr_gid == RMTUSER_REQ_PRIV) { /* Handles all exporters */
3295 if (allpags && (*acred)->cr_gid != RMTUSER_REQ_PRIV) {
3298 pag = PagInCred(*acred);
3300 return EINVAL; /* Better than panicing */
3302 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
3303 return EINVAL; /* Better than panicing */
3305 if (!(exporter = au->exporter)) {
3306 afs_PutUser(au, READ_LOCK);
3307 return EINVAL; /* Better than panicing */
3309 error = EXP_SYSNAME(exporter, (setsysname ? cp2 : NULL), &sysnamelist,
3312 if (error == ENODEV)
3313 foundname = 0; /* sysname not set yet! */
3315 afs_PutUser(au, READ_LOCK);
3320 strcpy(outname, sysnamelist[0]);
3322 afs_PutUser(au, READ_LOCK);
3326 /* Not xlating, so local case */
3328 osi_Panic("PSetSysName: !afs_sysname\n");
3329 if (!setsysname) { /* user just wants the info */
3330 strcpy(outname, afs_sysname);
3331 foundname = afs_sysnamecount;
3332 sysnamelist = afs_sysnamelist;
3333 } else { /* Local guy; only root can change sysname */
3334 if (!afs_osi_suser(*acred))
3337 /* allpags makes no sense for local use */
3341 /* clear @sys entries from the dnlc, once afs_lookup can
3342 * do lookups of @sys entries and thinks it can trust them */
3343 /* privs ok, store the entry, ... */
3344 strcpy(afs_sysname, inname);
3345 if (setsysname > 1) { /* ... or list */
3347 for (count = 1; count < setsysname; ++count) {
3348 if (!afs_sysnamelist[count])
3350 ("PSetSysName: no afs_sysnamelist entry to write\n");
3352 memcpy(afs_sysnamelist[count], cp, t + 1); /* include null */
3356 afs_sysnamecount = setsysname;
3361 cp = aout; /* not changing so report back the count and ... */
3362 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
3363 cp += sizeof(afs_int32);
3365 strcpy(cp, outname); /* ... the entry, ... */
3366 cp += strlen(outname) + 1;
3367 for (count = 1; count < foundname; ++count) { /* ... or list. */
3368 if (!sysnamelist[count])
3370 ("PSetSysName: no afs_sysnamelist entry to read\n");
3371 t = strlen(sysnamelist[count]);
3372 if (t >= MAXSYSNAME)
3373 osi_Panic("PSetSysName: sysname entry garbled\n");
3374 strcpy(cp, sysnamelist[count]);
3378 *aoutSize = cp - aout;
3383 /* sequential search through the list of touched cells is not a good
3384 * long-term solution here. For small n, though, it should be just
3385 * fine. Should consider special-casing the local cell for large n.
3386 * Likewise for PSetSPrefs.
3388 * s - number of ids in array l[] -- NOT index of last id
3389 * l - array of cell ids which have volumes that need to be sorted
3390 * vlonly - sort vl servers or file servers?
3393 ReSortCells_cb(struct cell *cell, void *arg)
3395 afs_int32 *p = (afs_int32 *) arg;
3396 afs_int32 *l = p + 1;
3399 for (i = 0; i < s; i++) {
3400 if (l[i] == cell->cellNum) {
3401 ObtainWriteLock(&cell->lock, 690);
3402 afs_SortServers(cell->cellHosts, MAXCELLHOSTS);
3403 ReleaseWriteLock(&cell->lock);
3411 ReSortCells(int s, afs_int32 * l, int vlonly)
3419 p = (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * (s + 1));
3421 memcpy(p + 1, l, s * sizeof(afs_int32));
3422 afs_TraverseCells(&ReSortCells_cb, p);
3423 afs_osi_Free(p, sizeof(afs_int32) * (s + 1));
3427 ObtainReadLock(&afs_xvolume);
3428 for (i = 0; i < NVOLS; i++) {
3429 for (j = afs_volumes[i]; j; j = j->next) {
3430 for (k = 0; k < s; k++)
3431 if (j->cell == l[k]) {
3432 ObtainWriteLock(&j->lock, 233);
3433 afs_SortServers(j->serverHost, MAXHOSTS);
3434 ReleaseWriteLock(&j->lock);
3439 ReleaseReadLock(&afs_xvolume);
3443 static int debugsetsp = 0;
3445 afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
3448 int i, j, k, matches, touchedSize;
3449 struct server *srvr = NULL;
3450 afs_int32 touched[34];
3454 for (k = 0; k < num; sp++, k++) {
3456 printf("sp host=%x, rank=%d\n", sp->host.s_addr, sp->rank);
3459 ObtainReadLock(&afs_xserver);
3461 i = SHash(sp->host.s_addr);
3462 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
3463 if (sa->sa_ip == sp->host.s_addr) {
3465 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3466 || (sa->sa_portal == AFS_FSPORT);
3467 if ((!vlonly && isfs) || (vlonly && !isfs)) {
3474 if (sa && matches) { /* found one! */
3476 printf("sa ip=%x, ip_rank=%d\n", sa->sa_ip, sa->sa_iprank);
3478 sa->sa_iprank = sp->rank + afs_randomMod15();
3479 afs_SortOneServer(sa->server);
3482 /* if we don't know yet what cell it's in, this is moot */
3483 for (j = touchedSize - 1;
3484 j >= 0 && touched[j] != srvr->cell->cellNum; j--)
3485 /* is it in our list of touched cells ? */ ;
3486 if (j < 0) { /* no, it's not */
3487 touched[touchedSize++] = srvr->cell->cellNum;
3488 if (touchedSize >= 32) { /* watch for ovrflow */
3489 ReleaseReadLock(&afs_xserver);
3490 ReSortCells(touchedSize, touched, vlonly);
3492 ObtainReadLock(&afs_xserver);
3498 ReleaseReadLock(&afs_xserver);
3499 /* if we didn't find one, start to create one. */
3500 /* Note that it doesn't have a cell yet... */
3502 afs_uint32 temp = sp->host.s_addr;
3504 afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
3505 WRITE_LOCK, (afsUUID *) 0, 0);
3506 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3507 afs_PutServer(srvr, WRITE_LOCK);
3509 } /* for all cited preferences */
3511 ReSortCells(touchedSize, touched, vlonly);
3516 * VIOC_SETPREFS (46) - Set server ranks
3518 * \param[in] ain the sprefs value you want the sprefs to be set to
3519 * \param[out] aout not in use
3521 * \retval EIO Error if the afs daemon hasn't started yet
3522 * \retval EACCES Error if the user doesn't have super-user credentials
3523 * \retval EINVAL Error if the struct setsprefs is too large or if it multiplied by the number of servers is too large
3525 * \post set the sprefs using the afs_setsprefs() function
3527 DECL_PIOCTL(PSetSPrefs)
3529 struct setspref *ssp;
3530 AFS_STATCNT(PSetSPrefs);
3532 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3533 return EIO; /* Inappropriate ioctl for device */
3535 if (!afs_osi_suser(*acred))
3538 if (ainSize < sizeof(struct setspref))
3541 ssp = (struct setspref *)ain;
3542 if (ainSize < sizeof(struct spref) * ssp->num_servers)
3545 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
3546 (ssp->flags & DBservers));
3551 * VIOC_SETPREFS33 (42) - Set server ranks (deprecated)
3553 * \param[in] ain the server preferences to be set
3554 * \param[out] aout not in use
3556 * \retval EIO Error if the afs daemon hasn't started yet
3557 * \retval EACCES Error if the user doesn't have super-user credentials
3559 * \post set the server preferences, calling a function
3561 * \notes this may only be performed by the local root user.
3563 DECL_PIOCTL(PSetSPrefs33)
3566 AFS_STATCNT(PSetSPrefs);
3567 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3568 return EIO; /* Inappropriate ioctl for device */
3571 if (!afs_osi_suser(*acred))
3574 sp = (struct spref *)ain;
3575 afs_setsprefs(sp, ainSize / (sizeof(struct spref)), 0 /*!vlonly */ );
3580 * VIOC_GETSPREFS (43) - Get server ranks
3584 * \param[in] ain the server preferences to get
3585 * \param[out] aout the server preferences information
3587 * \retval EIO Error if the afs daemon hasn't started yet
3588 * \retval ENOENT Error if the sprefrequest is too large
3590 * \post Get the sprefs
3592 * \notes in the hash table of server structs, all servers with the same IP address; will be on the same overflow chain; This could be sped slightly in some circumstances by having it cache the immediately previous slot in the hash table and some supporting information; Only reports file servers now.
3594 DECL_PIOCTL(PGetSPrefs)
3596 struct sprefrequest *spin; /* input */
3597 struct sprefinfo *spout; /* output */
3598 struct spref *srvout; /* one output component */
3599 int i, j; /* counters for hash table traversal */
3600 struct server *srvr; /* one of CM's server structs */
3602 int vlonly; /* just return vlservers ? */
3605 AFS_STATCNT(PGetSPrefs);
3606 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3607 return EIO; /* Inappropriate ioctl for device */
3610 if (ainSize < sizeof(struct sprefrequest_33)) {
3613 spin = ((struct sprefrequest *)ain);
3616 if (ainSize > sizeof(struct sprefrequest_33)) {
3617 vlonly = (spin->flags & DBservers);
3621 /* struct sprefinfo includes 1 server struct... that size gets added
3622 * in during the loop that follows.
3624 *aoutSize = sizeof(struct sprefinfo) - sizeof(struct spref);
3625 spout = (struct sprefinfo *)aout;
3626 spout->next_offset = spin->offset;
3627 spout->num_servers = 0;
3628 srvout = spout->servers;
3630 ObtainReadLock(&afs_xserver);
3631 for (i = 0, j = 0; j < NSERVERS; j++) { /* sift through hash table */
3632 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3633 if (spin->offset > (unsigned short)i) {
3634 continue; /* catch up to where we left off */
3636 spout->next_offset++;
3639 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3640 || (sa->sa_portal == AFS_FSPORT);
3642 if ((vlonly && isfs) || (!vlonly && !isfs)) {
3643 /* only report ranks for vl servers */
3647 srvout->host.s_addr = sa->sa_ip;
3648 srvout->rank = sa->sa_iprank;
3649 *aoutSize += sizeof(struct spref);
3650 spout->num_servers++;
3653 if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3654 ReleaseReadLock(&afs_xserver); /* no more room! */
3659 ReleaseReadLock(&afs_xserver);
3661 spout->next_offset = 0; /* start over from the beginning next time */
3665 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3666 int afs_NFSRootOnly = 1;
3668 * VIOC_EXPORTAFS (39) - Export afs to nfs clients
3672 * \param[in] ain a struct Vic * EIOctl containing export values needed to change between nfs and afs
3673 * \param[out] aout a struct of the exporter states (exporter->exp_states)
3675 * \retval ENODEV Error if the exporter doesn't exist
3676 * \retval EACCES Error if the user doesn't have super-user credentials
3678 * \post Changes the state of various values to reflect the change of the export values between nfs and afs.
3680 * \notes Legacy code obtained from IBM.
3682 DECL_PIOCTL(PExportAfs)
3684 afs_int32 export, newint =
3685 0, type, changestate, handleValue, convmode, pwsync, smounts;
3686 afs_int32 rempags = 0, pagcb = 0;
3687 register struct afs_exporter *exporter;
3689 AFS_STATCNT(PExportAfs);
3690 memcpy((char *)&handleValue, ain, sizeof(afs_int32));
3691 type = handleValue >> 24;
3696 exporter = exporter_find(type);
3698 export = handleValue & 3;
3699 changestate = handleValue & 0xfff;
3700 smounts = (handleValue >> 2) & 3;
3701 pwsync = (handleValue >> 4) & 3;
3702 convmode = (handleValue >> 6) & 3;
3703 rempags = (handleValue >> 8) & 3;
3704 pagcb = (handleValue >> 10) & 3;
3706 changestate = (handleValue >> 16) & 0x1;
3707 convmode = (handleValue >> 16) & 0x2;
3708 pwsync = (handleValue >> 16) & 0x4;
3709 smounts = (handleValue >> 16) & 0x8;
3710 export = handleValue & 0xff;
3713 /* Failed finding desired exporter; */
3717 handleValue = exporter->exp_states;
3718 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3719 *aoutSize = sizeof(afs_int32);
3721 if (!afs_osi_suser(*acred))
3722 return EACCES; /* Only superuser can do this */
3726 exporter->exp_states |= EXP_EXPORTED;
3728 exporter->exp_states &= ~EXP_EXPORTED;
3732 exporter->exp_states |= EXP_UNIXMODE;
3734 exporter->exp_states &= ~EXP_UNIXMODE;
3738 exporter->exp_states |= EXP_PWSYNC;
3740 exporter->exp_states &= ~EXP_PWSYNC;
3744 afs_NFSRootOnly = 0;
3745 exporter->exp_states |= EXP_SUBMOUNTS;
3747 afs_NFSRootOnly = 1;
3748 exporter->exp_states &= ~EXP_SUBMOUNTS;
3753 exporter->exp_states |= EXP_CLIPAGS;
3755 exporter->exp_states &= ~EXP_CLIPAGS;
3759 exporter->exp_states |= EXP_CALLBACK;
3761 exporter->exp_states &= ~EXP_CALLBACK;
3763 handleValue = exporter->exp_states;
3764 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3765 *aoutSize = sizeof(afs_int32);
3768 exporter->exp_states |= EXP_EXPORTED;
3770 exporter->exp_states &= ~EXP_EXPORTED;
3772 exporter->exp_states |= EXP_UNIXMODE;
3774 exporter->exp_states &= ~EXP_UNIXMODE;
3776 exporter->exp_states |= EXP_PWSYNC;
3778 exporter->exp_states &= ~EXP_PWSYNC;
3780 afs_NFSRootOnly = 0;
3781 exporter->exp_states |= EXP_SUBMOUNTS;
3783 afs_NFSRootOnly = 1;
3784 exporter->exp_states &= ~EXP_SUBMOUNTS;
3793 * VIOC_GAG (44) - Silence Cache Manager
3797 * \param[in] ain the flags to either gag or de-gag the cache manager
3798 * \param[out] aout not in use
3800 * \retval EACCES Error if the user doesn't have super-user credentials
3802 * \post set the gag flags, then show these flags
3806 struct gaginfo *gagflags;
3808 if (!afs_osi_suser(*acred))
3811 gagflags = (struct gaginfo *)ain;
3812 afs_showflags = gagflags->showflags;
3818 * VIOC_TWIDDLE (45) - Adjust RX knobs
3822 * \param[in] ain the previous settings of the 'knobs'
3823 * \param[out] aout not in use
3825 * \retval EACCES Error if the user doesn't have super-user credentials
3827 * \post build out the struct rxp, from a struct rx
3829 DECL_PIOCTL(PTwiddleRx)
3831 struct rxparams *rxp;
3833 if (!afs_osi_suser(*acred))
3836 rxp = (struct rxparams *)ain;
3838 if (rxp->rx_initReceiveWindow)
3839 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3840 if (rxp->rx_maxReceiveWindow)
3841 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3842 if (rxp->rx_initSendWindow)
3843 rx_initSendWindow = rxp->rx_initSendWindow;
3844 if (rxp->rx_maxSendWindow)
3845 rx_maxSendWindow = rxp->rx_maxSendWindow;
3846 if (rxp->rxi_nSendFrags)
3847 rxi_nSendFrags = rxp->rxi_nSendFrags;
3848 if (rxp->rxi_nRecvFrags)
3849 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3850 if (rxp->rxi_OrphanFragSize)
3851 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3852 if (rxp->rx_maxReceiveSize) {
3853 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3854 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3856 if (rxp->rx_MyMaxSendSize)
3857 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3863 * VIOC_GETINITPARAMS (49) - Get initial cache manager parameters
3867 * \param[in] ain not in use
3868 * \param[out] aout initial cache manager params
3870 * \retval E2BIG Error if the initial parameters are bigger than some PIGGYSIZE
3872 * \post return the initial cache manager parameters
3874 DECL_PIOCTL(PGetInitParams)
3876 if (sizeof(struct cm_initparams) > PIGGYSIZE)
3879 memcpy(aout, (char *)&cm_initParams, sizeof(struct cm_initparams));
3880 *aoutSize = sizeof(struct cm_initparams);
3884 #ifdef AFS_SGI65_ENV
3885 /* They took crget() from us, so fake it. */
3890 cr = crdup(get_current_cred());
3891 memset((char *)cr, 0, sizeof(cred_t));
3892 #if CELL || CELL_PREPARE
3900 * VIOC_GETRXKCRYPT (55) - Get rxkad encryption flag
3904 * \param[in] ain not in use
3905 * \param[out] aout value of cryptall
3907 * \post get the value of cryptall (presumably whether or not things should be encrypted)
3909 DECL_PIOCTL(PGetRxkcrypt)
3911 memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3912 *aoutSize = sizeof(afs_int32);
3917 * VIOC_SETRXKCRYPT (56) - Set rxkad encryption flag
3921 * \param[in] ain the argument whether or not things should be encrypted
3922 * \param[out] aout not in use
3924 * \retval EPERM Error if the user doesn't have super-user credentials
3925 * \retval EINVAL Error if the input is too big, or if the input is outside the bounds of what it can be set to
3927 * \post set whether or not things should be encrypted
3929 * \notes may need to be modified at a later date to take into account other values for cryptall (beyond true or false)
3931 DECL_PIOCTL(PSetRxkcrypt)
3935 if (!afs_osi_suser(*acred))
3937 if (ainSize != sizeof(afs_int32) || ain == NULL)
3939 memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3940 /* if new mappings added later this will need to be changed */
3941 if (tmpval != 0 && tmpval != 1)
3947 #ifdef AFS_NEED_CLIENTCONTEXT
3949 * Create new credentials to correspond to a remote user with given
3950 * <hostaddr, uid, g0, g1>. This allows a server running as root to
3951 * provide pioctl (and other) services to foreign clients (i.e. nfs
3952 * clients) by using this call to `become' the client.
3955 #define PIOCTL_HEADER 6
3957 HandleClientContext(struct afs_ioctl *ablob, int *com,
3958 struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3961 afs_uint32 hostaddr;
3962 afs_int32 uid, g0, g1, i, code, pag, exporter_type, isroot = 0;
3963 struct afs_exporter *exporter, *outexporter;
3964 struct AFS_UCRED *newcred;
3965 struct unixuser *au;
3966 afs_uint32 comp = *com & 0xff00;
3969 #if defined(AFS_SGIMP_ENV)
3970 osi_Assert(ISAFS_GLOCK());
3972 AFS_STATCNT(HandleClientContext);
3973 if (ablob->in_size < PIOCTL_HEADER * sizeof(afs_int32)) {
3974 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3975 return EINVAL; /* Too small to be good */
3977 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3978 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER * sizeof(afs_int32), code);
3980 osi_FreeLargeSpace(inData);
3984 /* Extract information for remote user */
3985 hostaddr = *((afs_uint32 *) ain);
3986 ain += sizeof(hostaddr);
3987 uid = *((afs_uint32 *) ain);
3989 g0 = *((afs_uint32 *) ain);
3991 g1 = *((afs_uint32 *) ain);
3993 *com = *((afs_uint32 *) ain);
3994 ain += sizeof(afs_int32);
3995 exporter_type = *((afs_uint32 *) ain); /* In case we support more than NFS */
3998 * Of course, one must be root for most of these functions, but
3999 * we'll allow (for knfs) you to set things if the pag is 0 and
4000 * you're setting tokens or unlogging.
4003 if (!afs_osi_suser(credp)) {
4004 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI64_ENV)
4005 /* Since SGI's suser() returns explicit failure after the call.. */
4008 /* check for acceptable opcodes for normal folks, which are, so far,
4009 * get/set tokens, sysname, and unlog.
4011 if (i != 9 && i != 3 && i != 38 && i != 8) {
4012 osi_FreeLargeSpace(inData);
4017 ablob->in_size -= PIOCTL_HEADER * sizeof(afs_int32);
4018 ablob->in += PIOCTL_HEADER * sizeof(afs_int32);
4019 osi_FreeLargeSpace(inData);
4022 * We map uid 0 to nobody to match the mapping that the nfs
4023 * server does and to ensure that the suser() calls in the afs
4024 * code fails for remote client roots.
4026 uid = afs_nobody; /* NFS_NOBODY == -2 */
4030 #ifdef AFS_AIX41_ENV
4033 newcred->cr_gid = isroot ? RMTUSER_REQ_PRIV : RMTUSER_REQ;
4034 #ifdef AFS_AIX51_ENV
4035 newcred->cr_groupset.gs_union.un_groups[0] = g0;
4036 newcred->cr_groupset.gs_union.un_groups[1] = g1;
4037 #elif defined(AFS_LINUX26_ENV)
4038 #ifdef AFS_LINUX26_ONEGROUP_ENV
4039 newcred->cr_group_info = groups_alloc(1); /* not that anything sets this */
4040 l = (((g0-0x3f00) & 0x3fff) << 14) | ((g1-0x3f00) & 0x3fff);
4041 h = ((g0-0x3f00) >> 14);
4042 h = ((g1-0x3f00) >> 14) + h + h + h;
4043 GROUP_AT(newcred->cr_group_info, 0) = ((h << 28) | l);
4045 newcred->cr_group_info = groups_alloc(2);
4046 GROUP_AT(newcred->cr_group_info, 0) = g0;
4047 GROUP_AT(newcred->cr_group_info, 1) = g1;
4050 newcred->cr_groups[0] = g0;
4051 newcred->cr_groups[1] = g1;
4054 newcred->cr_ngrps = 2;
4055 #elif !defined(AFS_LINUX26_ENV)
4056 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
4057 newcred->cr_ngroups = 2;
4059 for (i = 2; i < NGROUPS; i++)
4060 newcred->cr_groups[i] = NOGROUP;
4063 #if !defined(AFS_OSF_ENV)
4064 afs_nfsclient_init(); /* before looking for exporter, ensure one exists */
4066 if (!(exporter = exporter_find(exporter_type))) {
4067 /* Exporter wasn't initialized or an invalid exporter type */
4071 if (exporter->exp_states & EXP_PWSYNC) {
4072 if (uid != credp->cr_uid) {
4074 return ENOEXEC; /* XXX Find a better errno XXX */
4077 newcred->cr_uid = uid; /* Only temporary */
4078 code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
4079 /* The client's pag is the only unique identifier for it */
4080 newcred->cr_uid = pag;
4082 if (!code && *com == PSETPAG) {
4083 /* Special case for 'setpag' */
4084 afs_uint32 pagvalue = genpag();
4086 au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
4088 * Note that we leave the 'outexporter' struct held so it won't
4091 au->exporter = outexporter;
4092 if (ablob->out_size >= 4) {
4093 AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32),
4096 afs_PutUser(au, WRITE_LOCK);
4099 return PSETPAG; /* Special return for setpag */
4101 EXP_RELE(outexporter);
4104 *com = (*com) | comp;
4107 #endif /* AFS_NEED_CLIENTCONTEXT */
4111 * VIOC_GETCPREFS (50) - Get client interface
4115 * \param[in] ain sprefrequest input
4116 * \param[out] aout spref information
4118 * \retval EIO Error if the afs daemon hasn't started yet
4119 * \retval EINVAL Error if some of the standard args aren't set
4121 * \post get all interface addresses and other information of the client interface
4123 DECL_PIOCTL(PGetCPrefs)
4125 struct sprefrequest *spin; /* input */
4126 struct sprefinfo *spout; /* output */
4127 struct spref *srvout; /* one output component */
4131 AFS_STATCNT(PGetCPrefs);
4132 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4133 return EIO; /* Inappropriate ioctl for device */
4135 if (ainSize < sizeof(struct sprefrequest))
4138 spin = (struct sprefrequest *)ain;
4139 spout = (struct sprefinfo *)aout;
4141 maxNumber = spin->num_servers; /* max addrs this time */
4142 srvout = spout->servers;
4144 ObtainReadLock(&afs_xinterface);
4146 /* copy out the client interface information from the
4147 ** kernel data structure "interface" to the output buffer
4149 for (i = spin->offset, j = 0; (i < afs_cb_interface.numberOfInterfaces)
4150 && (j < maxNumber); i++, j++, srvout++)
4151 srvout->host.s_addr = afs_cb_interface.addr_in[i];
4153 spout->num_servers = j;
4154 *aoutSize = sizeof(struct sprefinfo) + (j - 1) * sizeof(struct spref);
4156 if (i >= afs_cb_interface.numberOfInterfaces)
4157 spout->next_offset = 0; /* start from beginning again */
4159 spout->next_offset = spin->offset + j;
4161 ReleaseReadLock(&afs_xinterface);
4166 * VIOC_SETCPREFS (51) - Set client interface
4170 * \param[in] ain the interfaces you want set
4171 * \param[out] aout not in use
4173 * \retval EIO Error if the afs daemon hasn't started yet
4174 * \retval EINVAL Error if the input is too large for the struct
4175 * \retval ENOMEM Error if there are too many servers
4177 * \post set the callbak interfaces addresses to those of the hosts
4179 DECL_PIOCTL(PSetCPrefs)
4181 struct setspref *sin;
4184 AFS_STATCNT(PSetCPrefs);
4185 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4186 return EIO; /* Inappropriate ioctl for device */
4188 sin = (struct setspref *)ain;
4190 if (ainSize < sizeof(struct setspref))
4192 #if 0 /* num_servers is unsigned */
4193 if (sin->num_servers < 0)
4196 if (sin->num_servers > AFS_MAX_INTERFACE_ADDR)
4199 ObtainWriteLock(&afs_xinterface, 412);
4200 afs_cb_interface.numberOfInterfaces = sin->num_servers;
4201 for (i = 0; (unsigned short)i < sin->num_servers; i++)
4202 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
4204 ReleaseWriteLock(&afs_xinterface);
4209 * VIOC_AFS_FLUSHMOUNT (52) - Flush mount symlink data
4213 * \param[in] ain the last part of a path to a mount point, which tells us what to flush
4214 * \param[out] aout not in use
4216 * \retval EINVAL Error if some of the initial arguments aren't set
4217 * \retval ENOTDIR Error if the initial argument for the mount point isn't a directory
4218 * \retval ENOENT Error if the dcache entry isn't set
4220 * \post remove all of the mount data from the dcache regarding a certain mount point
4222 DECL_PIOCTL(PFlushMount)
4224 register afs_int32 code;
4225 register struct vcache *tvc;
4226 register struct dcache *tdc;
4227 struct VenusFid tfid;
4229 struct sysname_info sysState;
4230 afs_size_t offset, len;
4232 AFS_STATCNT(PFlushMount);
4235 code = afs_VerifyVCache(avc, areq);
4238 if (vType(avc) != VDIR) {
4241 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
4244 Check_AtSys(avc, ain, &sysState, areq);
4245 ObtainReadLock(&tdc->lock);
4247 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
4248 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
4249 ReleaseReadLock(&tdc->lock);
4250 afs_PutDCache(tdc); /* we're done with the data */
4251 bufp = sysState.name;
4255 tfid.Cell = avc->f.fid.Cell;
4256 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
4257 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
4258 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
4260 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4266 if (tvc->mvstat != 1) {
4271 #ifdef AFS_BOZONLOCK_ENV
4272 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
4274 ObtainWriteLock(&tvc->lock, 649);
4275 ObtainWriteLock(&afs_xcbhash, 650);
4276 afs_DequeueCallback(tvc);
4277 tvc->f.states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
4278 ReleaseWriteLock(&afs_xcbhash);
4279 /* now find the disk cache entries */
4280 afs_TryToSmush(tvc, *acred, 1);
4281 osi_dnlc_purgedp(tvc);
4282 if (tvc->linkData && !(tvc->f.states & CCore)) {
4283 afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
4284 tvc->linkData = NULL;
4286 ReleaseWriteLock(&tvc->lock);
4287 #ifdef AFS_BOZONLOCK_ENV
4288 afs_BozonUnlock(&tvc->pvnLock, tvc);
4292 if (sysState.allocked)
4293 osi_FreeLargeSpace(bufp);
4298 * VIOC_RXSTAT_PROC (53) - Control process RX statistics
4302 * \param[in] ain the flags that control which stats to use
4303 * \param[out] aout not in use
4305 * \retval EACCES Error if the user doesn't have super-user credentials
4306 * \retval EINVAL Error if the flag input is too long
4308 * \post either enable process RPCStats, disable process RPCStats, or clear the process RPCStats
4310 DECL_PIOCTL(PRxStatProc)
4315 if (!afs_osi_suser(*acred)) {
4319 if (ainSize != sizeof(afs_int32)) {
4323 memcpy((char *)&flags, ain, sizeof(afs_int32));
4324 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4328 if (flags & AFSCALL_RXSTATS_ENABLE) {
4329 rx_enableProcessRPCStats();
4331 if (flags & AFSCALL_RXSTATS_DISABLE) {
4332 rx_disableProcessRPCStats();
4334 if (flags & AFSCALL_RXSTATS_CLEAR) {
4335 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
4344 * VIOC_RXSTAT_PEER (54) - Control peer RX statistics
4348 * \param[in] ain the flags that control which statistics to use
4349 * \param[out] aout not in use
4351 * \retval EACCES Error if the user doesn't have super-user credentials
4352 * \retval EINVAL Error if the flag input is too long
4354 * \post either enable peer RPCStatws, disable peer RPCStats, or clear the peer RPCStats
4356 DECL_PIOCTL(PRxStatPeer)
4361 if (!afs_osi_suser(*acred)) {
4365 if (ainSize != sizeof(afs_int32)) {
4369 memcpy((char *)&flags, ain, sizeof(afs_int32));
4370 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4374 if (flags & AFSCALL_RXSTATS_ENABLE) {
4375 rx_enablePeerRPCStats();
4377 if (flags & AFSCALL_RXSTATS_DISABLE) {
4378 rx_disablePeerRPCStats();
4380 if (flags & AFSCALL_RXSTATS_CLEAR) {
4381 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
4388 DECL_PIOCTL(PPrefetchFromTape)
4390 register afs_int32 code, code1;
4392 struct afs_conn *tc;
4393 struct rx_call *tcall;
4394 struct AFSVolSync tsync;
4395 struct AFSFetchStatus OutStatus;
4396 struct AFSCallBack CallBack;
4397 struct VenusFid tfid;
4401 AFS_STATCNT(PSetAcl);
4405 if (ain && (ainSize == 3 * sizeof(afs_int32)))
4406 Fid = (struct AFSFid *)ain;
4408 Fid = &avc->f.fid.Fid;
4409 tfid.Cell = avc->f.fid.Cell;
4410 tfid.Fid.Volume = Fid->Volume;
4411 tfid.Fid.Vnode = Fid->Vnode;
4412 tfid.Fid.Unique = Fid->Unique;
4414 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4416 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4417 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &avc->f.fid);
4420 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4421 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &tvc->f.fid);
4424 tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
4428 tcall = rx_NewCall(tc->id);
4430 StartRXAFS_FetchData(tcall, (struct AFSFid *)&tvc->f.fid.Fid, 0,
4433 bytes = rx_Read(tcall, (char *)aout, sizeof(afs_int32));
4435 EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
4437 code1 = rx_EndCall(tcall, code);
4441 } while (afs_Analyze
4442 (tc, code, &tvc->f.fid, areq, AFS_STATS_FS_RPCIDX_RESIDENCYRPCS,
4443 SHARED_LOCK, NULL));
4444 /* This call is done only to have the callback things handled correctly */
4445 afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
4449 *aoutSize = sizeof(afs_int32);
4456 register afs_int32 code;
4457 struct afs_conn *tc;
4459 struct FsCmdInputs *Inputs;
4460 struct FsCmdOutputs *Outputs;
4461 struct VenusFid tfid;
4464 Inputs = (struct FsCmdInputs *)ain;
4465 Outputs = (struct FsCmdOutputs *)aout;
4468 if (!ain || ainSize != sizeof(struct FsCmdInputs))
4473 Fid = &avc->f.fid.Fid;
4475 tfid.Cell = avc->f.fid.Cell;
4476 tfid.Fid.Volume = Fid->Volume;
4477 tfid.Fid.Vnode = Fid->Vnode;
4478 tfid.Fid.Unique = Fid->Unique;
4480 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4481 afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD, ICL_TYPE_POINTER, tvc,
4482 ICL_TYPE_INT32, Inputs->command, ICL_TYPE_FID, &tfid);
4486 if (Inputs->command) {
4488 tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
4492 RXAFS_FsCmd(tc->id, Fid, Inputs,
4493 (struct FsCmdOutputs *)aout);
4497 } while (afs_Analyze
4498 (tc, code, &tvc->f.fid, areq,
4499 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK, NULL));
4500 /* This call is done to have the callback things handled correctly */
4501 afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4502 } else { /* just a status request, return also link data */
4504 Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4505 Outputs->chars[0] = 0;
4506 if (vType(tvc) == VLNK) {
4507 ObtainWriteLock(&tvc->lock, 555);
4508 if (afs_HandleLink(tvc, areq) == 0)
4509 strncpy((char *)&Outputs->chars, tvc->linkData, MAXCMDCHARS);
4510 ReleaseWriteLock(&tvc->lock);
4517 *aoutSize = sizeof(struct FsCmdOutputs);
4522 DECL_PIOCTL(PNewUuid)
4524 /*AFS_STATCNT(PNewUuid); */
4525 if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4526 return EIO; /* Inappropriate ioctl for device */
4528 if (!afs_osi_suser(acred))
4531 ObtainWriteLock(&afs_xinterface, 555);
4532 afs_uuid_create(&afs_cb_interface.uuid);
4533 ReleaseWriteLock(&afs_xinterface);
4534 ForceAllNewConnections();
4538 #if defined(AFS_CACHE_BYPASS)
4540 DECL_PIOCTL(PSetCachingThreshold)
4545 setting = getting = 1;
4547 if (ain == NULL || ainSize < sizeof(afs_int32))
4553 if (setting == 0 && getting == 0)
4557 * If setting, set first, and return the value now in effect
4560 afs_int32 threshold;
4562 if (!afs_osi_suser(*acred))
4564 memcpy((char *)&threshold, ain, sizeof(afs_int32));
4565 cache_bypass_threshold = threshold;
4566 afs_warn("Cache Bypass Threshold set to: %d\n", threshold);
4567 /* TODO: move to separate pioctl, or enhance pioctl */
4568 cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
4572 /* Return the current size threshold */
4573 afs_int32 oldThreshold = cache_bypass_threshold;
4574 memcpy(aout, (char *)&oldThreshold, sizeof(afs_int32));
4575 *aoutSize = sizeof(afs_int32);
4581 #endif /* defined(AFS_CACHE_BYPASS) */
4583 DECL_PIOCTL(PCallBackAddr)
4586 afs_uint32 addr, code;
4590 struct afs_conn *tc;
4592 struct unixuser *tu;
4593 struct srvAddr **addrs;
4595 /*AFS_STATCNT(PCallBackAddr); */
4596 if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4597 return EIO; /* Inappropriate ioctl for device */
4599 if (!afs_osi_suser(acred))
4602 if (ainSize < sizeof(afs_int32))
4605 memcpy(&addr, ain, sizeof(afs_int32));
4607 ObtainReadLock(&afs_xinterface);
4608 for (i = 0; (unsigned short)i < afs_cb_interface.numberOfInterfaces; i++) {
4609 if (afs_cb_interface.addr_in[i] == addr)
4613 ReleaseWriteLock(&afs_xinterface);
4615 if (afs_cb_interface.addr_in[i] != addr)
4618 ObtainReadLock(&afs_xserver); /* Necessary? */
4619 ObtainReadLock(&afs_xsrvAddr);
4622 for (i = 0; i < NSERVERS; i++) {
4623 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4628 addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
4630 for (i = 0; i < NSERVERS; i++) {
4631 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4632 if (j >= srvAddrCount)
4638 ReleaseReadLock(&afs_xsrvAddr);
4639 ReleaseReadLock(&afs_xserver);
4641 for (i = 0; i < j; i++) {
4647 /* vlserver has no callback conn */
4648 if (sa->sa_portal == AFS_VLPORT) {
4652 if (!ts->cell) /* not really an active server, anyway, it must */
4653 continue; /* have just been added by setsprefs */
4655 /* get a connection, even if host is down; bumps conn ref count */
4656 tu = afs_GetUser(areq->uid, ts->cell->cellNum, SHARED_LOCK);
4657 tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
4658 1 /*force */ , 1 /*create */ , SHARED_LOCK);
4659 afs_PutUser(tu, SHARED_LOCK);
4663 if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(ts)) {
4664 if (sa->sa_flags & SRVADDR_ISDOWN) {
4665 rx_SetConnDeadTime(tc->id, 3);
4667 #ifdef RX_ENABLE_LOCKS
4669 #endif /* RX_ENABLE_LOCKS */
4670 code = RXAFS_CallBackRxConnAddr(tc->id, &addr);
4671 #ifdef RX_ENABLE_LOCKS
4673 #endif /* RX_ENABLE_LOCKS */
4675 afs_PutConn(tc, SHARED_LOCK); /* done with it now */
4676 } /* Outer loop over addrs */
4677 #endif /* UKERNEL */
4681 DECL_PIOCTL(PDiscon)
4683 #ifdef AFS_DISCON_ENV
4684 static afs_int32 mode = 1; /* Start up in 'off' */
4685 afs_int32 force = 0;
4690 if (!afs_osi_suser(*acred))
4696 afs_ConflictPolicy = ain[1] - 1;
4701 * All of these numbers are hard coded in fs.c. If they
4702 * change here, they should change there and vice versa
4705 case 0: /* Disconnect ("offline" mode), breaking all callbacks */
4706 if (!AFS_IS_DISCONNECTED) {
4707 ObtainWriteLock(&afs_discon_lock, 999);
4708 afs_DisconGiveUpCallbacks();
4709 afs_RemoveAllConns();
4710 afs_is_disconnected = 1;
4711 afs_is_discon_rw = 1;
4712 ReleaseWriteLock(&afs_discon_lock);
4715 case 1: /* Fully connected, ("online" mode). */
4716 ObtainWriteLock(&afs_discon_lock, 998);
4719 afs_MarkAllServersUp();
4720 code = afs_ResyncDisconFiles(areq, *acred);
4723 if (code && !force) {
4724 printf("Files not synchronized properly, still in discon state. \n"
4725 "Please retry or use \"force\".\n");
4729 afs_DisconDiscardAll(*acred);
4731 afs_ClearAllStatdFlag();
4732 afs_is_disconnected = 0;
4733 afs_is_discon_rw = 0;
4734 printf("\nSync succeeded. You are back online.\n");
4737 ReleaseWriteLock(&afs_discon_lock);
4746 memcpy(aout, &mode, sizeof(afs_int32));
4747 *aoutSize = sizeof(afs_int32);
4754 DECL_PIOCTL(PNFSNukeCreds)
4756 afs_uint32 addr, code;
4757 register afs_int32 i;
4758 register struct unixuser *tu;
4760 AFS_STATCNT(PUnlog);
4761 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4762 return EIO; /* Inappropriate ioctl for device */
4764 if (ainSize < sizeof(afs_int32))
4766 memcpy(&addr, ain, sizeof(afs_int32));
4768 if ((*acred)->cr_gid == RMTUSER_REQ_PRIV && !addr) {
4769 tu = afs_GetUser(areq->uid, -1, SHARED_LOCK);
4770 if (!tu->exporter || !(addr = EXP_GETHOST(tu->exporter))) {
4771 afs_PutUser(tu, SHARED_LOCK);
4774 afs_PutUser(tu, SHARED_LOCK);
4775 } else if (!afs_osi_suser(acred)) {
4779 ObtainWriteLock(&afs_xuser, 227);
4780 for (i = 0; i < NUSERS; i++) {
4781 for (tu = afs_users[i]; tu; tu = tu->next) {
4782 if (tu->exporter && EXP_CHECKHOST(tu->exporter, addr)) {
4784 tu->states &= ~UHasTokens;
4785 /* security is not having to say you're sorry */
4786 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
4788 ReleaseWriteLock(&afs_xuser);
4789 afs_ResetUserConns(tu);
4791 ObtainWriteLock(&afs_xuser, 228);
4793 /* set the expire times to 0, causes
4794 * afs_GCUserData to remove this entry
4796 tu->ct.EndTimestamp = 0;
4798 #endif /* UKERNEL */
4802 ReleaseWriteLock(&afs_xuser);