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)
688 #endif /* AFS_SGI_ENV */
689 #endif /* AFS_HPUX102_ENV */
691 #if defined(AFS_SGI_ENV)
692 /* "pioctl" system call entry point; just pass argument to the parameterized
701 afs_pioctl(struct pioctlargs *uap, rval_t * rvp)
705 AFS_STATCNT(afs_pioctl);
707 code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
716 #elif defined(AFS_OSF_ENV)
717 afs_pioctl(struct proc *p, void *args, int *retval)
724 } *uap = (struct a *)args;
726 AFS_STATCNT(afs_pioctl);
727 return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow));
730 #elif defined(AFS_FBSD50_ENV)
732 afs_pioctl(struct thread *td, void *args, int *retval)
739 } *uap = (struct a *)args;
741 AFS_STATCNT(afs_pioctl);
742 return (afs_syscall_pioctl
743 (uap->path, uap->cmd, uap->cmarg, uap->follow, td->td_ucred));
746 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
748 afs_pioctl(struct proc *p, void *args, int *retval)
755 } *uap = (struct a *)args;
757 AFS_STATCNT(afs_pioctl);
758 #ifdef AFS_DARWIN80_ENV
759 return (afs_syscall_pioctl
760 (uap->path, uap->cmd, uap->cmarg, uap->follow,
763 return (afs_syscall_pioctl
764 (uap->path, uap->cmd, uap->cmarg, uap->follow,
765 p->p_cred->pc_ucred));
771 /* macro to avoid adding any more #ifdef's to pioctl code. */
772 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
773 #define PIOCTL_FREE_CRED() crfree(credp)
775 #define PIOCTL_FREE_CRED()
780 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
781 rval_t *vvp, struct AFS_UCRED *credp)
783 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
784 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
785 struct AFS_UCRED *credp)
787 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
791 struct afs_ioctl data;
792 #ifdef AFS_NEED_CLIENTCONTEXT
793 struct AFS_UCRED *tmpcred = NULL;
795 struct AFS_UCRED *foreigncreds = NULL;
796 register afs_int32 code = 0;
797 struct vnode *vp = NULL;
799 struct ucred *credp = crref(); /* don't free until done! */
801 #ifdef AFS_LINUX22_ENV
802 cred_t *credp = crref(); /* don't free until done! */
806 AFS_STATCNT(afs_syscall_pioctl);
808 follow = 1; /* compat. with old venus */
809 code = copyin_afs_ioctl(cmarg, &data);
812 #if defined(KERNEL_HAVE_UERROR)
817 if ((com & 0xff) == PSetClientContext) {
818 #ifdef AFS_NEED_CLIENTCONTEXT
819 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
820 code = HandleClientContext(&data, &com, &foreigncreds, credp);
822 code = HandleClientContext(&data, &com, &foreigncreds, osi_curcred());
826 crfree(foreigncreds);
829 #if defined(KERNEL_HAVE_UERROR)
830 return (setuerror(code), code);
835 #else /* AFS_NEED_CLIENTCONTEXT */
837 #endif /* AFS_NEED_CLIENTCONTEXT */
839 #ifdef AFS_NEED_CLIENTCONTEXT
842 * We could have done without temporary setting the u.u_cred below
843 * (foreigncreds could be passed as param the pioctl modules)
844 * but calls such as afs_osi_suser() doesn't allow that since it
845 * references u.u_cred directly. We could, of course, do something
846 * like afs_osi_suser(cred) which, I think, is better since it
847 * generalizes and supports multi cred environments...
849 #if defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
851 credp = foreigncreds;
852 #elif defined(AFS_AIX41_ENV)
853 tmpcred = crref(); /* XXX */
855 #elif defined(AFS_HPUX101_ENV)
856 tmpcred = p_cred(u.u_procp);
857 set_p_cred(u.u_procp, foreigncreds);
858 #elif defined(AFS_SGI_ENV)
859 tmpcred = OSI_GET_CURRENT_CRED();
860 OSI_SET_CURRENT_CRED(foreigncreds);
863 u.u_cred = foreigncreds;
866 #endif /* AFS_NEED_CLIENTCONTEXT */
867 if ((com & 0xff) == 15) {
868 /* special case prefetch so entire pathname eval occurs in helper process.
869 * otherwise, the pioctl call is essentially useless */
870 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
872 Prefetch(path, &data, follow,
873 foreigncreds ? foreigncreds : credp);
875 code = Prefetch(path, &data, follow, osi_curcred());
878 #if defined(KERNEL_HAVE_UERROR)
887 lookupname(path, USR, follow, NULL, &vp,
888 foreigncreds ? foreigncreds : credp);
890 #ifdef AFS_LINUX22_ENV
891 code = gop_lookupname(path, AFS_UIOUSER, follow, &dp);
893 vp = (struct vnode *)dp->d_inode;
895 code = gop_lookupname(path, AFS_UIOUSER, follow, &vp);
896 #endif /* AFS_LINUX22_ENV */
897 #endif /* AFS_AIX41_ENV */
901 #if defined(KERNEL_HAVE_UERROR)
909 #if defined(AFS_SUN510_ENV)
910 if (vp && !IsAfsVnode(vp)) {
911 struct vnode *realvp;
913 #ifdef AFS_SUN511_ENV
914 (VOP_REALVP(vp, &realvp, NULL) == 0)
916 (VOP_REALVP(vp, &realvp) == 0)
919 struct vnode *oldvp = vp;
927 /* now make the call if we were passed no file, or were passed an AFS file */
928 if (!vp || IsAfsVnode(vp)) {
929 #if defined(AFS_SUN5_ENV)
930 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
931 #elif defined(AFS_AIX41_ENV)
933 struct ucred *cred1, *cred2;
936 cred1 = cred2 = foreigncreds;
938 cred1 = cred2 = credp;
940 code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
941 if (cred1 != cred2) {
942 /* something changed the creds */
946 #elif defined(AFS_HPUX101_ENV)
948 struct ucred *cred = p_cred(u.u_procp);
949 code = afs_HandlePioctl(vp, com, &data, follow, &cred);
951 #elif defined(AFS_SGI_ENV)
954 credp = OSI_GET_CURRENT_CRED();
955 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
957 #elif defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
958 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
960 code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
963 #if defined(KERNEL_HAVE_UERROR)
966 code = EINVAL; /* not in /afs */
971 #if defined(AFS_NEED_CLIENTCONTEXT)
974 crset(tmpcred); /* restore original credentials */
976 #if defined(AFS_HPUX101_ENV)
977 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
978 #elif defined(AFS_SGI_ENV)
979 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
980 #elif defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
981 credp = tmpcred; /* restore original credentials */
983 osi_curcred() = tmpcred; /* restore original credentials */
984 #endif /* AFS_HPUX101_ENV */
985 crfree(foreigncreds);
988 #endif /* AFS_NEED_CLIENTCONTEXT */
990 #ifdef AFS_LINUX22_ENV
993 AFS_RELE(vp); /* put vnode back */
997 #if defined(KERNEL_HAVE_UERROR)
1000 return (getuerror());
1006 #define MAXPIOCTLTOKENLEN \
1007 (3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
1010 afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
1011 register struct afs_ioctl *ablob, int afollow,
1012 struct AFS_UCRED **acred)
1015 struct vrequest treq;
1016 register afs_int32 code;
1017 register afs_int32 function, device;
1018 afs_int32 inSize, outSize, outSizeMax;
1019 char *inData, *outData;
1020 pioctlFunction *pioctlSw;
1022 struct afs_fakestat_state fakestate;
1024 avc = avp ? VTOAFS(avp) : NULL;
1025 afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
1026 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
1027 AFS_STATCNT(HandlePioctl);
1028 if ((code = afs_InitReq(&treq, *acred)))
1030 afs_InitFakeStat(&fakestate);
1032 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
1034 afs_PutFakeStat(&fakestate);
1038 device = (acom & 0xff00) >> 8;
1040 case 'V': /* Original pioctls */
1041 pioctlSw = VpioctlSw;
1042 pioctlSwSize = sizeof(VpioctlSw);
1044 case 'C': /* Coordinated/common pioctls */
1045 pioctlSw = CpioctlSw;
1046 pioctlSwSize = sizeof(CpioctlSw);
1048 case 'O': /* Coordinated/common pioctls */
1049 pioctlSw = OpioctlSw;
1050 pioctlSwSize = sizeof(OpioctlSw);
1053 afs_PutFakeStat(&fakestate);
1056 function = acom & 0xff;
1057 if (function >= (pioctlSwSize / sizeof(char *))) {
1058 afs_PutFakeStat(&fakestate);
1059 return EINVAL; /* out of range */
1061 inSize = ablob->in_size;
1063 /* Do all range checking before continuing */
1064 if (inSize > MAXPIOCTLTOKENLEN || inSize < 0 || ablob->out_size < 0)
1067 /* Note that we use osi_Alloc for large allocs and osi_AllocLargeSpace for small ones */
1068 if (inSize > AFS_LRALLOCSIZ) {
1069 inData = osi_Alloc(inSize + 1);
1071 inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1076 AFS_COPYIN(ablob->in, inData, inSize, code);
1077 inData[inSize] = '\0';
1081 if (inSize > AFS_LRALLOCSIZ) {
1082 osi_Free(inData, inSize + 1);
1084 osi_FreeLargeSpace(inData);
1086 afs_PutFakeStat(&fakestate);
1089 if (function == 8 && device == 'V') { /* PGetTokens */
1090 outSizeMax = MAXPIOCTLTOKENLEN;
1091 outData = osi_Alloc(outSizeMax);
1093 outSizeMax = AFS_LRALLOCSIZ;
1094 outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1097 if (inSize > AFS_LRALLOCSIZ) {
1098 osi_Free(inData, inSize + 1);
1100 osi_FreeLargeSpace(inData);
1102 afs_PutFakeStat(&fakestate);
1107 (*pioctlSw[function]) (avc, function, &treq, inData, outData, inSize,
1109 if (inSize > AFS_LRALLOCSIZ) {
1110 osi_Free(inData, inSize + 1);
1112 osi_FreeLargeSpace(inData);
1114 if (code == 0 && ablob->out_size > 0) {
1115 if (outSize > ablob->out_size) {
1116 code = E2BIG; /* data wont fit in user buffer */
1117 } else if (outSize) {
1118 AFS_COPYOUT(outData, ablob->out, outSize, code);
1121 if (outSizeMax > AFS_LRALLOCSIZ) {
1122 osi_Free(outData, outSizeMax);
1124 osi_FreeLargeSpace(outData);
1126 afs_PutFakeStat(&fakestate);
1127 return afs_CheckCode(code, &treq, 41);
1131 * VIOCGETFID (22) - Get file ID quickly
1135 * \param[in] ain not in use
1136 * \param[out] aout fid of requested file
1138 * \retval EINVAL Error if some of the initial arguments aren't set
1140 * \post get the file id of some file
1142 DECL_PIOCTL(PGetFID)
1144 AFS_STATCNT(PGetFID);
1147 memcpy(aout, (char *)&avc->f.fid, sizeof(struct VenusFid));
1148 *aoutSize = sizeof(struct VenusFid);
1153 * VIOCSETAL (1) - Set access control list
1157 * \param[in] ain the ACL being set
1158 * \param[out] aout the ACL being set returned
1160 * \retval EINVAL Error if some of the standard args aren't set
1162 * \post Changed ACL, via direct writing to the wire
1164 int dummy_PSetAcl(char *ain, char *aout)
1169 DECL_PIOCTL(PSetAcl)
1171 register afs_int32 code;
1172 struct afs_conn *tconn;
1173 struct AFSOpaque acl;
1174 struct AFSVolSync tsync;
1175 struct AFSFetchStatus OutStatus;
1178 AFS_STATCNT(PSetAcl);
1181 if ((acl.AFSOpaque_len = strlen(ain) + 1) > 1024 /* AFSOPAQUEMAX */)
1184 acl.AFSOpaque_val = ain;
1186 tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1188 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1191 RXAFS_StoreACL(tconn->id, (struct AFSFid *)&avc->f.fid.Fid,
1192 &acl, &OutStatus, &tsync);
1197 } while (afs_Analyze
1198 (tconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_STOREACL,
1199 SHARED_LOCK, NULL));
1201 /* now we've forgotten all of the access info */
1202 ObtainWriteLock(&afs_xcbhash, 455);
1204 afs_DequeueCallback(avc);
1205 avc->f.states &= ~(CStatd | CUnique);
1206 ReleaseWriteLock(&afs_xcbhash);
1207 if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1208 osi_dnlc_purgedp(avc);
1210 /* SXW - Should we flush metadata here? */
1214 int afs_defaultAsynchrony = 0;
1217 * VIOC_STOREBEHIND (47) Adjust store asynchrony
1221 * \param[in] ain sbstruct (store behind structure) input
1222 * \param[out] aout resulting sbstruct
1224 * \retval EPERM Error if the user doesn't have super-user credentials
1225 * \retval EACCES Error if there isn't enough access to not check the mode bits
1227 * \post sets asynchrony based on a file, from a struct sbstruct "I THINK"
1229 DECL_PIOCTL(PStoreBehind)
1232 struct sbstruct *sbr;
1234 sbr = (struct sbstruct *)ain;
1235 if (sbr->sb_default != -1) {
1236 if (afs_osi_suser(*acred))
1237 afs_defaultAsynchrony = sbr->sb_default;
1242 if (avc && (sbr->sb_thisfile != -1)) {
1244 (avc, PRSFS_WRITE | PRSFS_ADMINISTER, areq, DONT_CHECK_MODE_BITS))
1245 avc->asynchrony = sbr->sb_thisfile;
1250 *aoutSize = sizeof(struct sbstruct);
1251 sbr = (struct sbstruct *)aout;
1252 sbr->sb_default = afs_defaultAsynchrony;
1254 sbr->sb_thisfile = avc->asynchrony;
1261 * VIOC_GCPAGS (48) - Disable automatic PAG gc'ing
1265 * \param[in] ain not in use
1266 * \param[out] aout not in use
1268 * \retval EACCES Error if the user doesn't have super-user credentials
1270 * \post set the gcpags to GCPAGS_USERDISABLED
1272 DECL_PIOCTL(PGCPAGs)
1274 if (!afs_osi_suser(*acred)) {
1277 afs_gcpags = AFS_GCPAGS_USERDISABLED;
1282 * VIOCGETAL (2) - Get access control list
1286 * \param[in] ain not in use
1287 * \param[out] aout the ACL
1289 * \retval EINVAL Error if some of the standard args aren't set
1290 * \retval ERANGE Error if the vnode of the file id is too large
1291 * \retval -1 Error if getting the ACL failed
1293 * \post Obtain the ACL, based on file ID
1295 * \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
1297 DECL_PIOCTL(PGetAcl)
1299 struct AFSOpaque acl;
1300 struct AFSVolSync tsync;
1301 struct AFSFetchStatus OutStatus;
1303 struct afs_conn *tconn;
1307 AFS_STATCNT(PGetAcl);
1310 Fid.Volume = avc->f.fid.Fid.Volume;
1311 Fid.Vnode = avc->f.fid.Fid.Vnode;
1312 Fid.Unique = avc->f.fid.Fid.Unique;
1313 if (avc->f.states & CForeign) {
1315 * For a dfs xlator acl we have a special hack so that the
1316 * xlator will distinguish which type of acl will return. So
1317 * we currently use the top 2-bytes (vals 0-4) to tell which
1318 * type of acl to bring back. Horrible hack but this will
1319 * cause the least number of changes to code size and interfaces.
1321 if (Fid.Vnode & 0xc0000000)
1323 Fid.Vnode |= (ainSize << 30);
1325 acl.AFSOpaque_val = aout;
1327 tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1330 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1332 code = RXAFS_FetchACL(tconn->id, &Fid, &acl, &OutStatus, &tsync);
1337 } while (afs_Analyze
1338 (tconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_FETCHACL,
1339 SHARED_LOCK, NULL));
1342 *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1348 * PNoop returns success. Used for functions which are not implemented or are no longer in use.
1352 * \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
1361 * PBogus returns fail. Used for functions which are not implemented or are no longer in use.
1365 * \retval EINVAL Error if some of the standard args aren't set
1367 * \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;
1371 AFS_STATCNT(PBogus);
1376 * VIOC_FILE_CELL_NAME (30) - Get cell in which file lives
1380 * \param[in] ain not in use (avc used to pass in file id)
1381 * \param[out] aout cell name
1383 * \retval EINVAL Error if some of the standard args aren't set
1384 * \retval ESRCH Error if the file isn't part of a cell
1386 * \post Get a cell based on a passed in file id
1388 DECL_PIOCTL(PGetFileCell)
1390 register struct cell *tcell;
1392 AFS_STATCNT(PGetFileCell);
1395 tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
1398 strcpy(aout, tcell->cellName);
1399 afs_PutCell(tcell, READ_LOCK);
1400 *aoutSize = strlen(aout) + 1;
1405 * VIOC_GET_WS_CELL (31) - Get cell in which workstation lives
1409 * \param[in] ain not in use
1410 * \param[out] aout cell name
1412 * \retval EIO Error if the afs daemon hasn't started yet
1413 * \retval ESRCH Error if the machine isn't part of a cell, for whatever reason
1415 * \post Get the primary cell that the machine is a part of.
1417 DECL_PIOCTL(PGetWSCell)
1419 struct cell *tcell = NULL;
1421 AFS_STATCNT(PGetWSCell);
1422 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1423 return EIO; /* Inappropriate ioctl for device */
1425 tcell = afs_GetPrimaryCell(READ_LOCK);
1426 if (!tcell) /* no primary cell? */
1428 strcpy(aout, tcell->cellName);
1429 *aoutSize = strlen(aout) + 1;
1430 afs_PutCell(tcell, READ_LOCK);
1435 * VIOC_GET_PRIMARY_CELL (33) - Get primary cell for caller
1439 * \param[in] ain not in use (user id found via areq)
1440 * \param[out] aout cell name
1442 * \retval ESRCH Error if the user id doesn't have a primary cell specified
1444 * \post Get the primary cell for a certain user, based on the user's uid
1446 DECL_PIOCTL(PGetUserCell)
1448 register afs_int32 i;
1449 register struct unixuser *tu;
1450 register struct cell *tcell;
1452 AFS_STATCNT(PGetUserCell);
1453 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1454 return EIO; /* Inappropriate ioctl for device */
1456 /* return the cell name of the primary cell for this user */
1457 i = UHash(areq->uid);
1458 ObtainWriteLock(&afs_xuser, 224);
1459 for (tu = afs_users[i]; tu; tu = tu->next) {
1460 if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1462 ReleaseWriteLock(&afs_xuser);
1467 tcell = afs_GetCell(tu->cell, READ_LOCK);
1468 afs_PutUser(tu, WRITE_LOCK);
1472 strcpy(aout, tcell->cellName);
1473 afs_PutCell(tcell, READ_LOCK);
1474 *aoutSize = strlen(aout) + 1; /* 1 for the null */
1477 ReleaseWriteLock(&afs_xuser);
1485 * VIOCSETTOK (3) - Set authentication tokens
1489 * \param[in] ain the krb tickets from which to set the afs tokens
1490 * \param[out] aout not in use
1492 * \retval EINVAL Error if the ticket is either too long or too short
1493 * \retval EIO Error if the AFS initState is below 101
1494 * \retval ESRCH Error if the cell for which the Token is being set can't be found
1496 * \post Set the Tokens for a specific cell name, unless there is none set, then default to primary
1499 DECL_PIOCTL(PSetTokens)
1502 register struct unixuser *tu;
1503 struct ClearToken clear;
1504 register struct cell *tcell;
1507 struct vrequest treq;
1508 afs_int32 flag, set_parent_pag = 0;
1510 AFS_STATCNT(PSetTokens);
1511 if (!afs_resourceinit_flag) {
1514 memcpy((char *)&i, ain, sizeof(afs_int32));
1515 ain += sizeof(afs_int32);
1516 stp = ain; /* remember where the ticket is */
1517 if (i < 0 || i > MAXKTCTICKETLEN)
1518 return EINVAL; /* malloc may fail */
1520 ain += i; /* skip over ticket */
1521 memcpy((char *)&i, ain, sizeof(afs_int32));
1522 ain += sizeof(afs_int32);
1523 if (i != sizeof(struct ClearToken)) {
1526 memcpy((char *)&clear, ain, sizeof(struct ClearToken));
1527 if (clear.AuthHandle == -1)
1528 clear.AuthHandle = 999; /* more rxvab compat stuff */
1529 ain += sizeof(struct ClearToken);
1530 if (ainSize != 2 * sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1531 /* still stuff left? we've got primary flag and cell name. Set these */
1532 memcpy((char *)&flag, ain, sizeof(afs_int32)); /* primary id flag */
1533 ain += sizeof(afs_int32); /* skip id field */
1534 /* rest is cell name, look it up */
1535 /* some versions of gcc appear to need != 0 in order to get this right */
1536 if ((flag & 0x8000) != 0) { /* XXX Use Constant XXX */
1540 tcell = afs_GetCellByName(ain, READ_LOCK);
1544 /* default to primary cell, primary id */
1545 flag = 1; /* primary id */
1546 tcell = afs_GetPrimaryCell(READ_LOCK);
1551 afs_PutCell(tcell, READ_LOCK);
1552 if (set_parent_pag) {
1554 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1555 #if defined(AFS_DARWIN_ENV)
1556 struct proc *p = current_proc(); /* XXX */
1558 struct proc *p = curproc; /* XXX */
1560 #ifndef AFS_DARWIN80_ENV
1561 uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1562 p->p_pid, p->p_comm);
1564 if (!setpag(p, acred, -1, &pag, 1)) {
1567 if (!setpag(u.u_procp, acred, -1, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
1569 if (!setpag(acred, -1, &pag, 1)) {
1572 afs_InitReq(&treq, *acred);
1576 /* now we just set the tokens */
1577 tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1578 tu->vid = clear.ViceId;
1579 if (tu->stp != NULL) {
1580 afs_osi_Free(tu->stp, tu->stLen);
1582 tu->stp = (char *)afs_osi_Alloc(stLen);
1583 if (tu->stp == NULL) {
1587 memcpy(tu->stp, stp, stLen);
1590 afs_stats_cmfullperf.authent.TicketUpdates++;
1591 afs_ComputePAGStats();
1592 #endif /* AFS_NOSTATS */
1593 tu->states |= UHasTokens;
1594 tu->states &= ~UTokensBad;
1595 afs_SetPrimary(tu, flag);
1596 tu->tokenTime = osi_Time();
1597 afs_ResetUserConns(tu);
1598 afs_PutUser(tu, WRITE_LOCK);
1614 * VIOCGETVOLSTAT (4) - Get volume status
1618 * \param[in] ain not in use
1619 * \param[out] aout status of the volume
1621 * \retval EINVAL Error if some of the standard args aren't set
1623 * \post The status of a volume (based on the FID of the volume), or an offline message /motd
1625 DECL_PIOCTL(PGetVolumeStatus)
1628 char *offLineMsg = afs_osi_Alloc(256);
1629 char *motd = afs_osi_Alloc(256);
1630 register struct afs_conn *tc;
1631 register afs_int32 code = 0;
1632 struct AFSFetchVolumeStatus volstat;
1634 char *Name, *OfflineMsg, *MOTD;
1637 AFS_STATCNT(PGetVolumeStatus);
1643 OfflineMsg = offLineMsg;
1646 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1648 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1651 RXAFS_GetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &volstat,
1652 &Name, &OfflineMsg, &MOTD);
1657 } while (afs_Analyze
1658 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1659 SHARED_LOCK, NULL));
1663 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1665 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1666 cp += sizeof(VolumeStatus);
1667 strcpy(cp, volName);
1668 cp += strlen(volName) + 1;
1669 strcpy(cp, offLineMsg);
1670 cp += strlen(offLineMsg) + 1;
1672 cp += strlen(motd) + 1;
1673 *aoutSize = (cp - aout);
1675 afs_osi_Free(offLineMsg, 256);
1676 afs_osi_Free(motd, 256);
1681 * VIOCSETVOLSTAT (5) - Set volume status
1685 * \param[in] ain values to set the status at, offline message, message of the day, volume name, minimum quota, maximum quota
1686 * \param[out] aout status of a volume, offlines messages, minimum quota, maximumm quota
1688 * \retval EINVAL Error if some of the standard args aren't set
1689 * \retval EROFS Error if the volume is read only, or a backup volume
1690 * \retval ENODEV Error if the volume can't be accessed
1691 * \retval E2BIG Error if the volume name, offline message, and motd are too big
1693 * \post Set the status of a volume, including any offline messages, a minimum quota, and a maximum quota
1695 DECL_PIOCTL(PSetVolumeStatus)
1698 char *offLineMsg = afs_osi_Alloc(256);
1699 char *motd = afs_osi_Alloc(256);
1700 register struct afs_conn *tc;
1701 register afs_int32 code = 0;
1702 struct AFSFetchVolumeStatus volstat;
1703 struct AFSStoreVolumeStatus storeStat;
1704 register struct volume *tvp;
1708 AFS_STATCNT(PSetVolumeStatus);
1714 tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
1716 if (tvp->states & (VRO | VBackup)) {
1717 afs_PutVolume(tvp, READ_LOCK);
1721 afs_PutVolume(tvp, READ_LOCK);
1726 /* Copy the junk out, using cp as a roving pointer. */
1728 memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
1729 cp += sizeof(AFSFetchVolumeStatus);
1730 if (strlen(cp) >= sizeof(volName)) {
1734 strcpy(volName, cp);
1735 cp += strlen(volName) + 1;
1736 if (strlen(cp) >= sizeof(offLineMsg)) {
1740 strcpy(offLineMsg, cp);
1741 cp += strlen(offLineMsg) + 1;
1742 if (strlen(cp) >= sizeof(motd)) {
1748 if (volstat.MinQuota != -1) {
1749 storeStat.MinQuota = volstat.MinQuota;
1750 storeStat.Mask |= AFS_SETMINQUOTA;
1752 if (volstat.MaxQuota != -1) {
1753 storeStat.MaxQuota = volstat.MaxQuota;
1754 storeStat.Mask |= AFS_SETMAXQUOTA;
1757 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1759 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1762 RXAFS_SetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &storeStat,
1763 volName, offLineMsg, motd);
1768 } while (afs_Analyze
1769 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1770 SHARED_LOCK, NULL));
1774 /* we are sending parms back to make compat. with prev system. should
1775 * change interface later to not ask for current status, just set new status */
1777 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1778 cp += sizeof(VolumeStatus);
1779 strcpy(cp, volName);
1780 cp += strlen(volName) + 1;
1781 strcpy(cp, offLineMsg);
1782 cp += strlen(offLineMsg) + 1;
1784 cp += strlen(motd) + 1;
1785 *aoutSize = cp - aout;
1787 afs_osi_Free(offLineMsg, 256);
1788 afs_osi_Free(motd, 256);
1793 * VIOCFLUSH (6) - Invalidate cache entry
1797 * \param[in] ain not in use
1798 * \param[out] aout not in use
1800 * \retval EINVAL Error if some of the standard args aren't set
1802 * \post Flush any information the cache manager has on an entry
1806 AFS_STATCNT(PFlush);
1809 #ifdef AFS_BOZONLOCK_ENV
1810 afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
1812 ObtainWriteLock(&avc->lock, 225);
1813 afs_ResetVCache(avc, *acred);
1814 ReleaseWriteLock(&avc->lock);
1815 #ifdef AFS_BOZONLOCK_ENV
1816 afs_BozonUnlock(&avc->pvnLock, avc);
1822 * VIOC_AFS_STAT_MT_PT (29) - Stat mount point
1826 * \param[in] ain the last component in a path, related to mountpoint that we're looking for information about
1827 * \param[out] aout volume, cell, link data
1829 * \retval EINVAL Error if some of the standard args aren't set
1830 * \retval ENOTDIR Error if the 'mount point' argument isn't a directory
1831 * \retval EIO Error if the link data can't be accessed
1833 * \post Get the volume, and cell, as well as the link data for a mount point
1835 DECL_PIOCTL(PNewStatMount)
1837 register afs_int32 code;
1838 register struct vcache *tvc;
1839 register struct dcache *tdc;
1840 struct VenusFid tfid;
1842 struct sysname_info sysState;
1843 afs_size_t offset, len;
1845 AFS_STATCNT(PNewStatMount);
1848 code = afs_VerifyVCache(avc, areq);
1851 if (vType(avc) != VDIR) {
1854 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
1857 Check_AtSys(avc, ain, &sysState, areq);
1858 ObtainReadLock(&tdc->lock);
1860 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
1861 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1862 ReleaseReadLock(&tdc->lock);
1863 afs_PutDCache(tdc); /* we're done with the data */
1864 bufp = sysState.name;
1868 tfid.Cell = avc->f.fid.Cell;
1869 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
1870 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
1871 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
1873 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
1879 if (tvc->mvstat != 1) {
1884 ObtainWriteLock(&tvc->lock, 226);
1885 code = afs_HandleLink(tvc, areq);
1887 if (tvc->linkData) {
1888 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1891 /* we have the data */
1892 strcpy(aout, tvc->linkData);
1893 *aoutSize = strlen(tvc->linkData) + 1;
1898 ReleaseWriteLock(&tvc->lock);
1901 if (sysState.allocked)
1902 osi_FreeLargeSpace(bufp);
1907 * VIOCGETTOK (8) - Get authentication tokens
1911 * \param[in] ain userid
1912 * \param[out] aout token
1914 * \retval EIO Error if the afs daemon hasn't started yet
1915 * \retval EDOM Error if the input parameter is out of the bounds of the available tokens
1916 * \retval ENOTCONN Error if there aren't tokens for this cell
1918 * \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
1920 * \notes "it's a weird interface (from comments in the code)"
1923 DECL_PIOCTL(PGetTokens)
1925 register struct cell *tcell;
1926 register afs_int32 i;
1927 register struct unixuser *tu;
1929 afs_int32 iterator = 0;
1932 AFS_STATCNT(PGetTokens);
1933 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1934 return EIO; /* Inappropriate ioctl for device */
1936 /* weird interface. If input parameter is present, it is an integer and
1937 * we're supposed to return the parm'th tokens for this unix uid.
1938 * If not present, we just return tokens for cell 1.
1939 * If counter out of bounds, return EDOM.
1940 * If no tokens for the particular cell, return ENOTCONN.
1941 * Also, if this mysterious parm is present, we return, along with the
1942 * tokens, the primary cell indicator (an afs_int32 0) and the cell name
1943 * at the end, in that order.
1945 if ((newStyle = (ainSize > 0))) {
1946 memcpy((char *)&iterator, ain, sizeof(afs_int32));
1948 i = UHash(areq->uid);
1949 ObtainReadLock(&afs_xuser);
1950 for (tu = afs_users[i]; tu; tu = tu->next) {
1952 if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1953 if (iterator-- == 0)
1954 break; /* are we done yet? */
1957 if (tu->uid == areq->uid && afs_IsPrimaryCellNum(tu->cell))
1963 * No need to hold a read lock on each user entry
1967 ReleaseReadLock(&afs_xuser);
1972 if (((tu->states & UHasTokens) == 0)
1973 || (tu->ct.EndTimestamp < osi_Time())) {
1974 tu->states |= (UTokensBad | UNeedsReset);
1975 afs_PutUser(tu, READ_LOCK);
1978 /* use iterator for temp */
1980 iterator = tu->stLen; /* for compat, we try to return 56 byte tix if they fit */
1982 iterator = 56; /* # of bytes we're returning */
1983 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1984 cp += sizeof(afs_int32);
1985 memcpy(cp, tu->stp, tu->stLen); /* copy out st */
1987 iterator = sizeof(struct ClearToken);
1988 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1989 cp += sizeof(afs_int32);
1990 memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
1991 cp += sizeof(struct ClearToken);
1993 /* put out primary id and cell name, too */
1994 iterator = (tu->states & UPrimary ? 1 : 0);
1995 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1996 cp += sizeof(afs_int32);
1997 tcell = afs_GetCell(tu->cell, READ_LOCK);
1999 strcpy(cp, tcell->cellName);
2000 cp += strlen(tcell->cellName) + 1;
2001 afs_PutCell(tcell, READ_LOCK);
2005 *aoutSize = cp - aout;
2006 afs_PutUser(tu, READ_LOCK);
2011 * VIOCUNLOG (9) - Invalidate tokens
2015 * \param[in] ain not in use
2016 * \param[out] aout not in use
2018 * \retval EIO Error if the afs daemon hasn't been started yet
2020 * \post remove tokens from a user, specified by the user id
2022 * \notes sets the token's time to 0, which then causes it to be removed
2023 * \notes Unlog is the same as un-pag in OpenAFS
2027 register afs_int32 i;
2028 register struct unixuser *tu;
2030 AFS_STATCNT(PUnlog);
2031 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2032 return EIO; /* Inappropriate ioctl for device */
2034 i = UHash(areq->uid);
2035 ObtainWriteLock(&afs_xuser, 227);
2036 for (tu = afs_users[i]; tu; tu = tu->next) {
2037 if (tu->uid == areq->uid) {
2039 tu->states &= ~UHasTokens;
2040 /* security is not having to say you're sorry */
2041 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
2043 ReleaseWriteLock(&afs_xuser);
2044 /* We have to drop the lock over the call to afs_ResetUserConns, since
2045 * it obtains the afs_xvcache lock. We could also keep the lock, and
2046 * modify ResetUserConns to take parm saying we obtained the lock
2047 * already, but that is overkill. By keeping the "tu" pointer
2048 * held over the released lock, we guarantee that we won't lose our
2049 * place, and that we'll pass over every user conn that existed when
2050 * we began this call.
2052 afs_ResetUserConns(tu);
2054 ObtainWriteLock(&afs_xuser, 228);
2056 /* set the expire times to 0, causes
2057 * afs_GCUserData to remove this entry
2059 tu->ct.EndTimestamp = 0;
2061 #endif /* UKERNEL */
2064 ReleaseWriteLock(&afs_xuser);
2069 * VIOC_AFS_MARINER_HOST (32) - Get/set mariner (cache manager monitor) host
2073 * \param[in] ain host address to be set
2074 * \param[out] aout old host address
2076 * \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
2078 * \notes Errors turn off mariner
2080 DECL_PIOCTL(PMariner)
2082 afs_int32 newHostAddr;
2083 afs_int32 oldHostAddr;
2085 AFS_STATCNT(PMariner);
2087 memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost,
2090 oldHostAddr = 0xffffffff; /* disabled */
2092 memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
2093 if (newHostAddr == 0xffffffff) {
2094 /* disable mariner operations */
2096 } else if (newHostAddr) {
2098 afs_marinerHost = newHostAddr;
2100 memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
2101 *aoutSize = sizeof(afs_int32);
2106 * VIOCCKSERV (10) - Check that servers are up
2110 * \param[in] ain name of the cell
2111 * \param[out] aout current down server list
2113 * \retval EIO Error if the afs daemon hasn't started yet
2114 * \retval EACCES Error if the user doesn't have super-user credentials
2115 * \retval ENOENT Error if we are unable to obtain the cell
2117 * \post Either a fast check (where it doesn't contact servers) or a local check (checks local cell only)
2119 DECL_PIOCTL(PCheckServers)
2121 register char *cp = 0;
2123 register struct server *ts;
2124 afs_int32 temp, *lp = (afs_int32 *) ain, havecell = 0;
2126 struct chservinfo *pcheck;
2128 AFS_STATCNT(PCheckServers);
2130 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2131 return EIO; /* Inappropriate ioctl for device */
2133 if (*lp == 0x12345678) { /* For afs3.3 version */
2134 pcheck = (struct chservinfo *)ain;
2135 if (pcheck->tinterval >= 0) {
2137 memcpy(cp, (char *)&afs_probe_interval, sizeof(afs_int32));
2138 *aoutSize = sizeof(afs_int32);
2139 if (pcheck->tinterval > 0) {
2140 if (!afs_osi_suser(*acred))
2142 afs_probe_interval = pcheck->tinterval;
2148 temp = pcheck->tflags;
2149 cp = pcheck->tbuffer;
2150 } else { /* For pre afs3.3 versions */
2151 memcpy((char *)&temp, ain, sizeof(afs_int32));
2152 cp = ain + sizeof(afs_int32);
2153 if (ainSize > sizeof(afs_int32))
2158 * 1: fast check, don't contact servers.
2159 * 2: local cell only.
2162 /* have cell name, too */
2163 cellp = afs_GetCellByName(cp, READ_LOCK);
2168 if (!cellp && (temp & 2)) {
2169 /* use local cell */
2170 cellp = afs_GetPrimaryCell(READ_LOCK);
2172 if (!(temp & 1)) { /* if not fast, call server checker routine */
2173 afs_CheckServers(1, cellp); /* check down servers */
2174 afs_CheckServers(0, cellp); /* check up servers */
2176 /* now return the current down server list */
2178 ObtainReadLock(&afs_xserver);
2179 for (i = 0; i < NSERVERS; i++) {
2180 for (ts = afs_servers[i]; ts; ts = ts->next) {
2181 if (cellp && ts->cell != cellp)
2182 continue; /* cell spec'd and wrong */
2183 if ((ts->flags & SRVR_ISDOWN)
2184 && ts->addr->sa_portal != ts->cell->vlport) {
2185 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2186 cp += sizeof(afs_int32);
2190 ReleaseReadLock(&afs_xserver);
2192 afs_PutCell(cellp, READ_LOCK);
2193 *aoutSize = cp - aout;
2198 * VIOCCKBACK (11) - Check backup volume mappings
2202 * \param[in] ain not in use
2203 * \param[out] aout not in use
2205 * \retval EIO Error if the afs daemon hasn't started yet
2207 * \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
2209 DECL_PIOCTL(PCheckVolNames)
2211 AFS_STATCNT(PCheckVolNames);
2212 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2213 return EIO; /* Inappropriate ioctl for device */
2215 afs_CheckRootVolume();
2216 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE | AFS_VOLCHECK_EXPIRED |
2217 AFS_VOLCHECK_BUSY | AFS_VOLCHECK_MTPTS);
2222 * VIOCCKCONN (12) - Check connections for a user
2226 * \param[in] ain not in use
2227 * \param[out] aout not in use
2229 * \retval EACCESS Error if no user is specififed, the user has no tokens set, or if the user's tokens are bad
2231 * \post check to see if a user has the correct authentication. If so, allow access.
2233 * \notes Check the connections to all the servers specified
2235 DECL_PIOCTL(PCheckAuth)
2239 struct afs_conn *tc;
2240 struct unixuser *tu;
2243 AFS_STATCNT(PCheckAuth);
2244 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2245 return EIO; /* Inappropriate ioctl for device */
2248 tu = afs_GetUser(areq->uid, 1, READ_LOCK); /* check local cell authentication */
2252 /* we have a user */
2253 ObtainReadLock(&afs_xsrvAddr);
2254 ObtainReadLock(&afs_xconn);
2256 /* any tokens set? */
2257 if ((tu->states & UHasTokens) == 0)
2259 /* all connections in cell 1 working? */
2260 for (i = 0; i < NSERVERS; i++) {
2261 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2262 for (tc = sa->conns; tc; tc = tc->next) {
2263 if (tc->user == tu && (tu->states & UTokensBad))
2268 ReleaseReadLock(&afs_xsrvAddr);
2269 ReleaseReadLock(&afs_xconn);
2270 afs_PutUser(tu, READ_LOCK);
2272 memcpy(aout, (char *)&retValue, sizeof(afs_int32));
2273 *aoutSize = sizeof(afs_int32);
2278 Prefetch(char *apath, struct afs_ioctl *adata, int afollow,
2279 struct AFS_UCRED *acred)
2282 register afs_int32 code;
2283 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
2289 AFS_STATCNT(Prefetch);
2292 tp = osi_AllocLargeSpace(1024);
2293 AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2295 osi_FreeLargeSpace(tp);
2298 if (afs_BBusy()) { /* do this as late as possible */
2299 osi_FreeLargeSpace(tp);
2300 return EWOULDBLOCK; /* pretty close */
2302 afs_BQueue(BOP_PATH, (struct vcache *)0, 0, 0, acred, (afs_size_t) 0,
2303 (afs_size_t) 0, tp);
2308 * VIOCWHEREIS (14) - Find out where a volume is located
2312 * \param[in] ain not in use
2313 * \param[out] aout volume location
2315 * \retval EINVAL Error if some of the default arguments don't exist
2316 * \retval ENODEV Error if there is no such volume
2318 * \post fine a volume, based on a volume file id
2320 * \notes check each of the servers specified
2322 DECL_PIOCTL(PFindVolume)
2324 register struct volume *tvp;
2325 register struct server *ts;
2326 register afs_int32 i;
2329 AFS_STATCNT(PFindVolume);
2332 tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
2335 for (i = 0; i < MAXHOSTS; i++) {
2336 ts = tvp->serverHost[i];
2339 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2340 cp += sizeof(afs_int32);
2343 /* still room for terminating NULL, add it on */
2344 ainSize = 0; /* reuse vbl */
2345 memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
2346 cp += sizeof(afs_int32);
2348 *aoutSize = cp - aout;
2349 afs_PutVolume(tvp, READ_LOCK);
2356 * VIOCACCESS (20) - Access using PRS_FS bits
2360 * \param[in] ain PRS_FS bits
2361 * \param[out] aout not in use
2363 * \retval EINVAL Error if some of the initial arguments aren't set
2364 * \retval EACCES Error if access is denied
2366 * \post check to make sure access is allowed
2368 DECL_PIOCTL(PViceAccess)
2370 register afs_int32 code;
2373 AFS_STATCNT(PViceAccess);
2376 code = afs_VerifyVCache(avc, areq);
2379 memcpy((char *)&temp, ain, sizeof(afs_int32));
2380 code = afs_AccessOK(avc, temp, areq, CHECK_MODE_BITS);
2388 * VIOC_GETPAG (13) - Get PAG value
2392 * \param[in] ain not in use
2393 * \param[out] aout PAG value or NOPAG
2395 * \retval E2BIG Error not enough space to copy out value
2397 * \post get PAG value for the caller's cred
2399 DECL_PIOCTL(PGetPAG)
2403 if (*aoutSize < sizeof(afs_int32)) {
2407 pag = PagInCred(*acred);
2409 memcpy(aout, (char *)&pag, sizeof(afs_int32));
2410 *aoutSize = sizeof(afs_int32);
2414 DECL_PIOCTL(PPrecache)
2418 /*AFS_STATCNT(PPrecache);*/
2419 if (!afs_osi_suser(*acred))
2421 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2422 afs_preCache = newValue*1024;
2427 * VIOCSETCACHESIZE (24) - Set venus cache size in 1000 units
2431 * \param[in] ain the size the venus cache should be set to
2432 * \param[out] aout not in use
2434 * \retval EACCES Error if the user doesn't have super-user credentials
2435 * \retval EROFS Error if the cache is set to be in memory
2437 * \post Set the cache size based on user input. If no size is given, set it to the default OpenAFS cache size.
2439 * \notes recompute the general cache parameters for every single block allocated
2441 DECL_PIOCTL(PSetCacheSize)
2446 AFS_STATCNT(PSetCacheSize);
2447 if (!afs_osi_suser(*acred))
2449 /* too many things are setup initially in mem cache version */
2450 if (cacheDiskType == AFS_FCACHE_TYPE_MEM)
2452 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2454 afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2456 if (newValue < afs_min_cache)
2457 afs_cacheBlocks = afs_min_cache;
2459 afs_cacheBlocks = newValue;
2461 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2462 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2463 afs_MaybeWakeupTruncateDaemon();
2464 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2465 afs_osi_Wait(1000, 0, 0);
2466 afs_MaybeWakeupTruncateDaemon();
2471 #define MAXGCSTATS 16
2473 * VIOCGETCACHEPARMS (40) - Get cache stats
2477 * \param[in] ain afs index flags
2478 * \param[out] aout cache blocks, blocks used, blocks files (in an array)
2480 * \post Get the cache blocks, and how many of the cache blocks there are
2482 DECL_PIOCTL(PGetCacheSize)
2484 afs_int32 results[MAXGCSTATS];
2486 register struct dcache * tdc;
2489 AFS_STATCNT(PGetCacheSize);
2491 if (sizeof(afs_int32) == ainSize){
2492 memcpy((char *)&flags, ain, sizeof(afs_int32));
2493 } else if (0 == ainSize){
2499 memset((char *)results, 0, sizeof(results));
2500 results[0] = afs_cacheBlocks;
2501 results[1] = afs_blocksUsed;
2502 results[2] = afs_cacheFiles;
2505 for (i = 0; i < afs_cacheFiles; i++) {
2506 if (afs_indexFlags[i] & IFFree) results[3]++;
2508 } else if (2 == flags){
2509 for (i = 0; i < afs_cacheFiles; i++) {
2510 if (afs_indexFlags[i] & IFFree) results[3]++;
2511 if (afs_indexFlags[i] & IFEverUsed) results[4]++;
2512 if (afs_indexFlags[i] & IFDataMod) results[5]++;
2513 if (afs_indexFlags[i] & IFDirtyPages) results[6]++;
2514 if (afs_indexFlags[i] & IFAnyPages) results[7]++;
2515 if (afs_indexFlags[i] & IFDiscarded) results[8]++;
2517 tdc = afs_indexTable[i];
2520 size = tdc->validPos;
2521 if ( 0 < size && size < (1<<12) ) results[10]++;
2522 else if (size < (1<<14) ) results[11]++;
2523 else if (size < (1<<16) ) results[12]++;
2524 else if (size < (1<<18) ) results[13]++;
2525 else if (size < (1<<20) ) results[14]++;
2526 else if (size >= (1<<20) ) results[15]++;
2530 memcpy(aout, (char *)results, sizeof(results));
2531 *aoutSize = sizeof(results);
2536 * VIOCFLUSHCB (25) - Flush callback only
2540 * \param[in] ain not in use
2541 * \param[out] aout not in use
2543 * \retval EINVAL Error if some of the standard args aren't set
2544 * \retval 0 0 returned if the volume is set to read-only
2546 * \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.
2548 DECL_PIOCTL(PRemoveCallBack)
2550 register struct afs_conn *tc;
2551 register afs_int32 code = 0;
2552 struct AFSCallBack CallBacks_Array[1];
2553 struct AFSCBFids theFids;
2554 struct AFSCBs theCBs;
2557 AFS_STATCNT(PRemoveCallBack);
2560 if (avc->f.states & CRO)
2561 return 0; /* read-only-ness can't change */
2562 ObtainWriteLock(&avc->lock, 229);
2563 theFids.AFSCBFids_len = 1;
2564 theCBs.AFSCBs_len = 1;
2565 theFids.AFSCBFids_val = (struct AFSFid *)&avc->f.fid.Fid;
2566 theCBs.AFSCBs_val = CallBacks_Array;
2567 CallBacks_Array[0].CallBackType = CB_DROPPED;
2568 if (avc->callback) {
2570 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
2572 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2574 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2578 /* don't set code on failure since we wouldn't use it */
2579 } while (afs_Analyze
2580 (tc, code, &avc->f.fid, areq,
2581 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK, NULL));
2583 ObtainWriteLock(&afs_xcbhash, 457);
2584 afs_DequeueCallback(avc);
2586 avc->f.states &= ~(CStatd | CUnique);
2587 ReleaseWriteLock(&afs_xcbhash);
2588 if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2589 osi_dnlc_purgedp(avc);
2591 ReleaseWriteLock(&avc->lock);
2596 * VIOCNEWCELL (26) - Configure new cell
2600 * \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
2601 * \param[out] aout not in use
2603 * \retval EIO Error if the afs daemon hasn't started yet
2604 * \retval EACCES Error if the user doesn't have super-user cedentials
2605 * \retval EINVAL Error if some 'magic' var doesn't have a certain bit set
2607 * \post creates a new cell
2609 DECL_PIOCTL(PNewCell)
2611 /* create a new cell */
2612 afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic = 0;
2613 char *newcell = 0, *linkedcell = 0, *tp = ain;
2614 register afs_int32 code, linkedstate = 0, ls;
2615 u_short fsport = 0, vlport = 0;
2618 AFS_STATCNT(PNewCell);
2619 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2620 return EIO; /* Inappropriate ioctl for device */
2622 if (!afs_osi_suser(*acred))
2625 memcpy((char *)&magic, tp, sizeof(afs_int32));
2626 tp += sizeof(afs_int32);
2627 if (magic != 0x12345678)
2630 /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2631 * server addresses while the 3.5 fs newcell command passes
2632 * MAXHOSTS. To figure out which is which, check if the cellname
2635 newcell = tp + (MAXCELLHOSTS + 3) * sizeof(afs_int32);
2636 scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2638 /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2639 memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
2640 tp += (scount * sizeof(afs_int32));
2642 lp = (afs_int32 *) tp;
2646 fsport = 0; /* Privileged ports not allowed */
2648 vlport = 0; /* Privileged ports not allowed */
2649 tp += (3 * sizeof(afs_int32));
2651 if ((ls = *lp) & 1) {
2652 linkedcell = tp + strlen(newcell) + 1;
2653 linkedstate |= CLinkedCell;
2656 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2658 afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport,
2663 DECL_PIOCTL(PNewAlias)
2665 /* create a new cell alias */
2667 register afs_int32 code;
2668 char *realName, *aliasName;
2670 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2671 return EIO; /* Inappropriate ioctl for device */
2673 if (!afs_osi_suser(*acred))
2677 tp += strlen(aliasName) + 1;
2680 code = afs_NewCellAlias(aliasName, realName);
2686 * VIOCGETCELL (27) - Get cell info
2690 * \param[in] ain The cell index of a specific cell
2691 * \param[out] aout list of servers in the cell
2693 * \retval EIO Error if the afs daemon hasn't started yet
2694 * \retval EDOM Error if there is no cell asked about
2696 * \post Lists the cell's server names and and addresses
2698 DECL_PIOCTL(PListCells)
2700 afs_int32 whichCell;
2701 register struct cell *tcell = 0;
2702 register afs_int32 i;
2703 register char *cp, *tp = ain;
2705 AFS_STATCNT(PListCells);
2706 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2707 return EIO; /* Inappropriate ioctl for device */
2709 memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2710 tp += sizeof(afs_int32);
2711 tcell = afs_GetCellByIndex(whichCell, READ_LOCK);
2714 memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
2715 for (i = 0; i < MAXCELLHOSTS; i++) {
2716 if (tcell->cellHosts[i] == 0)
2718 memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip,
2720 cp += sizeof(afs_int32);
2722 cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2723 strcpy(cp, tcell->cellName);
2724 cp += strlen(tcell->cellName) + 1;
2725 *aoutSize = cp - aout;
2726 afs_PutCell(tcell, READ_LOCK);
2734 DECL_PIOCTL(PListAliases)
2736 afs_int32 whichAlias;
2737 register struct cell_alias *tcalias = 0;
2738 register char *cp, *tp = ain;
2740 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2741 return EIO; /* Inappropriate ioctl for device */
2742 if (ainSize < sizeof(afs_int32))
2745 memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2746 tp += sizeof(afs_int32);
2748 tcalias = afs_GetCellAlias(whichAlias);
2751 strcpy(cp, tcalias->alias);
2752 cp += strlen(tcalias->alias) + 1;
2753 strcpy(cp, tcalias->cell);
2754 cp += strlen(tcalias->cell) + 1;
2755 *aoutSize = cp - aout;
2756 afs_PutCellAlias(tcalias);
2765 * VIOC_AFS_DELETE_MT_PT (28) - Delete mount point
2769 * \param[in] ain the name of the file in this dir to remove
2770 * \param[out] aout not in use
2772 * \retval EINVAL Error if some of the standard args aren't set
2773 * \retval ENOTDIR Error if the argument to remove is not a directory
2774 * \retval ENOENT Error if there is no cache to remove the mount point from or if a vcache doesn't exist
2776 * \post Ensure that everything is OK before deleting the mountpoint. If not, don't delete. Delete a mount point based on a file id.
2778 DECL_PIOCTL(PRemoveMount)
2780 register afs_int32 code;
2782 struct sysname_info sysState;
2783 afs_size_t offset, len;
2784 register struct afs_conn *tc;
2785 register struct dcache *tdc;
2786 register struct vcache *tvc;
2787 struct AFSFetchStatus OutDirStatus;
2788 struct VenusFid tfid;
2789 struct AFSVolSync tsync;
2793 /* "ain" is the name of the file in this dir to remove */
2795 AFS_STATCNT(PRemoveMount);
2798 code = afs_VerifyVCache(avc, areq);
2801 if (vType(avc) != VDIR)
2804 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1); /* test for error below */
2807 Check_AtSys(avc, ain, &sysState, areq);
2808 ObtainReadLock(&tdc->lock);
2810 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
2811 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2812 ReleaseReadLock(&tdc->lock);
2813 bufp = sysState.name;
2818 tfid.Cell = avc->f.fid.Cell;
2819 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
2820 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
2821 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
2823 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
2830 if (tvc->mvstat != 1) {
2836 ObtainWriteLock(&tvc->lock, 230);
2837 code = afs_HandleLink(tvc, areq);
2839 if (tvc->linkData) {
2840 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2845 ReleaseWriteLock(&tvc->lock);
2846 osi_dnlc_purgedp(tvc);
2852 ObtainWriteLock(&avc->lock, 231);
2853 osi_dnlc_remove(avc, bufp, tvc);
2855 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
2857 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2860 RXAFS_RemoveFile(tc->id, (struct AFSFid *)&avc->f.fid.Fid, bufp,
2861 &OutDirStatus, &tsync);
2866 } while (afs_Analyze
2867 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_REMOVEFILE,
2868 SHARED_LOCK, NULL));
2873 ReleaseWriteLock(&avc->lock);
2877 /* we have the thing in the cache */
2878 ObtainWriteLock(&tdc->lock, 661);
2879 if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2880 /* we can do it locally */
2881 code = afs_dir_Delete(tdc, bufp);
2883 ZapDCE(tdc); /* surprise error -- invalid value */
2887 ReleaseWriteLock(&tdc->lock);
2888 afs_PutDCache(tdc); /* drop ref count */
2890 avc->f.states &= ~CUnique; /* For the dfs xlator */
2891 ReleaseWriteLock(&avc->lock);
2894 if (sysState.allocked)
2895 osi_FreeLargeSpace(bufp);
2900 * VIOC_VENUSLOG (34) - Enable/Disable venus logging
2904 * \retval EINVAL Error if some of the standard args aren't set
2906 * \notes Obsoleted, perhaps should be PBogus
2908 DECL_PIOCTL(PVenusLogging)
2910 return EINVAL; /* OBSOLETE */
2914 * VIOC_GETCELLSTATUS (35) - Get cell status info
2918 * \param[in] ain The cell you want status information on
2919 * \param[out] aout cell state (as a struct)
2921 * \retval EIO Error if the afs daemon hasn't started yet
2922 * \retval ENOENT Error if the cell doesn't exist
2924 * \post Returns the state of the cell as defined in a struct cell
2926 DECL_PIOCTL(PGetCellStatus)
2928 register struct cell *tcell;
2931 AFS_STATCNT(PGetCellStatus);
2932 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2933 return EIO; /* Inappropriate ioctl for device */
2935 tcell = afs_GetCellByName(ain, READ_LOCK);
2938 temp = tcell->states;
2939 afs_PutCell(tcell, READ_LOCK);
2940 memcpy(aout, (char *)&temp, sizeof(afs_int32));
2941 *aoutSize = sizeof(afs_int32);
2946 * VIOC_SETCELLSTATUS (36) - Set corresponding info
2950 * \param[in] ain The cell you want to set information about, and the values you want to set
2951 * \param[out] aout not in use
2953 * \retval EIO Error if the afs daemon hasn't started yet
2954 * \retval EACCES Error if the user doesn't have super-user credentials
2956 * \post Set the state of the cell in a defined struct cell, based on whether or not SetUID is allowed
2958 DECL_PIOCTL(PSetCellStatus)
2960 register struct cell *tcell;
2963 if (!afs_osi_suser(*acred))
2965 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2966 return EIO; /* Inappropriate ioctl for device */
2968 tcell = afs_GetCellByName(ain + 2 * sizeof(afs_int32), WRITE_LOCK);
2971 memcpy((char *)&temp, ain, sizeof(afs_int32));
2973 tcell->states |= CNoSUID;
2975 tcell->states &= ~CNoSUID;
2976 afs_PutCell(tcell, WRITE_LOCK);
2981 * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
2985 * \param[in] ain not in use (args in avc)
2986 * \param[out] aout not in use
2988 * \retval EINVAL Error if some of the standard args aren't set
2989 * \retval EIO Error if the afs daemon hasn't started yet
2991 * \post Wipe everything on the volume. This is done dependent on which platform this is for.
2993 * \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.
2995 DECL_PIOCTL(PFlushVolumeData)
2997 register afs_int32 i;
2998 register struct dcache *tdc;
2999 register struct vcache *tvc;
3000 register struct volume *tv;
3001 afs_int32 cell, volume;
3002 struct afs_q *tq, *uq;
3003 #ifdef AFS_DARWIN80_ENV
3007 AFS_STATCNT(PFlushVolumeData);
3010 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3011 return EIO; /* Inappropriate ioctl for device */
3013 volume = avc->f.fid.Fid.Volume; /* who to zap */
3014 cell = avc->f.fid.Cell;
3017 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
3018 * the vcaches associated with the volume.
3021 ObtainReadLock(&afs_xvcache);
3022 i = VCHashV(&avc->f.fid);
3023 for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
3026 if (tvc->f.fid.Fid.Volume == volume && tvc->f.fid.Cell == cell) {
3027 if (tvc->f.states & CVInit) {
3028 ReleaseReadLock(&afs_xvcache);
3029 afs_osi_Sleep(&tvc->f.states);
3032 #ifdef AFS_DARWIN80_ENV
3033 if (tvc->f.states & CDeadVnode) {
3034 ReleaseReadLock(&afs_xvcache);
3035 afs_osi_Sleep(&tvc->f.states);
3039 #if defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
3040 VN_HOLD(AFSTOV(tvc));
3042 #ifdef AFS_DARWIN80_ENV
3046 if (vnode_ref(vp)) {
3053 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
3056 VREFCOUNT_INC(tvc); /* AIX, apparently */
3060 ReleaseReadLock(&afs_xvcache);
3061 #ifdef AFS_BOZONLOCK_ENV
3062 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3064 ObtainWriteLock(&tvc->lock, 232);
3066 ObtainWriteLock(&afs_xcbhash, 458);
3067 afs_DequeueCallback(tvc);
3068 tvc->f.states &= ~(CStatd | CDirty);
3069 ReleaseWriteLock(&afs_xcbhash);
3070 if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
3071 osi_dnlc_purgedp(tvc);
3072 afs_TryToSmush(tvc, *acred, 1);
3073 ReleaseWriteLock(&tvc->lock);
3074 #ifdef AFS_BOZONLOCK_ENV
3075 afs_BozonUnlock(&tvc->pvnLock, tvc);
3077 #ifdef AFS_DARWIN80_ENV
3078 vnode_put(AFSTOV(tvc));
3080 ObtainReadLock(&afs_xvcache);
3082 /* our tvc ptr is still good until now */
3086 ReleaseReadLock(&afs_xvcache);
3089 MObtainWriteLock(&afs_xdcache, 328); /* needed if you're going to flush any stuff */
3090 for (i = 0; i < afs_cacheFiles; i++) {
3091 if (!(afs_indexFlags[i] & IFEverUsed))
3092 continue; /* never had any data */
3093 tdc = afs_GetDSlot(i, NULL);
3094 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
3095 ReleaseReadLock(&tdc->tlock);
3096 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
3097 if (!(afs_indexFlags[i] & IFDataMod)) {
3098 /* if the file is modified, but has a ref cnt of only 1, then
3099 * someone probably has the file open and is writing into it.
3100 * Better to skip flushing such a file, it will be brought back
3101 * immediately on the next write anyway.
3103 * If we *must* flush, then this code has to be rearranged to call
3104 * afs_storeAllSegments() first */
3105 afs_FlushDCache(tdc);
3109 ReleaseReadLock(&tdc->tlock);
3111 afs_PutDCache(tdc); /* bumped by getdslot */
3113 MReleaseWriteLock(&afs_xdcache);
3115 ObtainReadLock(&afs_xvolume);
3116 for (i = 0; i < NVOLS; i++) {
3117 for (tv = afs_volumes[i]; tv; tv = tv->next) {
3118 if (tv->volume == volume) {
3119 afs_ResetVolumeInfo(tv);
3124 ReleaseReadLock(&afs_xvolume);
3126 /* probably, a user is doing this, probably, because things are screwed up.
3127 * maybe it's the dnlc's fault? */
3134 * VIOCGETVCXSTATUS (41) - gets vnode x status
3138 * \param[in] ain not in use (avc used)
3139 * \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
3141 * \retval EINVAL Error if some of the initial default arguments aren't set
3142 * \retval EACCES Error if access to check the mode bits is denied
3144 * \post gets stats for the vnode, a struct listed in vcxstat
3146 DECL_PIOCTL(PGetVnodeXStatus)
3148 register afs_int32 code;
3149 struct vcxstat stat;
3152 /* AFS_STATCNT(PGetVnodeXStatus); */
3155 code = afs_VerifyVCache(avc, areq);
3158 if (vType(avc) == VDIR)
3159 mode = PRSFS_LOOKUP;
3162 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3165 memset(&stat, 0, sizeof(struct vcxstat));
3166 stat.fid = avc->f.fid;
3167 hset32(stat.DataVersion, hgetlo(avc->f.m.DataVersion));
3168 stat.lock = avc->lock;
3169 stat.parentVnode = avc->f.parent.vnode;
3170 stat.parentUnique = avc->f.parent.unique;
3171 hset(stat.flushDV, avc->flushDV);
3172 hset(stat.mapDV, avc->mapDV);
3173 stat.truncPos = avc->f.truncPos;
3174 { /* just grab the first two - won't break anything... */
3175 struct axscache *ac;
3177 for (i = 0, ac = avc->Access; ac && i < CPSIZE; i++, ac = ac->next) {
3178 stat.randomUid[i] = ac->uid;
3179 stat.randomAccess[i] = ac->axess;
3182 stat.callback = afs_data_pointer_to_int32(avc->callback);
3183 stat.cbExpires = avc->cbExpires;
3184 stat.anyAccess = avc->f.anyAccess;
3185 stat.opens = avc->opens;
3186 stat.execsOrWriters = avc->execsOrWriters;
3187 stat.flockCount = avc->flockCount;
3188 stat.mvstat = avc->mvstat;
3189 stat.states = avc->f.states;
3190 memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
3191 *aoutSize = sizeof(struct vcxstat);
3196 DECL_PIOCTL(PGetVnodeXStatus2)
3198 register afs_int32 code;
3199 struct vcxstat2 stat;
3204 code = afs_VerifyVCache(avc, areq);
3207 if (vType(avc) == VDIR)
3208 mode = PRSFS_LOOKUP;
3211 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3214 memset(&stat, 0, sizeof(struct vcxstat2));
3216 stat.cbExpires = avc->cbExpires;
3217 stat.anyAccess = avc->f.anyAccess;
3218 stat.mvstat = avc->mvstat;
3219 stat.callerAccess = afs_GetAccessBits(avc, ~0, areq);
3221 memcpy(aout, (char *)&stat, sizeof(struct vcxstat2));
3222 *aoutSize = sizeof(struct vcxstat2);
3228 * VIOC_AFS_SYSNAME (38) - Change @sys value
3232 * \param[in] ain new value for @sys
3233 * \param[out] aout count, entry, list (debug values?)
3235 * \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"
3236 * \retval ENODEV Error if there isn't already a system named that ("I THINK")
3237 * \retval EACCES Error if the user doesn't have super-user credentials
3239 * \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
3241 * \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.
3243 DECL_PIOCTL(PSetSysName)
3245 char *cp, *cp2 = NULL, inname[MAXSYSNAME], outname[MAXSYSNAME];
3246 afs_int32 setsysname;
3248 register struct afs_exporter *exporter;
3249 register struct unixuser *au;
3250 register afs_int32 pag, error;
3251 int t, count, num = 0, allpags = 0;
3254 AFS_STATCNT(PSetSysName);
3255 if (!afs_globalVFS) {
3256 /* Afsd is NOT running; disable it */
3257 #if defined(KERNEL_HAVE_UERROR)
3258 return (setuerror(EINVAL), EINVAL);
3263 memset(inname, 0, MAXSYSNAME);
3264 memcpy(&setsysname, ain, sizeof(afs_int32));
3265 ain += sizeof(afs_int32);
3266 if (setsysname & 0x8000) {
3268 setsysname &= ~0x8000;
3273 if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
3276 for (cp = ain, count = 0; count < setsysname; count++) {
3277 /* won't go past end of ain since maxsysname*num < ain length */
3279 if (t >= MAXSYSNAME || t <= 0)
3281 /* check for names that can shoot us in the foot */
3282 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
3288 /* inname gets first entry in case we're being a translator */
3290 memcpy(inname, ain, t + 1); /* include terminating null */
3294 if ((*acred)->cr_gid == RMTUSER_REQ ||
3295 (*acred)->cr_gid == RMTUSER_REQ_PRIV) { /* Handles all exporters */
3296 if (allpags && (*acred)->cr_gid != RMTUSER_REQ_PRIV) {
3299 pag = PagInCred(*acred);
3301 return EINVAL; /* Better than panicing */
3303 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
3304 return EINVAL; /* Better than panicing */
3306 if (!(exporter = au->exporter)) {
3307 afs_PutUser(au, READ_LOCK);
3308 return EINVAL; /* Better than panicing */
3310 error = EXP_SYSNAME(exporter, (setsysname ? cp2 : NULL), &sysnamelist,
3313 if (error == ENODEV)
3314 foundname = 0; /* sysname not set yet! */
3316 afs_PutUser(au, READ_LOCK);
3321 strcpy(outname, sysnamelist[0]);
3323 afs_PutUser(au, READ_LOCK);
3327 /* Not xlating, so local case */
3329 osi_Panic("PSetSysName: !afs_sysname\n");
3330 if (!setsysname) { /* user just wants the info */
3331 strcpy(outname, afs_sysname);
3332 foundname = afs_sysnamecount;
3333 sysnamelist = afs_sysnamelist;
3334 } else { /* Local guy; only root can change sysname */
3335 if (!afs_osi_suser(*acred))
3338 /* allpags makes no sense for local use */
3342 /* clear @sys entries from the dnlc, once afs_lookup can
3343 * do lookups of @sys entries and thinks it can trust them */
3344 /* privs ok, store the entry, ... */
3345 strcpy(afs_sysname, inname);
3346 if (setsysname > 1) { /* ... or list */
3348 for (count = 1; count < setsysname; ++count) {
3349 if (!afs_sysnamelist[count])
3351 ("PSetSysName: no afs_sysnamelist entry to write\n");
3353 memcpy(afs_sysnamelist[count], cp, t + 1); /* include null */
3357 afs_sysnamecount = setsysname;
3362 cp = aout; /* not changing so report back the count and ... */
3363 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
3364 cp += sizeof(afs_int32);
3366 strcpy(cp, outname); /* ... the entry, ... */
3367 cp += strlen(outname) + 1;
3368 for (count = 1; count < foundname; ++count) { /* ... or list. */
3369 if (!sysnamelist[count])
3371 ("PSetSysName: no afs_sysnamelist entry to read\n");
3372 t = strlen(sysnamelist[count]);
3373 if (t >= MAXSYSNAME)
3374 osi_Panic("PSetSysName: sysname entry garbled\n");
3375 strcpy(cp, sysnamelist[count]);
3379 *aoutSize = cp - aout;
3384 /* sequential search through the list of touched cells is not a good
3385 * long-term solution here. For small n, though, it should be just
3386 * fine. Should consider special-casing the local cell for large n.
3387 * Likewise for PSetSPrefs.
3389 * s - number of ids in array l[] -- NOT index of last id
3390 * l - array of cell ids which have volumes that need to be sorted
3391 * vlonly - sort vl servers or file servers?
3394 ReSortCells_cb(struct cell *cell, void *arg)
3396 afs_int32 *p = (afs_int32 *) arg;
3397 afs_int32 *l = p + 1;
3400 for (i = 0; i < s; i++) {
3401 if (l[i] == cell->cellNum) {
3402 ObtainWriteLock(&cell->lock, 690);
3403 afs_SortServers(cell->cellHosts, MAXCELLHOSTS);
3404 ReleaseWriteLock(&cell->lock);
3412 ReSortCells(int s, afs_int32 * l, int vlonly)
3420 p = (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * (s + 1));
3422 memcpy(p + 1, l, s * sizeof(afs_int32));
3423 afs_TraverseCells(&ReSortCells_cb, p);
3424 afs_osi_Free(p, sizeof(afs_int32) * (s + 1));
3428 ObtainReadLock(&afs_xvolume);
3429 for (i = 0; i < NVOLS; i++) {
3430 for (j = afs_volumes[i]; j; j = j->next) {
3431 for (k = 0; k < s; k++)
3432 if (j->cell == l[k]) {
3433 ObtainWriteLock(&j->lock, 233);
3434 afs_SortServers(j->serverHost, MAXHOSTS);
3435 ReleaseWriteLock(&j->lock);
3440 ReleaseReadLock(&afs_xvolume);
3444 static int debugsetsp = 0;
3446 afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
3449 int i, j, k, matches, touchedSize;
3450 struct server *srvr = NULL;
3451 afs_int32 touched[34];
3455 for (k = 0; k < num; sp++, k++) {
3457 printf("sp host=%x, rank=%d\n", sp->host.s_addr, sp->rank);
3460 ObtainReadLock(&afs_xserver);
3462 i = SHash(sp->host.s_addr);
3463 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
3464 if (sa->sa_ip == sp->host.s_addr) {
3466 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3467 || (sa->sa_portal == AFS_FSPORT);
3468 if ((!vlonly && isfs) || (vlonly && !isfs)) {
3475 if (sa && matches) { /* found one! */
3477 printf("sa ip=%x, ip_rank=%d\n", sa->sa_ip, sa->sa_iprank);
3479 sa->sa_iprank = sp->rank + afs_randomMod15();
3480 afs_SortOneServer(sa->server);
3483 /* if we don't know yet what cell it's in, this is moot */
3484 for (j = touchedSize - 1;
3485 j >= 0 && touched[j] != srvr->cell->cellNum; j--)
3486 /* is it in our list of touched cells ? */ ;
3487 if (j < 0) { /* no, it's not */
3488 touched[touchedSize++] = srvr->cell->cellNum;
3489 if (touchedSize >= 32) { /* watch for ovrflow */
3490 ReleaseReadLock(&afs_xserver);
3491 ReSortCells(touchedSize, touched, vlonly);
3493 ObtainReadLock(&afs_xserver);
3499 ReleaseReadLock(&afs_xserver);
3500 /* if we didn't find one, start to create one. */
3501 /* Note that it doesn't have a cell yet... */
3503 afs_uint32 temp = sp->host.s_addr;
3505 afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
3506 WRITE_LOCK, (afsUUID *) 0, 0);
3507 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3508 afs_PutServer(srvr, WRITE_LOCK);
3510 } /* for all cited preferences */
3512 ReSortCells(touchedSize, touched, vlonly);
3517 * VIOC_SETPREFS (46) - Set server ranks
3519 * \param[in] ain the sprefs value you want the sprefs to be set to
3520 * \param[out] aout not in use
3522 * \retval EIO Error if the afs daemon hasn't started yet
3523 * \retval EACCES Error if the user doesn't have super-user credentials
3524 * \retval EINVAL Error if the struct setsprefs is too large or if it multiplied by the number of servers is too large
3526 * \post set the sprefs using the afs_setsprefs() function
3528 DECL_PIOCTL(PSetSPrefs)
3530 struct setspref *ssp;
3531 AFS_STATCNT(PSetSPrefs);
3533 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3534 return EIO; /* Inappropriate ioctl for device */
3536 if (!afs_osi_suser(*acred))
3539 if (ainSize < sizeof(struct setspref))
3542 ssp = (struct setspref *)ain;
3543 if (ainSize < sizeof(struct spref) * ssp->num_servers)
3546 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
3547 (ssp->flags & DBservers));
3552 * VIOC_SETPREFS33 (42) - Set server ranks (deprecated)
3554 * \param[in] ain the server preferences to be set
3555 * \param[out] aout not in use
3557 * \retval EIO Error if the afs daemon hasn't started yet
3558 * \retval EACCES Error if the user doesn't have super-user credentials
3560 * \post set the server preferences, calling a function
3562 * \notes this may only be performed by the local root user.
3564 DECL_PIOCTL(PSetSPrefs33)
3567 AFS_STATCNT(PSetSPrefs);
3568 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3569 return EIO; /* Inappropriate ioctl for device */
3572 if (!afs_osi_suser(*acred))
3575 sp = (struct spref *)ain;
3576 afs_setsprefs(sp, ainSize / (sizeof(struct spref)), 0 /*!vlonly */ );
3581 * VIOC_GETSPREFS (43) - Get server ranks
3585 * \param[in] ain the server preferences to get
3586 * \param[out] aout the server preferences information
3588 * \retval EIO Error if the afs daemon hasn't started yet
3589 * \retval ENOENT Error if the sprefrequest is too large
3591 * \post Get the sprefs
3593 * \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.
3595 DECL_PIOCTL(PGetSPrefs)
3597 struct sprefrequest *spin; /* input */
3598 struct sprefinfo *spout; /* output */
3599 struct spref *srvout; /* one output component */
3600 int i, j; /* counters for hash table traversal */
3601 struct server *srvr; /* one of CM's server structs */
3603 int vlonly; /* just return vlservers ? */
3606 AFS_STATCNT(PGetSPrefs);
3607 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3608 return EIO; /* Inappropriate ioctl for device */
3611 if (ainSize < sizeof(struct sprefrequest_33)) {
3614 spin = ((struct sprefrequest *)ain);
3617 if (ainSize > sizeof(struct sprefrequest_33)) {
3618 vlonly = (spin->flags & DBservers);
3622 /* struct sprefinfo includes 1 server struct... that size gets added
3623 * in during the loop that follows.
3625 *aoutSize = sizeof(struct sprefinfo) - sizeof(struct spref);
3626 spout = (struct sprefinfo *)aout;
3627 spout->next_offset = spin->offset;
3628 spout->num_servers = 0;
3629 srvout = spout->servers;
3631 ObtainReadLock(&afs_xserver);
3632 for (i = 0, j = 0; j < NSERVERS; j++) { /* sift through hash table */
3633 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3634 if (spin->offset > (unsigned short)i) {
3635 continue; /* catch up to where we left off */
3637 spout->next_offset++;
3640 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3641 || (sa->sa_portal == AFS_FSPORT);
3643 if ((vlonly && isfs) || (!vlonly && !isfs)) {
3644 /* only report ranks for vl servers */
3648 srvout->host.s_addr = sa->sa_ip;
3649 srvout->rank = sa->sa_iprank;
3650 *aoutSize += sizeof(struct spref);
3651 spout->num_servers++;
3654 if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3655 ReleaseReadLock(&afs_xserver); /* no more room! */
3660 ReleaseReadLock(&afs_xserver);
3662 spout->next_offset = 0; /* start over from the beginning next time */
3666 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3667 int afs_NFSRootOnly = 1;
3669 * VIOC_EXPORTAFS (39) - Export afs to nfs clients
3673 * \param[in] ain a struct Vic * EIOctl containing export values needed to change between nfs and afs
3674 * \param[out] aout a struct of the exporter states (exporter->exp_states)
3676 * \retval ENODEV Error if the exporter doesn't exist
3677 * \retval EACCES Error if the user doesn't have super-user credentials
3679 * \post Changes the state of various values to reflect the change of the export values between nfs and afs.
3681 * \notes Legacy code obtained from IBM.
3683 DECL_PIOCTL(PExportAfs)
3685 afs_int32 export, newint =
3686 0, type, changestate, handleValue, convmode, pwsync, smounts;
3687 afs_int32 rempags = 0, pagcb = 0;
3688 register struct afs_exporter *exporter;
3690 AFS_STATCNT(PExportAfs);
3691 memcpy((char *)&handleValue, ain, sizeof(afs_int32));
3692 type = handleValue >> 24;
3697 exporter = exporter_find(type);
3699 export = handleValue & 3;
3700 changestate = handleValue & 0xfff;
3701 smounts = (handleValue >> 2) & 3;
3702 pwsync = (handleValue >> 4) & 3;
3703 convmode = (handleValue >> 6) & 3;
3704 rempags = (handleValue >> 8) & 3;
3705 pagcb = (handleValue >> 10) & 3;
3707 changestate = (handleValue >> 16) & 0x1;
3708 convmode = (handleValue >> 16) & 0x2;
3709 pwsync = (handleValue >> 16) & 0x4;
3710 smounts = (handleValue >> 16) & 0x8;
3711 export = handleValue & 0xff;
3714 /* Failed finding desired exporter; */
3718 handleValue = exporter->exp_states;
3719 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3720 *aoutSize = sizeof(afs_int32);
3722 if (!afs_osi_suser(*acred))
3723 return EACCES; /* Only superuser can do this */
3727 exporter->exp_states |= EXP_EXPORTED;
3729 exporter->exp_states &= ~EXP_EXPORTED;
3733 exporter->exp_states |= EXP_UNIXMODE;
3735 exporter->exp_states &= ~EXP_UNIXMODE;
3739 exporter->exp_states |= EXP_PWSYNC;
3741 exporter->exp_states &= ~EXP_PWSYNC;
3745 afs_NFSRootOnly = 0;
3746 exporter->exp_states |= EXP_SUBMOUNTS;
3748 afs_NFSRootOnly = 1;
3749 exporter->exp_states &= ~EXP_SUBMOUNTS;
3754 exporter->exp_states |= EXP_CLIPAGS;
3756 exporter->exp_states &= ~EXP_CLIPAGS;
3760 exporter->exp_states |= EXP_CALLBACK;
3762 exporter->exp_states &= ~EXP_CALLBACK;
3764 handleValue = exporter->exp_states;
3765 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3766 *aoutSize = sizeof(afs_int32);
3769 exporter->exp_states |= EXP_EXPORTED;
3771 exporter->exp_states &= ~EXP_EXPORTED;
3773 exporter->exp_states |= EXP_UNIXMODE;
3775 exporter->exp_states &= ~EXP_UNIXMODE;
3777 exporter->exp_states |= EXP_PWSYNC;
3779 exporter->exp_states &= ~EXP_PWSYNC;
3781 afs_NFSRootOnly = 0;
3782 exporter->exp_states |= EXP_SUBMOUNTS;
3784 afs_NFSRootOnly = 1;
3785 exporter->exp_states &= ~EXP_SUBMOUNTS;
3794 * VIOC_GAG (44) - Silence Cache Manager
3798 * \param[in] ain the flags to either gag or de-gag the cache manager
3799 * \param[out] aout not in use
3801 * \retval EACCES Error if the user doesn't have super-user credentials
3803 * \post set the gag flags, then show these flags
3807 struct gaginfo *gagflags;
3809 if (!afs_osi_suser(*acred))
3812 gagflags = (struct gaginfo *)ain;
3813 afs_showflags = gagflags->showflags;
3819 * VIOC_TWIDDLE (45) - Adjust RX knobs
3823 * \param[in] ain the previous settings of the 'knobs'
3824 * \param[out] aout not in use
3826 * \retval EACCES Error if the user doesn't have super-user credentials
3828 * \post build out the struct rxp, from a struct rx
3830 DECL_PIOCTL(PTwiddleRx)
3832 struct rxparams *rxp;
3834 if (!afs_osi_suser(*acred))
3837 rxp = (struct rxparams *)ain;
3839 if (rxp->rx_initReceiveWindow)
3840 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3841 if (rxp->rx_maxReceiveWindow)
3842 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3843 if (rxp->rx_initSendWindow)
3844 rx_initSendWindow = rxp->rx_initSendWindow;
3845 if (rxp->rx_maxSendWindow)
3846 rx_maxSendWindow = rxp->rx_maxSendWindow;
3847 if (rxp->rxi_nSendFrags)
3848 rxi_nSendFrags = rxp->rxi_nSendFrags;
3849 if (rxp->rxi_nRecvFrags)
3850 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3851 if (rxp->rxi_OrphanFragSize)
3852 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3853 if (rxp->rx_maxReceiveSize) {
3854 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3855 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3857 if (rxp->rx_MyMaxSendSize)
3858 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3864 * VIOC_GETINITPARAMS (49) - Get initial cache manager parameters
3868 * \param[in] ain not in use
3869 * \param[out] aout initial cache manager params
3871 * \retval E2BIG Error if the initial parameters are bigger than some PIGGYSIZE
3873 * \post return the initial cache manager parameters
3875 DECL_PIOCTL(PGetInitParams)
3877 if (sizeof(struct cm_initparams) > PIGGYSIZE)
3880 memcpy(aout, (char *)&cm_initParams, sizeof(struct cm_initparams));
3881 *aoutSize = sizeof(struct cm_initparams);
3885 #ifdef AFS_SGI65_ENV
3886 /* They took crget() from us, so fake it. */
3891 cr = crdup(get_current_cred());
3892 memset((char *)cr, 0, sizeof(cred_t));
3893 #if CELL || CELL_PREPARE
3901 * VIOC_GETRXKCRYPT (55) - Get rxkad encryption flag
3905 * \param[in] ain not in use
3906 * \param[out] aout value of cryptall
3908 * \post get the value of cryptall (presumably whether or not things should be encrypted)
3910 DECL_PIOCTL(PGetRxkcrypt)
3912 memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3913 *aoutSize = sizeof(afs_int32);
3918 * VIOC_SETRXKCRYPT (56) - Set rxkad encryption flag
3922 * \param[in] ain the argument whether or not things should be encrypted
3923 * \param[out] aout not in use
3925 * \retval EPERM Error if the user doesn't have super-user credentials
3926 * \retval EINVAL Error if the input is too big, or if the input is outside the bounds of what it can be set to
3928 * \post set whether or not things should be encrypted
3930 * \notes may need to be modified at a later date to take into account other values for cryptall (beyond true or false)
3932 DECL_PIOCTL(PSetRxkcrypt)
3936 if (!afs_osi_suser(*acred))
3938 if (ainSize != sizeof(afs_int32) || ain == NULL)
3940 memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3941 /* if new mappings added later this will need to be changed */
3942 if (tmpval != 0 && tmpval != 1)
3948 #ifdef AFS_NEED_CLIENTCONTEXT
3950 * Create new credentials to correspond to a remote user with given
3951 * <hostaddr, uid, g0, g1>. This allows a server running as root to
3952 * provide pioctl (and other) services to foreign clients (i.e. nfs
3953 * clients) by using this call to `become' the client.
3956 #define PIOCTL_HEADER 6
3958 HandleClientContext(struct afs_ioctl *ablob, int *com,
3959 struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3962 afs_uint32 hostaddr;
3963 afs_int32 uid, g0, g1, i, code, pag, exporter_type, isroot = 0;
3964 struct afs_exporter *exporter, *outexporter;
3965 struct AFS_UCRED *newcred;
3966 struct unixuser *au;
3967 afs_uint32 comp = *com & 0xff00;
3970 #if defined(AFS_SGIMP_ENV)
3971 osi_Assert(ISAFS_GLOCK());
3973 AFS_STATCNT(HandleClientContext);
3974 if (ablob->in_size < PIOCTL_HEADER * sizeof(afs_int32)) {
3975 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3976 return EINVAL; /* Too small to be good */
3978 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3979 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER * sizeof(afs_int32), code);
3981 osi_FreeLargeSpace(inData);
3985 /* Extract information for remote user */
3986 hostaddr = *((afs_uint32 *) ain);
3987 ain += sizeof(hostaddr);
3988 uid = *((afs_uint32 *) ain);
3990 g0 = *((afs_uint32 *) ain);
3992 g1 = *((afs_uint32 *) ain);
3994 *com = *((afs_uint32 *) ain);
3995 ain += sizeof(afs_int32);
3996 exporter_type = *((afs_uint32 *) ain); /* In case we support more than NFS */
3999 * Of course, one must be root for most of these functions, but
4000 * we'll allow (for knfs) you to set things if the pag is 0 and
4001 * you're setting tokens or unlogging.
4004 if (!afs_osi_suser(credp)) {
4005 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI64_ENV)
4006 /* Since SGI's suser() returns explicit failure after the call.. */
4009 /* check for acceptable opcodes for normal folks, which are, so far,
4010 * get/set tokens, sysname, and unlog.
4012 if (i != 9 && i != 3 && i != 38 && i != 8) {
4013 osi_FreeLargeSpace(inData);
4018 ablob->in_size -= PIOCTL_HEADER * sizeof(afs_int32);
4019 ablob->in += PIOCTL_HEADER * sizeof(afs_int32);
4020 osi_FreeLargeSpace(inData);
4023 * We map uid 0 to nobody to match the mapping that the nfs
4024 * server does and to ensure that the suser() calls in the afs
4025 * code fails for remote client roots.
4027 uid = afs_nobody; /* NFS_NOBODY == -2 */
4031 #ifdef AFS_AIX41_ENV
4034 newcred->cr_gid = isroot ? RMTUSER_REQ_PRIV : RMTUSER_REQ;
4035 #ifdef AFS_AIX51_ENV
4036 newcred->cr_groupset.gs_union.un_groups[0] = g0;
4037 newcred->cr_groupset.gs_union.un_groups[1] = g1;
4038 #elif defined(AFS_LINUX26_ENV)
4039 #ifdef AFS_LINUX26_ONEGROUP_ENV
4040 newcred->cr_group_info = groups_alloc(1); /* not that anything sets this */
4041 l = (((g0-0x3f00) & 0x3fff) << 14) | ((g1-0x3f00) & 0x3fff);
4042 h = ((g0-0x3f00) >> 14);
4043 h = ((g1-0x3f00) >> 14) + h + h + h;
4044 GROUP_AT(newcred->cr_group_info, 0) = ((h << 28) | l);
4046 newcred->cr_group_info = groups_alloc(2);
4047 GROUP_AT(newcred->cr_group_info, 0) = g0;
4048 GROUP_AT(newcred->cr_group_info, 1) = g1;
4051 newcred->cr_groups[0] = g0;
4052 newcred->cr_groups[1] = g1;
4055 newcred->cr_ngrps = 2;
4056 #elif !defined(AFS_LINUX26_ENV)
4057 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
4058 newcred->cr_ngroups = 2;
4060 for (i = 2; i < NGROUPS; i++)
4061 newcred->cr_groups[i] = NOGROUP;
4064 #if !defined(AFS_OSF_ENV)
4065 afs_nfsclient_init(); /* before looking for exporter, ensure one exists */
4067 if (!(exporter = exporter_find(exporter_type))) {
4068 /* Exporter wasn't initialized or an invalid exporter type */
4072 if (exporter->exp_states & EXP_PWSYNC) {
4073 if (uid != credp->cr_uid) {
4075 return ENOEXEC; /* XXX Find a better errno XXX */
4078 newcred->cr_uid = uid; /* Only temporary */
4079 code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
4080 /* The client's pag is the only unique identifier for it */
4081 newcred->cr_uid = pag;
4083 if (!code && *com == PSETPAG) {
4084 /* Special case for 'setpag' */
4085 afs_uint32 pagvalue = genpag();
4087 au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
4089 * Note that we leave the 'outexporter' struct held so it won't
4092 au->exporter = outexporter;
4093 if (ablob->out_size >= 4) {
4094 AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32),
4097 afs_PutUser(au, WRITE_LOCK);
4100 return PSETPAG; /* Special return for setpag */
4102 EXP_RELE(outexporter);
4105 *com = (*com) | comp;
4108 #endif /* AFS_NEED_CLIENTCONTEXT */
4112 * VIOC_GETCPREFS (50) - Get client interface
4116 * \param[in] ain sprefrequest input
4117 * \param[out] aout spref information
4119 * \retval EIO Error if the afs daemon hasn't started yet
4120 * \retval EINVAL Error if some of the standard args aren't set
4122 * \post get all interface addresses and other information of the client interface
4124 DECL_PIOCTL(PGetCPrefs)
4126 struct sprefrequest *spin; /* input */
4127 struct sprefinfo *spout; /* output */
4128 struct spref *srvout; /* one output component */
4132 AFS_STATCNT(PGetCPrefs);
4133 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4134 return EIO; /* Inappropriate ioctl for device */
4136 if (ainSize < sizeof(struct sprefrequest))
4139 spin = (struct sprefrequest *)ain;
4140 spout = (struct sprefinfo *)aout;
4142 maxNumber = spin->num_servers; /* max addrs this time */
4143 srvout = spout->servers;
4145 ObtainReadLock(&afs_xinterface);
4147 /* copy out the client interface information from the
4148 ** kernel data structure "interface" to the output buffer
4150 for (i = spin->offset, j = 0; (i < afs_cb_interface.numberOfInterfaces)
4151 && (j < maxNumber); i++, j++, srvout++)
4152 srvout->host.s_addr = afs_cb_interface.addr_in[i];
4154 spout->num_servers = j;
4155 *aoutSize = sizeof(struct sprefinfo) + (j - 1) * sizeof(struct spref);
4157 if (i >= afs_cb_interface.numberOfInterfaces)
4158 spout->next_offset = 0; /* start from beginning again */
4160 spout->next_offset = spin->offset + j;
4162 ReleaseReadLock(&afs_xinterface);
4167 * VIOC_SETCPREFS (51) - Set client interface
4171 * \param[in] ain the interfaces you want set
4172 * \param[out] aout not in use
4174 * \retval EIO Error if the afs daemon hasn't started yet
4175 * \retval EINVAL Error if the input is too large for the struct
4176 * \retval ENOMEM Error if there are too many servers
4178 * \post set the callbak interfaces addresses to those of the hosts
4180 DECL_PIOCTL(PSetCPrefs)
4182 struct setspref *sin;
4185 AFS_STATCNT(PSetCPrefs);
4186 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4187 return EIO; /* Inappropriate ioctl for device */
4189 sin = (struct setspref *)ain;
4191 if (ainSize < sizeof(struct setspref))
4193 #if 0 /* num_servers is unsigned */
4194 if (sin->num_servers < 0)
4197 if (sin->num_servers > AFS_MAX_INTERFACE_ADDR)
4200 ObtainWriteLock(&afs_xinterface, 412);
4201 afs_cb_interface.numberOfInterfaces = sin->num_servers;
4202 for (i = 0; (unsigned short)i < sin->num_servers; i++)
4203 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
4205 ReleaseWriteLock(&afs_xinterface);
4210 * VIOC_AFS_FLUSHMOUNT (52) - Flush mount symlink data
4214 * \param[in] ain the last part of a path to a mount point, which tells us what to flush
4215 * \param[out] aout not in use
4217 * \retval EINVAL Error if some of the initial arguments aren't set
4218 * \retval ENOTDIR Error if the initial argument for the mount point isn't a directory
4219 * \retval ENOENT Error if the dcache entry isn't set
4221 * \post remove all of the mount data from the dcache regarding a certain mount point
4223 DECL_PIOCTL(PFlushMount)
4225 register afs_int32 code;
4226 register struct vcache *tvc;
4227 register struct dcache *tdc;
4228 struct VenusFid tfid;
4230 struct sysname_info sysState;
4231 afs_size_t offset, len;
4233 AFS_STATCNT(PFlushMount);
4236 code = afs_VerifyVCache(avc, areq);
4239 if (vType(avc) != VDIR) {
4242 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
4245 Check_AtSys(avc, ain, &sysState, areq);
4246 ObtainReadLock(&tdc->lock);
4248 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
4249 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
4250 ReleaseReadLock(&tdc->lock);
4251 afs_PutDCache(tdc); /* we're done with the data */
4252 bufp = sysState.name;
4256 tfid.Cell = avc->f.fid.Cell;
4257 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
4258 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
4259 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
4261 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4267 if (tvc->mvstat != 1) {
4272 #ifdef AFS_BOZONLOCK_ENV
4273 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
4275 ObtainWriteLock(&tvc->lock, 649);
4276 ObtainWriteLock(&afs_xcbhash, 650);
4277 afs_DequeueCallback(tvc);
4278 tvc->f.states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
4279 ReleaseWriteLock(&afs_xcbhash);
4280 /* now find the disk cache entries */
4281 afs_TryToSmush(tvc, *acred, 1);
4282 osi_dnlc_purgedp(tvc);
4283 if (tvc->linkData && !(tvc->f.states & CCore)) {
4284 afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
4285 tvc->linkData = NULL;
4287 ReleaseWriteLock(&tvc->lock);
4288 #ifdef AFS_BOZONLOCK_ENV
4289 afs_BozonUnlock(&tvc->pvnLock, tvc);
4293 if (sysState.allocked)
4294 osi_FreeLargeSpace(bufp);
4299 * VIOC_RXSTAT_PROC (53) - Control process RX statistics
4303 * \param[in] ain the flags that control which stats to use
4304 * \param[out] aout not in use
4306 * \retval EACCES Error if the user doesn't have super-user credentials
4307 * \retval EINVAL Error if the flag input is too long
4309 * \post either enable process RPCStats, disable process RPCStats, or clear the process RPCStats
4311 DECL_PIOCTL(PRxStatProc)
4316 if (!afs_osi_suser(*acred)) {
4320 if (ainSize != sizeof(afs_int32)) {
4324 memcpy((char *)&flags, ain, sizeof(afs_int32));
4325 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4329 if (flags & AFSCALL_RXSTATS_ENABLE) {
4330 rx_enableProcessRPCStats();
4332 if (flags & AFSCALL_RXSTATS_DISABLE) {
4333 rx_disableProcessRPCStats();
4335 if (flags & AFSCALL_RXSTATS_CLEAR) {
4336 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
4345 * VIOC_RXSTAT_PEER (54) - Control peer RX statistics
4349 * \param[in] ain the flags that control which statistics to use
4350 * \param[out] aout not in use
4352 * \retval EACCES Error if the user doesn't have super-user credentials
4353 * \retval EINVAL Error if the flag input is too long
4355 * \post either enable peer RPCStatws, disable peer RPCStats, or clear the peer RPCStats
4357 DECL_PIOCTL(PRxStatPeer)
4362 if (!afs_osi_suser(*acred)) {
4366 if (ainSize != sizeof(afs_int32)) {
4370 memcpy((char *)&flags, ain, sizeof(afs_int32));
4371 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4375 if (flags & AFSCALL_RXSTATS_ENABLE) {
4376 rx_enablePeerRPCStats();
4378 if (flags & AFSCALL_RXSTATS_DISABLE) {
4379 rx_disablePeerRPCStats();
4381 if (flags & AFSCALL_RXSTATS_CLEAR) {
4382 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
4389 DECL_PIOCTL(PPrefetchFromTape)
4391 register afs_int32 code, code1;
4393 struct afs_conn *tc;
4394 struct rx_call *tcall;
4395 struct AFSVolSync tsync;
4396 struct AFSFetchStatus OutStatus;
4397 struct AFSCallBack CallBack;
4398 struct VenusFid tfid;
4402 AFS_STATCNT(PSetAcl);
4406 if (ain && (ainSize == 3 * sizeof(afs_int32)))
4407 Fid = (struct AFSFid *)ain;
4409 Fid = &avc->f.fid.Fid;
4410 tfid.Cell = avc->f.fid.Cell;
4411 tfid.Fid.Volume = Fid->Volume;
4412 tfid.Fid.Vnode = Fid->Vnode;
4413 tfid.Fid.Unique = Fid->Unique;
4415 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4417 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4418 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &avc->f.fid);
4421 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4422 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &tvc->f.fid);
4425 tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
4429 tcall = rx_NewCall(tc->id);
4431 StartRXAFS_FetchData(tcall, (struct AFSFid *)&tvc->f.fid.Fid, 0,
4434 bytes = rx_Read(tcall, (char *)aout, sizeof(afs_int32));
4436 EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
4438 code1 = rx_EndCall(tcall, code);
4442 } while (afs_Analyze
4443 (tc, code, &tvc->f.fid, areq, AFS_STATS_FS_RPCIDX_RESIDENCYRPCS,
4444 SHARED_LOCK, NULL));
4445 /* This call is done only to have the callback things handled correctly */
4446 afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
4450 *aoutSize = sizeof(afs_int32);
4457 register afs_int32 code;
4458 struct afs_conn *tc;
4460 struct FsCmdInputs *Inputs;
4461 struct FsCmdOutputs *Outputs;
4462 struct VenusFid tfid;
4465 Inputs = (struct FsCmdInputs *)ain;
4466 Outputs = (struct FsCmdOutputs *)aout;
4469 if (!ain || ainSize != sizeof(struct FsCmdInputs))
4474 Fid = &avc->f.fid.Fid;
4476 tfid.Cell = avc->f.fid.Cell;
4477 tfid.Fid.Volume = Fid->Volume;
4478 tfid.Fid.Vnode = Fid->Vnode;
4479 tfid.Fid.Unique = Fid->Unique;
4481 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4482 afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD, ICL_TYPE_POINTER, tvc,
4483 ICL_TYPE_INT32, Inputs->command, ICL_TYPE_FID, &tfid);
4487 if (Inputs->command) {
4489 tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
4493 RXAFS_FsCmd(tc->id, Fid, Inputs,
4494 (struct FsCmdOutputs *)aout);
4498 } while (afs_Analyze
4499 (tc, code, &tvc->f.fid, areq,
4500 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK, NULL));
4501 /* This call is done to have the callback things handled correctly */
4502 afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4503 } else { /* just a status request, return also link data */
4505 Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4506 Outputs->chars[0] = 0;
4507 if (vType(tvc) == VLNK) {
4508 ObtainWriteLock(&tvc->lock, 555);
4509 if (afs_HandleLink(tvc, areq) == 0)
4510 strncpy((char *)&Outputs->chars, tvc->linkData, MAXCMDCHARS);
4511 ReleaseWriteLock(&tvc->lock);
4518 *aoutSize = sizeof(struct FsCmdOutputs);
4523 DECL_PIOCTL(PNewUuid)
4525 /*AFS_STATCNT(PNewUuid); */
4526 if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4527 return EIO; /* Inappropriate ioctl for device */
4529 if (!afs_osi_suser(acred))
4532 ObtainWriteLock(&afs_xinterface, 555);
4533 afs_uuid_create(&afs_cb_interface.uuid);
4534 ReleaseWriteLock(&afs_xinterface);
4535 ForceAllNewConnections();
4539 #if defined(AFS_CACHE_BYPASS)
4541 DECL_PIOCTL(PSetCachingThreshold)
4546 setting = getting = 1;
4548 if (ain == NULL || ainSize < sizeof(afs_int32))
4554 if (setting == 0 && getting == 0)
4558 * If setting, set first, and return the value now in effect
4561 afs_int32 threshold;
4563 if (!afs_osi_suser(*acred))
4565 memcpy((char *)&threshold, ain, sizeof(afs_int32));
4566 cache_bypass_threshold = threshold;
4567 afs_warn("Cache Bypass Threshold set to: %d\n", threshold);
4568 /* TODO: move to separate pioctl, or enhance pioctl */
4569 cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
4573 /* Return the current size threshold */
4574 afs_int32 oldThreshold = cache_bypass_threshold;
4575 memcpy(aout, (char *)&oldThreshold, sizeof(afs_int32));
4576 *aoutSize = sizeof(afs_int32);
4582 #endif /* defined(AFS_CACHE_BYPASS) */
4584 DECL_PIOCTL(PCallBackAddr)
4587 afs_uint32 addr, code;
4591 struct afs_conn *tc;
4593 struct unixuser *tu;
4594 struct srvAddr **addrs;
4596 /*AFS_STATCNT(PCallBackAddr); */
4597 if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4598 return EIO; /* Inappropriate ioctl for device */
4600 if (!afs_osi_suser(acred))
4603 if (ainSize < sizeof(afs_int32))
4606 memcpy(&addr, ain, sizeof(afs_int32));
4608 ObtainReadLock(&afs_xinterface);
4609 for (i = 0; (unsigned short)i < afs_cb_interface.numberOfInterfaces; i++) {
4610 if (afs_cb_interface.addr_in[i] == addr)
4614 ReleaseWriteLock(&afs_xinterface);
4616 if (afs_cb_interface.addr_in[i] != addr)
4619 ObtainReadLock(&afs_xserver); /* Necessary? */
4620 ObtainReadLock(&afs_xsrvAddr);
4623 for (i = 0; i < NSERVERS; i++) {
4624 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4629 addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
4631 for (i = 0; i < NSERVERS; i++) {
4632 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4633 if (j >= srvAddrCount)
4639 ReleaseReadLock(&afs_xsrvAddr);
4640 ReleaseReadLock(&afs_xserver);
4642 for (i = 0; i < j; i++) {
4648 /* vlserver has no callback conn */
4649 if (sa->sa_portal == AFS_VLPORT) {
4653 if (!ts->cell) /* not really an active server, anyway, it must */
4654 continue; /* have just been added by setsprefs */
4656 /* get a connection, even if host is down; bumps conn ref count */
4657 tu = afs_GetUser(areq->uid, ts->cell->cellNum, SHARED_LOCK);
4658 tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
4659 1 /*force */ , 1 /*create */ , SHARED_LOCK);
4660 afs_PutUser(tu, SHARED_LOCK);
4664 if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(ts)) {
4665 if (sa->sa_flags & SRVADDR_ISDOWN) {
4666 rx_SetConnDeadTime(tc->id, 3);
4668 #ifdef RX_ENABLE_LOCKS
4670 #endif /* RX_ENABLE_LOCKS */
4671 code = RXAFS_CallBackRxConnAddr(tc->id, &addr);
4672 #ifdef RX_ENABLE_LOCKS
4674 #endif /* RX_ENABLE_LOCKS */
4676 afs_PutConn(tc, SHARED_LOCK); /* done with it now */
4677 } /* Outer loop over addrs */
4678 #endif /* UKERNEL */
4682 DECL_PIOCTL(PDiscon)
4684 #ifdef AFS_DISCON_ENV
4685 static afs_int32 mode = 1; /* Start up in 'off' */
4686 afs_int32 force = 0;
4691 if (!afs_osi_suser(*acred))
4697 afs_ConflictPolicy = ain[1] - 1;
4702 * All of these numbers are hard coded in fs.c. If they
4703 * change here, they should change there and vice versa
4706 case 0: /* Disconnect ("offline" mode), breaking all callbacks */
4707 if (!AFS_IS_DISCONNECTED) {
4708 ObtainWriteLock(&afs_discon_lock, 999);
4709 afs_DisconGiveUpCallbacks();
4710 afs_RemoveAllConns();
4711 afs_is_disconnected = 1;
4712 afs_is_discon_rw = 1;
4713 ReleaseWriteLock(&afs_discon_lock);
4716 case 1: /* Fully connected, ("online" mode). */
4717 ObtainWriteLock(&afs_discon_lock, 998);
4720 afs_MarkAllServersUp();
4721 code = afs_ResyncDisconFiles(areq, *acred);
4724 if (code && !force) {
4725 printf("Files not synchronized properly, still in discon state. \n"
4726 "Please retry or use \"force\".\n");
4730 afs_DisconDiscardAll(*acred);
4732 afs_ClearAllStatdFlag();
4733 afs_is_disconnected = 0;
4734 afs_is_discon_rw = 0;
4735 printf("\nSync succeeded. You are back online.\n");
4738 ReleaseWriteLock(&afs_discon_lock);
4747 memcpy(aout, &mode, sizeof(afs_int32));
4748 *aoutSize = sizeof(afs_int32);
4755 DECL_PIOCTL(PNFSNukeCreds)
4757 afs_uint32 addr, code;
4758 register afs_int32 i;
4759 register struct unixuser *tu;
4761 AFS_STATCNT(PUnlog);
4762 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4763 return EIO; /* Inappropriate ioctl for device */
4765 if (ainSize < sizeof(afs_int32))
4767 memcpy(&addr, ain, sizeof(afs_int32));
4769 if ((*acred)->cr_gid == RMTUSER_REQ_PRIV && !addr) {
4770 tu = afs_GetUser(areq->uid, -1, SHARED_LOCK);
4771 if (!tu->exporter || !(addr = EXP_GETHOST(tu->exporter))) {
4772 afs_PutUser(tu, SHARED_LOCK);
4775 afs_PutUser(tu, SHARED_LOCK);
4776 } else if (!afs_osi_suser(acred)) {
4780 ObtainWriteLock(&afs_xuser, 227);
4781 for (i = 0; i < NUSERS; i++) {
4782 for (tu = afs_users[i]; tu; tu = tu->next) {
4783 if (tu->exporter && EXP_CHECKHOST(tu->exporter, addr)) {
4785 tu->states &= ~UHasTokens;
4786 /* security is not having to say you're sorry */
4787 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
4789 ReleaseWriteLock(&afs_xuser);
4790 afs_ResetUserConns(tu);
4792 ObtainWriteLock(&afs_xuser, 228);
4794 /* set the expire times to 0, causes
4795 * afs_GCUserData to remove this entry
4797 tu->ct.EndTimestamp = 0;
4799 #endif /* UKERNEL */
4803 ReleaseWriteLock(&afs_xuser);