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