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,
144 afs_ucred_t **acred);
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)
385 # ifdef AFS_AIX32_ENV
386 # ifdef AFS_AIX51_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)
404 # ifdef AFS_AIX51_ENV
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_FBSD50_ENV)
423 afs_xioctl(struct thread *td, register struct ioctl_args *uap,
426 afs_proc_t *p = td->td_proc;
427 # elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
435 afs_xioctl(afs_proc_t *p, register struct ioctl_args *uap, register_t *retval)
437 # elif defined(AFS_LINUX22_ENV)
438 struct afs_ioctl_sys {
443 afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
446 struct afs_ioctl_sys ua, *uap = &ua;
455 } *uap = (struct a *)u.u_ap;
456 # endif /* AFS_SUN5_ENV */
458 # if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
460 # elif !defined(AFS_LINUX22_ENV)
461 register struct file *fd;
463 # if defined(AFS_XBSD_ENV)
464 register struct filedesc *fdp;
466 register struct vcache *tvc;
467 register int ioctlDone = 0, code = 0;
469 AFS_STATCNT(afs_xioctl);
470 # if defined(AFS_DARWIN_ENV)
471 if ((code = fdgetf(p, uap->fd, &fd)))
473 # elif defined(AFS_XBSD_ENV)
475 if ((u_int) uap->fd >= fdp->fd_nfiles
476 || (fd = fdp->fd_ofiles[uap->fd]) == NULL)
478 if ((fd->f_flag & (FREAD | FWRITE)) == 0)
480 # elif defined(AFS_LINUX22_ENV)
483 # elif defined(AFS_AIX32_ENV)
487 # ifdef AFS_AIX51_ENV
491 if (setuerror(getf(uap->fd, &fd))) {
494 # elif defined(AFS_SUN5_ENV)
495 # if defined(AFS_SUN57_ENV)
499 # elif defined(AFS_SUN54_ENV)
504 if (code = getf(uap->fd, &fd)) {
507 # endif /* AFS_SUN57_ENV */
513 /* first determine whether this is any sort of vnode */
514 # if defined(AFS_LINUX22_ENV)
519 if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
521 if (fd->f_type == DTYPE_VNODE) {
523 /* good, this is a vnode; next see if it is an AFS vnode */
524 # if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
525 tvc = VTOAFS(fd->f_vnode); /* valid, given a vnode */
526 # elif defined(AFS_OBSD_ENV)
528 IsAfsVnode((struct vnode *)fd->
529 f_data) ? VTOAFS((struct vnode *)fd->f_data) : NULL;
531 tvc = VTOAFS((struct vnode *)fd->f_data); /* valid, given a vnode */
533 # endif /* AFS_LINUX22_ENV */
534 if (tvc && IsAfsVnode(AFSTOV(tvc))) {
535 /* This is an AFS vnode */
536 if (((uap->com >> 8) & 0xff) == 'V') {
537 register struct afs_ioctl *datap;
540 (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
541 code=copyin_afs_ioctl((char *)uap->arg, datap);
543 osi_FreeSmallSpace(datap);
545 # if defined(AFS_AIX41_ENV)
547 # elif defined(AFS_SUN54_ENV)
549 # elif defined(AFS_SUN5_ENV)
553 # if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
555 # elif defined(AFS_SUN5_ENV)
557 # elif defined(AFS_LINUX22_ENV)
560 return (setuerror(code), code);
563 code = HandleIoctl(tvc, uap->com, datap);
564 osi_FreeSmallSpace(datap);
567 # if defined(AFS_AIX41_ENV)
571 # if defined(AFS_LINUX22_ENV)
579 # if defined(AFS_AIX41_ENV)
581 # ifdef AFS_AIX51_ENV
583 code = okioctl(fdes, com, arg, ext, arg2, arg3);
584 # else /* __64BIT__ */
585 code = okioctl32(fdes, com, arg, ext, arg2, arg3);
586 # endif /* __64BIT__ */
587 # else /* !AFS_AIX51_ENV */
588 code = okioctl(fdes, com, arg, ext);
589 # endif /* AFS_AIX51_ENV */
591 # elif defined(AFS_AIX32_ENV)
592 okioctl(fdes, com, arg, ext);
593 # elif defined(AFS_SUN5_ENV)
594 # if defined(AFS_SUN57_ENV)
596 # elif defined(AFS_SUN54_ENV)
601 code = ioctl(uap, rvp);
602 # elif defined(AFS_FBSD50_ENV)
603 return ioctl(td, uap);
604 # elif defined(AFS_FBSD_ENV)
605 return ioctl(p, uap);
606 # elif defined(AFS_OBSD_ENV)
607 code = sys_ioctl(p, uap, retval);
608 # elif defined(AFS_DARWIN_ENV)
609 return ioctl(p, uap, retval);
610 # elif !defined(AFS_LINUX22_ENV)
616 # ifdef AFS_SUN54_ENV
622 # elif defined(AFS_LINUX22_ENV)
624 # elif defined(KERNEL_HAVE_UERROR)
627 # if defined(AFS_AIX32_ENV) && !defined(AFS_AIX41_ENV)
628 return (getuerror()? -1 : u.u_ioctlrv);
630 return getuerror()? -1 : 0;
634 # if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
640 # endif /* AFS_SGI_ENV */
641 #endif /* AFS_HPUX102_ENV */
643 #if defined(AFS_SGI_ENV)
644 /* "pioctl" system call entry point; just pass argument to the parameterized
653 afs_pioctl(struct pioctlargs *uap, rval_t * rvp)
657 AFS_STATCNT(afs_pioctl);
659 code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
661 # ifdef AFS_SGI64_ENV
668 #elif defined(AFS_FBSD50_ENV)
670 afs_pioctl(struct thread *td, void *args, int *retval)
677 } *uap = (struct a *)args;
679 AFS_STATCNT(afs_pioctl);
680 return (afs_syscall_pioctl
681 (uap->path, uap->cmd, uap->cmarg, uap->follow, td->td_ucred));
684 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
686 afs_pioctl(afs_proc_t *p, void *args, int *retval)
693 } *uap = (struct a *)args;
695 AFS_STATCNT(afs_pioctl);
696 # ifdef AFS_DARWIN80_ENV
697 return (afs_syscall_pioctl
698 (uap->path, uap->cmd, uap->cmarg, uap->follow,
701 return (afs_syscall_pioctl
702 (uap->path, uap->cmd, uap->cmarg, uap->follow,
703 p->p_cred->pc_ucred));
709 /* macro to avoid adding any more #ifdef's to pioctl code. */
710 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
711 #define PIOCTL_FREE_CRED() crfree(credp)
713 #define PIOCTL_FREE_CRED()
718 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
719 rval_t *vvp, afs_ucred_t *credp)
721 #ifdef AFS_DARWIN100_ENV
722 afs_syscall64_pioctl(user_addr_t path, unsigned int com, user_addr_t cmarg,
723 int follow, afs_ucred_t *credp)
724 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
725 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
728 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
732 struct afs_ioctl data;
733 #ifdef AFS_NEED_CLIENTCONTEXT
734 afs_ucred_t *tmpcred = NULL;
736 #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)
737 afs_ucred_t *foreigncreds = NULL;
739 register afs_int32 code = 0;
740 struct vnode *vp = NULL;
742 struct ucred *credp = crref(); /* don't free until done! */
744 #ifdef AFS_LINUX22_ENV
745 cred_t *credp = crref(); /* don't free until done! */
749 AFS_STATCNT(afs_syscall_pioctl);
751 follow = 1; /* compat. with old venus */
752 code = copyin_afs_ioctl(cmarg, &data);
755 #if defined(KERNEL_HAVE_UERROR)
760 if ((com & 0xff) == PSetClientContext) {
761 #ifdef AFS_NEED_CLIENTCONTEXT
762 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
763 code = HandleClientContext(&data, &com, &foreigncreds, credp);
765 code = HandleClientContext(&data, &com, &foreigncreds, osi_curcred());
769 crfree(foreigncreds);
772 #if defined(KERNEL_HAVE_UERROR)
773 return (setuerror(code), code);
778 #else /* AFS_NEED_CLIENTCONTEXT */
780 #endif /* AFS_NEED_CLIENTCONTEXT */
782 #ifdef AFS_NEED_CLIENTCONTEXT
785 * We could have done without temporary setting the u.u_cred below
786 * (foreigncreds could be passed as param the pioctl modules)
787 * but calls such as afs_osi_suser() doesn't allow that since it
788 * references u.u_cred directly. We could, of course, do something
789 * like afs_osi_suser(cred) which, I think, is better since it
790 * generalizes and supports multi cred environments...
792 #if defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
794 credp = foreigncreds;
795 #elif defined(AFS_AIX41_ENV)
796 tmpcred = crref(); /* XXX */
798 #elif defined(AFS_HPUX101_ENV)
799 tmpcred = p_cred(u.u_procp);
800 set_p_cred(u.u_procp, foreigncreds);
801 #elif defined(AFS_SGI_ENV)
802 tmpcred = OSI_GET_CURRENT_CRED();
803 OSI_SET_CURRENT_CRED(foreigncreds);
806 u.u_cred = foreigncreds;
809 #endif /* AFS_NEED_CLIENTCONTEXT */
810 if ((com & 0xff) == 15) {
811 /* special case prefetch so entire pathname eval occurs in helper process.
812 * otherwise, the pioctl call is essentially useless */
813 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
815 Prefetch(path, &data, follow,
816 foreigncreds ? foreigncreds : credp);
818 code = Prefetch(path, &data, follow, osi_curcred());
821 #if defined(KERNEL_HAVE_UERROR)
830 lookupname(path, USR, follow, NULL, &vp,
831 foreigncreds ? foreigncreds : credp);
833 #ifdef AFS_LINUX22_ENV
834 code = gop_lookupname_user(path, AFS_UIOUSER, follow, &dp);
836 vp = (struct vnode *)dp->d_inode;
838 code = gop_lookupname_user(path, AFS_UIOUSER, follow, &vp);
839 #endif /* AFS_LINUX22_ENV */
840 #endif /* AFS_AIX41_ENV */
844 #if defined(KERNEL_HAVE_UERROR)
852 #if defined(AFS_SUN510_ENV)
853 if (vp && !IsAfsVnode(vp)) {
854 struct vnode *realvp;
856 #ifdef AFS_SUN511_ENV
857 (VOP_REALVP(vp, &realvp, NULL) == 0)
859 (VOP_REALVP(vp, &realvp) == 0)
862 struct vnode *oldvp = vp;
870 /* now make the call if we were passed no file, or were passed an AFS file */
871 if (!vp || IsAfsVnode(vp)) {
872 #if defined(AFS_SUN5_ENV)
873 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
874 #elif defined(AFS_AIX41_ENV)
876 struct ucred *cred1, *cred2;
879 cred1 = cred2 = foreigncreds;
881 cred1 = cred2 = credp;
883 code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
884 if (cred1 != cred2) {
885 /* something changed the creds */
889 #elif defined(AFS_HPUX101_ENV)
891 struct ucred *cred = p_cred(u.u_procp);
892 code = afs_HandlePioctl(vp, com, &data, follow, &cred);
894 #elif defined(AFS_SGI_ENV)
897 credp = OSI_GET_CURRENT_CRED();
898 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
900 #elif defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
901 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
903 code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
906 #if defined(KERNEL_HAVE_UERROR)
909 code = EINVAL; /* not in /afs */
914 #if defined(AFS_NEED_CLIENTCONTEXT)
917 crset(tmpcred); /* restore original credentials */
919 #if defined(AFS_HPUX101_ENV)
920 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
921 #elif defined(AFS_SGI_ENV)
922 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
923 #elif defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
924 credp = tmpcred; /* restore original credentials */
926 osi_curcred() = tmpcred; /* restore original credentials */
927 #endif /* AFS_HPUX101_ENV */
928 crfree(foreigncreds);
931 #endif /* AFS_NEED_CLIENTCONTEXT */
933 #ifdef AFS_LINUX22_ENV
936 AFS_RELE(vp); /* put vnode back */
940 #if defined(KERNEL_HAVE_UERROR)
943 return (getuerror());
949 #ifdef AFS_DARWIN100_ENV
951 afs_syscall_pioctl(char * path, unsigned int com, caddr_t cmarg,
952 int follow, afs_ucred_t *credp)
954 return afs_syscall64_pioctl(CAST_USER_ADDR_T(path), com,
955 CAST_USER_ADDR_T((unsigned int)cmarg), follow,
960 #define MAXPIOCTLTOKENLEN \
961 (3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
964 afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
965 register struct afs_ioctl *ablob, int afollow,
969 struct vrequest treq;
970 register afs_int32 code;
971 register afs_int32 function, device;
972 afs_int32 inSize, outSize, outSizeMax;
973 char *inData, *outData;
974 pioctlFunction *pioctlSw;
976 struct afs_fakestat_state fakestate;
978 avc = avp ? VTOAFS(avp) : NULL;
979 afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
980 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
981 AFS_STATCNT(HandlePioctl);
982 if ((code = afs_InitReq(&treq, *acred)))
984 afs_InitFakeStat(&fakestate);
986 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
988 afs_PutFakeStat(&fakestate);
992 device = (acom & 0xff00) >> 8;
994 case 'V': /* Original pioctls */
995 pioctlSw = VpioctlSw;
996 pioctlSwSize = sizeof(VpioctlSw);
998 case 'C': /* Coordinated/common pioctls */
999 pioctlSw = CpioctlSw;
1000 pioctlSwSize = sizeof(CpioctlSw);
1002 case 'O': /* Coordinated/common pioctls */
1003 pioctlSw = OpioctlSw;
1004 pioctlSwSize = sizeof(OpioctlSw);
1007 afs_PutFakeStat(&fakestate);
1010 function = acom & 0xff;
1011 if (function >= (pioctlSwSize / sizeof(char *))) {
1012 afs_PutFakeStat(&fakestate);
1013 return EINVAL; /* out of range */
1015 inSize = ablob->in_size;
1017 /* Do all range checking before continuing */
1018 if (inSize > MAXPIOCTLTOKENLEN || inSize < 0 || ablob->out_size < 0)
1021 /* Note that we use osi_Alloc for large allocs and osi_AllocLargeSpace for small ones */
1022 if (inSize > AFS_LRALLOCSIZ) {
1023 inData = osi_Alloc(inSize + 1);
1025 inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1030 AFS_COPYIN(ablob->in, inData, inSize, code);
1031 inData[inSize] = '\0';
1035 if (inSize > AFS_LRALLOCSIZ) {
1036 osi_Free(inData, inSize + 1);
1038 osi_FreeLargeSpace(inData);
1040 afs_PutFakeStat(&fakestate);
1043 if (function == 8 && device == 'V') { /* PGetTokens */
1044 outSizeMax = MAXPIOCTLTOKENLEN;
1045 outData = osi_Alloc(outSizeMax);
1047 outSizeMax = AFS_LRALLOCSIZ;
1048 outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1051 if (inSize > AFS_LRALLOCSIZ) {
1052 osi_Free(inData, inSize + 1);
1054 osi_FreeLargeSpace(inData);
1056 afs_PutFakeStat(&fakestate);
1061 (*pioctlSw[function]) (avc, function, &treq, inData, outData, inSize,
1063 if (inSize > AFS_LRALLOCSIZ) {
1064 osi_Free(inData, inSize + 1);
1066 osi_FreeLargeSpace(inData);
1068 if (code == 0 && ablob->out_size > 0) {
1069 if (outSize > ablob->out_size) {
1070 code = E2BIG; /* data wont fit in user buffer */
1071 } else if (outSize) {
1072 AFS_COPYOUT(outData, ablob->out, outSize, code);
1075 if (outSizeMax > AFS_LRALLOCSIZ) {
1076 osi_Free(outData, outSizeMax);
1078 osi_FreeLargeSpace(outData);
1080 afs_PutFakeStat(&fakestate);
1081 return afs_CheckCode(code, &treq, 41);
1085 * VIOCGETFID (22) - Get file ID quickly
1089 * \param[in] ain not in use
1090 * \param[out] aout fid of requested file
1092 * \retval EINVAL Error if some of the initial arguments aren't set
1094 * \post get the file id of some file
1096 DECL_PIOCTL(PGetFID)
1098 AFS_STATCNT(PGetFID);
1101 memcpy(aout, (char *)&avc->f.fid, sizeof(struct VenusFid));
1102 *aoutSize = sizeof(struct VenusFid);
1107 * VIOCSETAL (1) - Set access control list
1111 * \param[in] ain the ACL being set
1112 * \param[out] aout the ACL being set returned
1114 * \retval EINVAL Error if some of the standard args aren't set
1116 * \post Changed ACL, via direct writing to the wire
1118 int dummy_PSetAcl(char *ain, char *aout)
1123 DECL_PIOCTL(PSetAcl)
1125 register afs_int32 code;
1126 struct afs_conn *tconn;
1127 struct AFSOpaque acl;
1128 struct AFSVolSync tsync;
1129 struct AFSFetchStatus OutStatus;
1132 AFS_STATCNT(PSetAcl);
1135 if ((acl.AFSOpaque_len = strlen(ain) + 1) > 1024 /* AFSOPAQUEMAX */)
1138 acl.AFSOpaque_val = ain;
1140 tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1142 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1145 RXAFS_StoreACL(tconn->id, (struct AFSFid *)&avc->f.fid.Fid,
1146 &acl, &OutStatus, &tsync);
1151 } while (afs_Analyze
1152 (tconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_STOREACL,
1153 SHARED_LOCK, NULL));
1155 /* now we've forgotten all of the access info */
1156 ObtainWriteLock(&afs_xcbhash, 455);
1158 afs_DequeueCallback(avc);
1159 avc->f.states &= ~(CStatd | CUnique);
1160 ReleaseWriteLock(&afs_xcbhash);
1161 if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1162 osi_dnlc_purgedp(avc);
1164 /* SXW - Should we flush metadata here? */
1168 int afs_defaultAsynchrony = 0;
1171 * VIOC_STOREBEHIND (47) Adjust store asynchrony
1175 * \param[in] ain sbstruct (store behind structure) input
1176 * \param[out] aout resulting sbstruct
1178 * \retval EPERM Error if the user doesn't have super-user credentials
1179 * \retval EACCES Error if there isn't enough access to not check the mode bits
1181 * \post sets asynchrony based on a file, from a struct sbstruct "I THINK"
1183 DECL_PIOCTL(PStoreBehind)
1186 struct sbstruct *sbr;
1188 sbr = (struct sbstruct *)ain;
1189 if (sbr->sb_default != -1) {
1190 if (afs_osi_suser(*acred))
1191 afs_defaultAsynchrony = sbr->sb_default;
1196 if (avc && (sbr->sb_thisfile != -1)) {
1198 (avc, PRSFS_WRITE | PRSFS_ADMINISTER, areq, DONT_CHECK_MODE_BITS))
1199 avc->asynchrony = sbr->sb_thisfile;
1204 *aoutSize = sizeof(struct sbstruct);
1205 sbr = (struct sbstruct *)aout;
1206 sbr->sb_default = afs_defaultAsynchrony;
1208 sbr->sb_thisfile = avc->asynchrony;
1215 * VIOC_GCPAGS (48) - Disable automatic PAG gc'ing
1219 * \param[in] ain not in use
1220 * \param[out] aout not in use
1222 * \retval EACCES Error if the user doesn't have super-user credentials
1224 * \post set the gcpags to GCPAGS_USERDISABLED
1226 DECL_PIOCTL(PGCPAGs)
1228 if (!afs_osi_suser(*acred)) {
1231 afs_gcpags = AFS_GCPAGS_USERDISABLED;
1236 * VIOCGETAL (2) - Get access control list
1240 * \param[in] ain not in use
1241 * \param[out] aout the ACL
1243 * \retval EINVAL Error if some of the standard args aren't set
1244 * \retval ERANGE Error if the vnode of the file id is too large
1245 * \retval -1 Error if getting the ACL failed
1247 * \post Obtain the ACL, based on file ID
1249 * \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
1251 DECL_PIOCTL(PGetAcl)
1253 struct AFSOpaque acl;
1254 struct AFSVolSync tsync;
1255 struct AFSFetchStatus OutStatus;
1257 struct afs_conn *tconn;
1261 AFS_STATCNT(PGetAcl);
1264 Fid.Volume = avc->f.fid.Fid.Volume;
1265 Fid.Vnode = avc->f.fid.Fid.Vnode;
1266 Fid.Unique = avc->f.fid.Fid.Unique;
1267 if (avc->f.states & CForeign) {
1269 * For a dfs xlator acl we have a special hack so that the
1270 * xlator will distinguish which type of acl will return. So
1271 * we currently use the top 2-bytes (vals 0-4) to tell which
1272 * type of acl to bring back. Horrible hack but this will
1273 * cause the least number of changes to code size and interfaces.
1275 if (Fid.Vnode & 0xc0000000)
1277 Fid.Vnode |= (ainSize << 30);
1279 acl.AFSOpaque_val = aout;
1281 tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1284 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1286 code = RXAFS_FetchACL(tconn->id, &Fid, &acl, &OutStatus, &tsync);
1291 } while (afs_Analyze
1292 (tconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_FETCHACL,
1293 SHARED_LOCK, NULL));
1296 *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1302 * PNoop returns success. Used for functions which are not implemented or are no longer in use.
1306 * \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
1315 * PBogus returns fail. Used for functions which are not implemented or are no longer in use.
1319 * \retval EINVAL Error if some of the standard args aren't set
1321 * \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;
1325 AFS_STATCNT(PBogus);
1330 * VIOC_FILE_CELL_NAME (30) - Get cell in which file lives
1334 * \param[in] ain not in use (avc used to pass in file id)
1335 * \param[out] aout cell name
1337 * \retval EINVAL Error if some of the standard args aren't set
1338 * \retval ESRCH Error if the file isn't part of a cell
1340 * \post Get a cell based on a passed in file id
1342 DECL_PIOCTL(PGetFileCell)
1344 register struct cell *tcell;
1346 AFS_STATCNT(PGetFileCell);
1349 tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
1352 strcpy(aout, tcell->cellName);
1353 afs_PutCell(tcell, READ_LOCK);
1354 *aoutSize = strlen(aout) + 1;
1359 * VIOC_GET_WS_CELL (31) - Get cell in which workstation lives
1363 * \param[in] ain not in use
1364 * \param[out] aout cell name
1366 * \retval EIO Error if the afs daemon hasn't started yet
1367 * \retval ESRCH Error if the machine isn't part of a cell, for whatever reason
1369 * \post Get the primary cell that the machine is a part of.
1371 DECL_PIOCTL(PGetWSCell)
1373 struct cell *tcell = NULL;
1375 AFS_STATCNT(PGetWSCell);
1376 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1377 return EIO; /* Inappropriate ioctl for device */
1379 tcell = afs_GetPrimaryCell(READ_LOCK);
1380 if (!tcell) /* no primary cell? */
1382 strcpy(aout, tcell->cellName);
1383 *aoutSize = strlen(aout) + 1;
1384 afs_PutCell(tcell, READ_LOCK);
1389 * VIOC_GET_PRIMARY_CELL (33) - Get primary cell for caller
1393 * \param[in] ain not in use (user id found via areq)
1394 * \param[out] aout cell name
1396 * \retval ESRCH Error if the user id doesn't have a primary cell specified
1398 * \post Get the primary cell for a certain user, based on the user's uid
1400 DECL_PIOCTL(PGetUserCell)
1402 register afs_int32 i;
1403 register struct unixuser *tu;
1404 register struct cell *tcell;
1406 AFS_STATCNT(PGetUserCell);
1407 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1408 return EIO; /* Inappropriate ioctl for device */
1410 /* return the cell name of the primary cell for this user */
1411 i = UHash(areq->uid);
1412 ObtainWriteLock(&afs_xuser, 224);
1413 for (tu = afs_users[i]; tu; tu = tu->next) {
1414 if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1416 ReleaseWriteLock(&afs_xuser);
1421 tcell = afs_GetCell(tu->cell, READ_LOCK);
1422 afs_PutUser(tu, WRITE_LOCK);
1426 strcpy(aout, tcell->cellName);
1427 afs_PutCell(tcell, READ_LOCK);
1428 *aoutSize = strlen(aout) + 1; /* 1 for the null */
1431 ReleaseWriteLock(&afs_xuser);
1439 * VIOCSETTOK (3) - Set authentication tokens
1443 * \param[in] ain the krb tickets from which to set the afs tokens
1444 * \param[out] aout not in use
1446 * \retval EINVAL Error if the ticket is either too long or too short
1447 * \retval EIO Error if the AFS initState is below 101
1448 * \retval ESRCH Error if the cell for which the Token is being set can't be found
1450 * \post Set the Tokens for a specific cell name, unless there is none set, then default to primary
1453 DECL_PIOCTL(PSetTokens)
1456 register struct unixuser *tu;
1457 struct ClearToken clear;
1458 register struct cell *tcell;
1461 struct vrequest treq;
1462 afs_int32 flag, set_parent_pag = 0;
1464 AFS_STATCNT(PSetTokens);
1465 if (!afs_resourceinit_flag) {
1468 memcpy((char *)&i, ain, sizeof(afs_int32));
1469 ain += sizeof(afs_int32);
1470 stp = ain; /* remember where the ticket is */
1471 if (i < 0 || i > MAXKTCTICKETLEN)
1472 return EINVAL; /* malloc may fail */
1474 ain += i; /* skip over ticket */
1475 memcpy((char *)&i, ain, sizeof(afs_int32));
1476 ain += sizeof(afs_int32);
1477 if (i != sizeof(struct ClearToken)) {
1480 memcpy((char *)&clear, ain, sizeof(struct ClearToken));
1481 if (clear.AuthHandle == -1)
1482 clear.AuthHandle = 999; /* more rxvab compat stuff */
1483 ain += sizeof(struct ClearToken);
1484 if (ainSize != 2 * sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1485 /* still stuff left? we've got primary flag and cell name. Set these */
1486 memcpy((char *)&flag, ain, sizeof(afs_int32)); /* primary id flag */
1487 ain += sizeof(afs_int32); /* skip id field */
1488 /* rest is cell name, look it up */
1489 /* some versions of gcc appear to need != 0 in order to get this right */
1490 if ((flag & 0x8000) != 0) { /* XXX Use Constant XXX */
1494 tcell = afs_GetCellByName(ain, READ_LOCK);
1498 /* default to primary cell, primary id */
1499 flag = 1; /* primary id */
1500 tcell = afs_GetPrimaryCell(READ_LOCK);
1505 afs_PutCell(tcell, READ_LOCK);
1506 if (set_parent_pag) {
1508 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1509 # if defined(AFS_DARWIN_ENV)
1510 afs_proc_t *p = current_proc(); /* XXX */
1512 afs_proc_t *p = curproc; /* XXX */
1514 # ifndef AFS_DARWIN80_ENV
1515 uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1516 p->p_pid, p->p_comm);
1518 if (!setpag(p, acred, -1, &pag, 1)) {
1520 if (!setpag(acred, -1, &pag, 1)) {
1522 afs_InitReq(&treq, *acred);
1526 /* now we just set the tokens */
1527 tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1528 tu->vid = clear.ViceId;
1529 if (tu->stp != NULL) {
1530 afs_osi_Free(tu->stp, tu->stLen);
1532 tu->stp = (char *)afs_osi_Alloc(stLen);
1533 if (tu->stp == NULL) {
1537 memcpy(tu->stp, stp, stLen);
1540 afs_stats_cmfullperf.authent.TicketUpdates++;
1541 afs_ComputePAGStats();
1542 #endif /* AFS_NOSTATS */
1543 tu->states |= UHasTokens;
1544 tu->states &= ~UTokensBad;
1545 afs_SetPrimary(tu, flag);
1546 tu->tokenTime = osi_Time();
1547 afs_ResetUserConns(tu);
1548 afs_PutUser(tu, WRITE_LOCK);
1564 * VIOCGETVOLSTAT (4) - Get volume status
1568 * \param[in] ain not in use
1569 * \param[out] aout status of the volume
1571 * \retval EINVAL Error if some of the standard args aren't set
1573 * \post The status of a volume (based on the FID of the volume), or an offline message /motd
1575 DECL_PIOCTL(PGetVolumeStatus)
1578 char *offLineMsg = afs_osi_Alloc(256);
1579 char *motd = afs_osi_Alloc(256);
1580 register struct afs_conn *tc;
1581 register afs_int32 code = 0;
1582 struct AFSFetchVolumeStatus volstat;
1584 char *Name, *OfflineMsg, *MOTD;
1587 AFS_STATCNT(PGetVolumeStatus);
1593 OfflineMsg = offLineMsg;
1596 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1598 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1601 RXAFS_GetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &volstat,
1602 &Name, &OfflineMsg, &MOTD);
1607 } while (afs_Analyze
1608 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1609 SHARED_LOCK, NULL));
1613 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1615 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1616 cp += sizeof(VolumeStatus);
1617 strcpy(cp, volName);
1618 cp += strlen(volName) + 1;
1619 strcpy(cp, offLineMsg);
1620 cp += strlen(offLineMsg) + 1;
1622 cp += strlen(motd) + 1;
1623 *aoutSize = (cp - aout);
1625 afs_osi_Free(offLineMsg, 256);
1626 afs_osi_Free(motd, 256);
1631 * VIOCSETVOLSTAT (5) - Set volume status
1635 * \param[in] ain values to set the status at, offline message, message of the day, volume name, minimum quota, maximum quota
1636 * \param[out] aout status of a volume, offlines messages, minimum quota, maximumm quota
1638 * \retval EINVAL Error if some of the standard args aren't set
1639 * \retval EROFS Error if the volume is read only, or a backup volume
1640 * \retval ENODEV Error if the volume can't be accessed
1641 * \retval E2BIG Error if the volume name, offline message, and motd are too big
1643 * \post Set the status of a volume, including any offline messages, a minimum quota, and a maximum quota
1645 DECL_PIOCTL(PSetVolumeStatus)
1648 char *offLineMsg = afs_osi_Alloc(256);
1649 char *motd = afs_osi_Alloc(256);
1650 register struct afs_conn *tc;
1651 register afs_int32 code = 0;
1652 struct AFSFetchVolumeStatus volstat;
1653 struct AFSStoreVolumeStatus storeStat;
1654 register struct volume *tvp;
1658 AFS_STATCNT(PSetVolumeStatus);
1664 tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
1666 if (tvp->states & (VRO | VBackup)) {
1667 afs_PutVolume(tvp, READ_LOCK);
1671 afs_PutVolume(tvp, READ_LOCK);
1676 /* Copy the junk out, using cp as a roving pointer. */
1678 memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
1679 cp += sizeof(AFSFetchVolumeStatus);
1680 if (strlen(cp) >= sizeof(volName)) {
1684 strcpy(volName, cp);
1685 cp += strlen(volName) + 1;
1686 if (strlen(cp) >= sizeof(offLineMsg)) {
1690 strcpy(offLineMsg, cp);
1691 cp += strlen(offLineMsg) + 1;
1692 if (strlen(cp) >= sizeof(motd)) {
1698 if (volstat.MinQuota != -1) {
1699 storeStat.MinQuota = volstat.MinQuota;
1700 storeStat.Mask |= AFS_SETMINQUOTA;
1702 if (volstat.MaxQuota != -1) {
1703 storeStat.MaxQuota = volstat.MaxQuota;
1704 storeStat.Mask |= AFS_SETMAXQUOTA;
1707 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1709 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1712 RXAFS_SetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &storeStat,
1713 volName, offLineMsg, motd);
1718 } while (afs_Analyze
1719 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1720 SHARED_LOCK, NULL));
1724 /* we are sending parms back to make compat. with prev system. should
1725 * change interface later to not ask for current status, just set new status */
1727 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1728 cp += sizeof(VolumeStatus);
1729 strcpy(cp, volName);
1730 cp += strlen(volName) + 1;
1731 strcpy(cp, offLineMsg);
1732 cp += strlen(offLineMsg) + 1;
1734 cp += strlen(motd) + 1;
1735 *aoutSize = cp - aout;
1737 afs_osi_Free(offLineMsg, 256);
1738 afs_osi_Free(motd, 256);
1743 * VIOCFLUSH (6) - Invalidate cache entry
1747 * \param[in] ain not in use
1748 * \param[out] aout not in use
1750 * \retval EINVAL Error if some of the standard args aren't set
1752 * \post Flush any information the cache manager has on an entry
1756 AFS_STATCNT(PFlush);
1759 #ifdef AFS_BOZONLOCK_ENV
1760 afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
1762 ObtainWriteLock(&avc->lock, 225);
1763 afs_ResetVCache(avc, *acred);
1764 ReleaseWriteLock(&avc->lock);
1765 #ifdef AFS_BOZONLOCK_ENV
1766 afs_BozonUnlock(&avc->pvnLock, avc);
1772 * VIOC_AFS_STAT_MT_PT (29) - Stat mount point
1776 * \param[in] ain the last component in a path, related to mountpoint that we're looking for information about
1777 * \param[out] aout volume, cell, link data
1779 * \retval EINVAL Error if some of the standard args aren't set
1780 * \retval ENOTDIR Error if the 'mount point' argument isn't a directory
1781 * \retval EIO Error if the link data can't be accessed
1783 * \post Get the volume, and cell, as well as the link data for a mount point
1785 DECL_PIOCTL(PNewStatMount)
1787 register afs_int32 code;
1788 register struct vcache *tvc;
1789 register struct dcache *tdc;
1790 struct VenusFid tfid;
1792 struct sysname_info sysState;
1793 afs_size_t offset, len;
1795 AFS_STATCNT(PNewStatMount);
1798 code = afs_VerifyVCache(avc, areq);
1801 if (vType(avc) != VDIR) {
1804 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
1807 Check_AtSys(avc, ain, &sysState, areq);
1808 ObtainReadLock(&tdc->lock);
1810 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
1811 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1812 ReleaseReadLock(&tdc->lock);
1813 afs_PutDCache(tdc); /* we're done with the data */
1814 bufp = sysState.name;
1818 tfid.Cell = avc->f.fid.Cell;
1819 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
1820 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
1821 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
1823 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
1829 if (tvc->mvstat != 1) {
1834 ObtainWriteLock(&tvc->lock, 226);
1835 code = afs_HandleLink(tvc, areq);
1837 if (tvc->linkData) {
1838 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1841 /* we have the data */
1842 strcpy(aout, tvc->linkData);
1843 *aoutSize = strlen(tvc->linkData) + 1;
1848 ReleaseWriteLock(&tvc->lock);
1851 if (sysState.allocked)
1852 osi_FreeLargeSpace(bufp);
1857 * VIOCGETTOK (8) - Get authentication tokens
1861 * \param[in] ain userid
1862 * \param[out] aout token
1864 * \retval EIO Error if the afs daemon hasn't started yet
1865 * \retval EDOM Error if the input parameter is out of the bounds of the available tokens
1866 * \retval ENOTCONN Error if there aren't tokens for this cell
1868 * \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
1870 * \notes "it's a weird interface (from comments in the code)"
1873 DECL_PIOCTL(PGetTokens)
1875 register struct cell *tcell;
1876 register afs_int32 i;
1877 register struct unixuser *tu;
1879 afs_int32 iterator = 0;
1882 AFS_STATCNT(PGetTokens);
1883 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1884 return EIO; /* Inappropriate ioctl for device */
1886 /* weird interface. If input parameter is present, it is an integer and
1887 * we're supposed to return the parm'th tokens for this unix uid.
1888 * If not present, we just return tokens for cell 1.
1889 * If counter out of bounds, return EDOM.
1890 * If no tokens for the particular cell, return ENOTCONN.
1891 * Also, if this mysterious parm is present, we return, along with the
1892 * tokens, the primary cell indicator (an afs_int32 0) and the cell name
1893 * at the end, in that order.
1895 if ((newStyle = (ainSize > 0))) {
1896 memcpy((char *)&iterator, ain, sizeof(afs_int32));
1898 i = UHash(areq->uid);
1899 ObtainReadLock(&afs_xuser);
1900 for (tu = afs_users[i]; tu; tu = tu->next) {
1902 if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1903 if (iterator-- == 0)
1904 break; /* are we done yet? */
1907 if (tu->uid == areq->uid && afs_IsPrimaryCellNum(tu->cell))
1913 * No need to hold a read lock on each user entry
1917 ReleaseReadLock(&afs_xuser);
1922 if (((tu->states & UHasTokens) == 0)
1923 || (tu->ct.EndTimestamp < osi_Time())) {
1924 tu->states |= (UTokensBad | UNeedsReset);
1925 afs_PutUser(tu, READ_LOCK);
1928 /* use iterator for temp */
1930 iterator = tu->stLen; /* for compat, we try to return 56 byte tix if they fit */
1932 iterator = 56; /* # of bytes we're returning */
1933 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1934 cp += sizeof(afs_int32);
1935 memcpy(cp, tu->stp, tu->stLen); /* copy out st */
1937 iterator = sizeof(struct ClearToken);
1938 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1939 cp += sizeof(afs_int32);
1940 memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
1941 cp += sizeof(struct ClearToken);
1943 /* put out primary id and cell name, too */
1944 iterator = (tu->states & UPrimary ? 1 : 0);
1945 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1946 cp += sizeof(afs_int32);
1947 tcell = afs_GetCell(tu->cell, READ_LOCK);
1949 strcpy(cp, tcell->cellName);
1950 cp += strlen(tcell->cellName) + 1;
1951 afs_PutCell(tcell, READ_LOCK);
1955 *aoutSize = cp - aout;
1956 afs_PutUser(tu, READ_LOCK);
1961 * VIOCUNLOG (9) - Invalidate tokens
1965 * \param[in] ain not in use
1966 * \param[out] aout not in use
1968 * \retval EIO Error if the afs daemon hasn't been started yet
1970 * \post remove tokens from a user, specified by the user id
1972 * \notes sets the token's time to 0, which then causes it to be removed
1973 * \notes Unlog is the same as un-pag in OpenAFS
1977 register afs_int32 i;
1978 register struct unixuser *tu;
1980 AFS_STATCNT(PUnlog);
1981 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1982 return EIO; /* Inappropriate ioctl for device */
1984 i = UHash(areq->uid);
1985 ObtainWriteLock(&afs_xuser, 227);
1986 for (tu = afs_users[i]; tu; tu = tu->next) {
1987 if (tu->uid == areq->uid) {
1989 tu->states &= ~UHasTokens;
1990 /* security is not having to say you're sorry */
1991 memset(&tu->ct, 0, sizeof(struct ClearToken));
1993 ReleaseWriteLock(&afs_xuser);
1994 /* We have to drop the lock over the call to afs_ResetUserConns, since
1995 * it obtains the afs_xvcache lock. We could also keep the lock, and
1996 * modify ResetUserConns to take parm saying we obtained the lock
1997 * already, but that is overkill. By keeping the "tu" pointer
1998 * held over the released lock, we guarantee that we won't lose our
1999 * place, and that we'll pass over every user conn that existed when
2000 * we began this call.
2002 afs_ResetUserConns(tu);
2004 ObtainWriteLock(&afs_xuser, 228);
2006 /* set the expire times to 0, causes
2007 * afs_GCUserData to remove this entry
2009 tu->ct.EndTimestamp = 0;
2011 #endif /* UKERNEL */
2014 ReleaseWriteLock(&afs_xuser);
2019 * VIOC_AFS_MARINER_HOST (32) - Get/set mariner (cache manager monitor) host
2023 * \param[in] ain host address to be set
2024 * \param[out] aout old host address
2026 * \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
2028 * \notes Errors turn off mariner
2030 DECL_PIOCTL(PMariner)
2032 afs_int32 newHostAddr;
2033 afs_int32 oldHostAddr;
2035 AFS_STATCNT(PMariner);
2037 memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost,
2040 oldHostAddr = 0xffffffff; /* disabled */
2042 memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
2043 if (newHostAddr == 0xffffffff) {
2044 /* disable mariner operations */
2046 } else if (newHostAddr) {
2048 afs_marinerHost = newHostAddr;
2050 memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
2051 *aoutSize = sizeof(afs_int32);
2056 * VIOCCKSERV (10) - Check that servers are up
2060 * \param[in] ain name of the cell
2061 * \param[out] aout current down server list
2063 * \retval EIO Error if the afs daemon hasn't started yet
2064 * \retval EACCES Error if the user doesn't have super-user credentials
2065 * \retval ENOENT Error if we are unable to obtain the cell
2067 * \post Either a fast check (where it doesn't contact servers) or a local check (checks local cell only)
2069 DECL_PIOCTL(PCheckServers)
2071 register char *cp = 0;
2073 register struct server *ts;
2074 afs_int32 temp, *lp = (afs_int32 *) ain, havecell = 0;
2076 struct chservinfo *pcheck;
2078 AFS_STATCNT(PCheckServers);
2080 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2081 return EIO; /* Inappropriate ioctl for device */
2083 if (*lp == 0x12345678) { /* For afs3.3 version */
2084 pcheck = (struct chservinfo *)ain;
2085 if (pcheck->tinterval >= 0) {
2087 memcpy(cp, (char *)&afs_probe_interval, sizeof(afs_int32));
2088 *aoutSize = sizeof(afs_int32);
2089 if (pcheck->tinterval > 0) {
2090 if (!afs_osi_suser(*acred))
2092 afs_probe_interval = pcheck->tinterval;
2098 temp = pcheck->tflags;
2099 cp = pcheck->tbuffer;
2100 } else { /* For pre afs3.3 versions */
2101 memcpy((char *)&temp, ain, sizeof(afs_int32));
2102 cp = ain + sizeof(afs_int32);
2103 if (ainSize > sizeof(afs_int32))
2108 * 1: fast check, don't contact servers.
2109 * 2: local cell only.
2112 /* have cell name, too */
2113 cellp = afs_GetCellByName(cp, READ_LOCK);
2118 if (!cellp && (temp & 2)) {
2119 /* use local cell */
2120 cellp = afs_GetPrimaryCell(READ_LOCK);
2122 if (!(temp & 1)) { /* if not fast, call server checker routine */
2123 afs_CheckServers(1, cellp); /* check down servers */
2124 afs_CheckServers(0, cellp); /* check up servers */
2126 /* now return the current down server list */
2128 ObtainReadLock(&afs_xserver);
2129 for (i = 0; i < NSERVERS; i++) {
2130 for (ts = afs_servers[i]; ts; ts = ts->next) {
2131 if (cellp && ts->cell != cellp)
2132 continue; /* cell spec'd and wrong */
2133 if ((ts->flags & SRVR_ISDOWN)
2134 && ts->addr->sa_portal != ts->cell->vlport) {
2135 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2136 cp += sizeof(afs_int32);
2140 ReleaseReadLock(&afs_xserver);
2142 afs_PutCell(cellp, READ_LOCK);
2143 *aoutSize = cp - aout;
2148 * VIOCCKBACK (11) - Check backup volume mappings
2152 * \param[in] ain not in use
2153 * \param[out] aout not in use
2155 * \retval EIO Error if the afs daemon hasn't started yet
2157 * \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
2159 DECL_PIOCTL(PCheckVolNames)
2161 AFS_STATCNT(PCheckVolNames);
2162 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2163 return EIO; /* Inappropriate ioctl for device */
2165 afs_CheckRootVolume();
2166 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE | AFS_VOLCHECK_EXPIRED |
2167 AFS_VOLCHECK_BUSY | AFS_VOLCHECK_MTPTS);
2172 * VIOCCKCONN (12) - Check connections for a user
2176 * \param[in] ain not in use
2177 * \param[out] aout not in use
2179 * \retval EACCESS Error if no user is specififed, the user has no tokens set, or if the user's tokens are bad
2181 * \post check to see if a user has the correct authentication. If so, allow access.
2183 * \notes Check the connections to all the servers specified
2185 DECL_PIOCTL(PCheckAuth)
2189 struct afs_conn *tc;
2190 struct unixuser *tu;
2193 AFS_STATCNT(PCheckAuth);
2194 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2195 return EIO; /* Inappropriate ioctl for device */
2198 tu = afs_GetUser(areq->uid, 1, READ_LOCK); /* check local cell authentication */
2202 /* we have a user */
2203 ObtainReadLock(&afs_xsrvAddr);
2204 ObtainReadLock(&afs_xconn);
2206 /* any tokens set? */
2207 if ((tu->states & UHasTokens) == 0)
2209 /* all connections in cell 1 working? */
2210 for (i = 0; i < NSERVERS; i++) {
2211 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2212 for (tc = sa->conns; tc; tc = tc->next) {
2213 if (tc->user == tu && (tu->states & UTokensBad))
2218 ReleaseReadLock(&afs_xsrvAddr);
2219 ReleaseReadLock(&afs_xconn);
2220 afs_PutUser(tu, READ_LOCK);
2222 memcpy(aout, (char *)&retValue, sizeof(afs_int32));
2223 *aoutSize = sizeof(afs_int32);
2228 Prefetch(uparmtype apath, struct afs_ioctl *adata, int afollow,
2232 register afs_int32 code;
2233 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
2239 AFS_STATCNT(Prefetch);
2242 tp = osi_AllocLargeSpace(1024);
2243 AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2245 osi_FreeLargeSpace(tp);
2248 if (afs_BBusy()) { /* do this as late as possible */
2249 osi_FreeLargeSpace(tp);
2250 return EWOULDBLOCK; /* pretty close */
2252 afs_BQueue(BOP_PATH, (struct vcache *)0, 0, 0, acred, (afs_size_t) 0,
2253 (afs_size_t) 0, tp);
2258 * VIOCWHEREIS (14) - Find out where a volume is located
2262 * \param[in] ain not in use
2263 * \param[out] aout volume location
2265 * \retval EINVAL Error if some of the default arguments don't exist
2266 * \retval ENODEV Error if there is no such volume
2268 * \post fine a volume, based on a volume file id
2270 * \notes check each of the servers specified
2272 DECL_PIOCTL(PFindVolume)
2274 register struct volume *tvp;
2275 register struct server *ts;
2276 register afs_int32 i;
2279 AFS_STATCNT(PFindVolume);
2282 tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
2285 for (i = 0; i < MAXHOSTS; i++) {
2286 ts = tvp->serverHost[i];
2289 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2290 cp += sizeof(afs_int32);
2293 /* still room for terminating NULL, add it on */
2294 ainSize = 0; /* reuse vbl */
2295 memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
2296 cp += sizeof(afs_int32);
2298 *aoutSize = cp - aout;
2299 afs_PutVolume(tvp, READ_LOCK);
2306 * VIOCACCESS (20) - Access using PRS_FS bits
2310 * \param[in] ain PRS_FS bits
2311 * \param[out] aout not in use
2313 * \retval EINVAL Error if some of the initial arguments aren't set
2314 * \retval EACCES Error if access is denied
2316 * \post check to make sure access is allowed
2318 DECL_PIOCTL(PViceAccess)
2320 register afs_int32 code;
2323 AFS_STATCNT(PViceAccess);
2326 code = afs_VerifyVCache(avc, areq);
2329 memcpy((char *)&temp, ain, sizeof(afs_int32));
2330 code = afs_AccessOK(avc, temp, areq, CHECK_MODE_BITS);
2338 * VIOC_GETPAG (13) - Get PAG value
2342 * \param[in] ain not in use
2343 * \param[out] aout PAG value or NOPAG
2345 * \retval E2BIG Error not enough space to copy out value
2347 * \post get PAG value for the caller's cred
2349 DECL_PIOCTL(PGetPAG)
2353 if (*aoutSize < sizeof(afs_int32)) {
2357 pag = PagInCred(*acred);
2359 memcpy(aout, (char *)&pag, sizeof(afs_int32));
2360 *aoutSize = sizeof(afs_int32);
2364 DECL_PIOCTL(PPrecache)
2368 /*AFS_STATCNT(PPrecache);*/
2369 if (!afs_osi_suser(*acred))
2371 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2372 afs_preCache = newValue*1024;
2377 * VIOCSETCACHESIZE (24) - Set venus cache size in 1000 units
2381 * \param[in] ain the size the venus cache should be set to
2382 * \param[out] aout not in use
2384 * \retval EACCES Error if the user doesn't have super-user credentials
2385 * \retval EROFS Error if the cache is set to be in memory
2387 * \post Set the cache size based on user input. If no size is given, set it to the default OpenAFS cache size.
2389 * \notes recompute the general cache parameters for every single block allocated
2391 DECL_PIOCTL(PSetCacheSize)
2396 AFS_STATCNT(PSetCacheSize);
2397 if (!afs_osi_suser(*acred))
2399 /* too many things are setup initially in mem cache version */
2400 if (cacheDiskType == AFS_FCACHE_TYPE_MEM)
2402 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2404 afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2406 if (newValue < afs_min_cache)
2407 afs_cacheBlocks = afs_min_cache;
2409 afs_cacheBlocks = newValue;
2411 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2412 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2413 afs_MaybeWakeupTruncateDaemon();
2414 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2415 afs_osi_Wait(1000, 0, 0);
2416 afs_MaybeWakeupTruncateDaemon();
2421 #define MAXGCSTATS 16
2423 * VIOCGETCACHEPARMS (40) - Get cache stats
2427 * \param[in] ain afs index flags
2428 * \param[out] aout cache blocks, blocks used, blocks files (in an array)
2430 * \post Get the cache blocks, and how many of the cache blocks there are
2432 DECL_PIOCTL(PGetCacheSize)
2434 afs_int32 results[MAXGCSTATS];
2436 register struct dcache * tdc;
2439 AFS_STATCNT(PGetCacheSize);
2441 if (sizeof(afs_int32) == ainSize){
2442 memcpy((char *)&flags, ain, sizeof(afs_int32));
2443 } else if (0 == ainSize){
2449 memset(results, 0, sizeof(results));
2450 results[0] = afs_cacheBlocks;
2451 results[1] = afs_blocksUsed;
2452 results[2] = afs_cacheFiles;
2455 for (i = 0; i < afs_cacheFiles; i++) {
2456 if (afs_indexFlags[i] & IFFree) results[3]++;
2458 } else if (2 == flags){
2459 for (i = 0; i < afs_cacheFiles; i++) {
2460 if (afs_indexFlags[i] & IFFree) results[3]++;
2461 if (afs_indexFlags[i] & IFEverUsed) results[4]++;
2462 if (afs_indexFlags[i] & IFDataMod) results[5]++;
2463 if (afs_indexFlags[i] & IFDirtyPages) results[6]++;
2464 if (afs_indexFlags[i] & IFAnyPages) results[7]++;
2465 if (afs_indexFlags[i] & IFDiscarded) results[8]++;
2467 tdc = afs_indexTable[i];
2470 size = tdc->validPos;
2471 if ( 0 < size && size < (1<<12) ) results[10]++;
2472 else if (size < (1<<14) ) results[11]++;
2473 else if (size < (1<<16) ) results[12]++;
2474 else if (size < (1<<18) ) results[13]++;
2475 else if (size < (1<<20) ) results[14]++;
2476 else if (size >= (1<<20) ) results[15]++;
2480 memcpy(aout, (char *)results, sizeof(results));
2481 *aoutSize = sizeof(results);
2486 * VIOCFLUSHCB (25) - Flush callback only
2490 * \param[in] ain not in use
2491 * \param[out] aout not in use
2493 * \retval EINVAL Error if some of the standard args aren't set
2494 * \retval 0 0 returned if the volume is set to read-only
2496 * \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.
2498 DECL_PIOCTL(PRemoveCallBack)
2500 register struct afs_conn *tc;
2501 register afs_int32 code = 0;
2502 struct AFSCallBack CallBacks_Array[1];
2503 struct AFSCBFids theFids;
2504 struct AFSCBs theCBs;
2507 AFS_STATCNT(PRemoveCallBack);
2510 if (avc->f.states & CRO)
2511 return 0; /* read-only-ness can't change */
2512 ObtainWriteLock(&avc->lock, 229);
2513 theFids.AFSCBFids_len = 1;
2514 theCBs.AFSCBs_len = 1;
2515 theFids.AFSCBFids_val = (struct AFSFid *)&avc->f.fid.Fid;
2516 theCBs.AFSCBs_val = CallBacks_Array;
2517 CallBacks_Array[0].CallBackType = CB_DROPPED;
2518 if (avc->callback) {
2520 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
2522 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2524 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2528 /* don't set code on failure since we wouldn't use it */
2529 } while (afs_Analyze
2530 (tc, code, &avc->f.fid, areq,
2531 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK, NULL));
2533 ObtainWriteLock(&afs_xcbhash, 457);
2534 afs_DequeueCallback(avc);
2536 avc->f.states &= ~(CStatd | CUnique);
2537 ReleaseWriteLock(&afs_xcbhash);
2538 if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2539 osi_dnlc_purgedp(avc);
2541 ReleaseWriteLock(&avc->lock);
2546 * VIOCNEWCELL (26) - Configure new cell
2550 * \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
2551 * \param[out] aout not in use
2553 * \retval EIO Error if the afs daemon hasn't started yet
2554 * \retval EACCES Error if the user doesn't have super-user cedentials
2555 * \retval EINVAL Error if some 'magic' var doesn't have a certain bit set
2557 * \post creates a new cell
2559 DECL_PIOCTL(PNewCell)
2561 /* create a new cell */
2562 afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic = 0;
2563 char *newcell = 0, *linkedcell = 0, *tp = ain;
2564 register afs_int32 code, linkedstate = 0, ls;
2565 u_short fsport = 0, vlport = 0;
2568 AFS_STATCNT(PNewCell);
2569 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2570 return EIO; /* Inappropriate ioctl for device */
2572 if (!afs_osi_suser(*acred))
2575 memcpy((char *)&magic, tp, sizeof(afs_int32));
2576 tp += sizeof(afs_int32);
2577 if (magic != 0x12345678)
2580 /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2581 * server addresses while the 3.5 fs newcell command passes
2582 * MAXHOSTS. To figure out which is which, check if the cellname
2585 newcell = tp + (MAXCELLHOSTS + 3) * sizeof(afs_int32);
2586 scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2588 /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2589 memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
2590 tp += (scount * sizeof(afs_int32));
2592 lp = (afs_int32 *) tp;
2596 fsport = 0; /* Privileged ports not allowed */
2598 vlport = 0; /* Privileged ports not allowed */
2599 tp += (3 * sizeof(afs_int32));
2601 if ((ls = *lp) & 1) {
2602 linkedcell = tp + strlen(newcell) + 1;
2603 linkedstate |= CLinkedCell;
2606 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2608 afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport,
2613 DECL_PIOCTL(PNewAlias)
2615 /* create a new cell alias */
2617 register afs_int32 code;
2618 char *realName, *aliasName;
2620 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2621 return EIO; /* Inappropriate ioctl for device */
2623 if (!afs_osi_suser(*acred))
2627 tp += strlen(aliasName) + 1;
2630 code = afs_NewCellAlias(aliasName, realName);
2636 * VIOCGETCELL (27) - Get cell info
2640 * \param[in] ain The cell index of a specific cell
2641 * \param[out] aout list of servers in the cell
2643 * \retval EIO Error if the afs daemon hasn't started yet
2644 * \retval EDOM Error if there is no cell asked about
2646 * \post Lists the cell's server names and and addresses
2648 DECL_PIOCTL(PListCells)
2650 afs_int32 whichCell;
2651 register struct cell *tcell = 0;
2652 register afs_int32 i;
2653 register char *cp, *tp = ain;
2655 AFS_STATCNT(PListCells);
2656 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2657 return EIO; /* Inappropriate ioctl for device */
2659 memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2660 tp += sizeof(afs_int32);
2661 tcell = afs_GetCellByIndex(whichCell, READ_LOCK);
2664 memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
2665 for (i = 0; i < MAXCELLHOSTS; i++) {
2666 if (tcell->cellHosts[i] == 0)
2668 memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip,
2670 cp += sizeof(afs_int32);
2672 cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2673 strcpy(cp, tcell->cellName);
2674 cp += strlen(tcell->cellName) + 1;
2675 *aoutSize = cp - aout;
2676 afs_PutCell(tcell, READ_LOCK);
2684 DECL_PIOCTL(PListAliases)
2686 afs_int32 whichAlias;
2687 register struct cell_alias *tcalias = 0;
2688 register char *cp, *tp = ain;
2690 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2691 return EIO; /* Inappropriate ioctl for device */
2692 if (ainSize < sizeof(afs_int32))
2695 memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2696 tp += sizeof(afs_int32);
2698 tcalias = afs_GetCellAlias(whichAlias);
2701 strcpy(cp, tcalias->alias);
2702 cp += strlen(tcalias->alias) + 1;
2703 strcpy(cp, tcalias->cell);
2704 cp += strlen(tcalias->cell) + 1;
2705 *aoutSize = cp - aout;
2706 afs_PutCellAlias(tcalias);
2715 * VIOC_AFS_DELETE_MT_PT (28) - Delete mount point
2719 * \param[in] ain the name of the file in this dir to remove
2720 * \param[out] aout not in use
2722 * \retval EINVAL Error if some of the standard args aren't set
2723 * \retval ENOTDIR Error if the argument to remove is not a directory
2724 * \retval ENOENT Error if there is no cache to remove the mount point from or if a vcache doesn't exist
2726 * \post Ensure that everything is OK before deleting the mountpoint. If not, don't delete. Delete a mount point based on a file id.
2728 DECL_PIOCTL(PRemoveMount)
2730 register afs_int32 code;
2732 struct sysname_info sysState;
2733 afs_size_t offset, len;
2734 register struct afs_conn *tc;
2735 register struct dcache *tdc;
2736 register struct vcache *tvc;
2737 struct AFSFetchStatus OutDirStatus;
2738 struct VenusFid tfid;
2739 struct AFSVolSync tsync;
2743 /* "ain" is the name of the file in this dir to remove */
2745 AFS_STATCNT(PRemoveMount);
2748 code = afs_VerifyVCache(avc, areq);
2751 if (vType(avc) != VDIR)
2754 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1); /* test for error below */
2757 Check_AtSys(avc, ain, &sysState, areq);
2758 ObtainReadLock(&tdc->lock);
2760 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
2761 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2762 ReleaseReadLock(&tdc->lock);
2763 bufp = sysState.name;
2768 tfid.Cell = avc->f.fid.Cell;
2769 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
2770 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
2771 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
2773 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
2780 if (tvc->mvstat != 1) {
2786 ObtainWriteLock(&tvc->lock, 230);
2787 code = afs_HandleLink(tvc, areq);
2789 if (tvc->linkData) {
2790 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2795 ReleaseWriteLock(&tvc->lock);
2796 osi_dnlc_purgedp(tvc);
2802 ObtainWriteLock(&avc->lock, 231);
2803 osi_dnlc_remove(avc, bufp, tvc);
2805 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
2807 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2810 RXAFS_RemoveFile(tc->id, (struct AFSFid *)&avc->f.fid.Fid, bufp,
2811 &OutDirStatus, &tsync);
2816 } while (afs_Analyze
2817 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_REMOVEFILE,
2818 SHARED_LOCK, NULL));
2823 ReleaseWriteLock(&avc->lock);
2827 /* we have the thing in the cache */
2828 ObtainWriteLock(&tdc->lock, 661);
2829 if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2830 /* we can do it locally */
2831 code = afs_dir_Delete(tdc, bufp);
2833 ZapDCE(tdc); /* surprise error -- invalid value */
2837 ReleaseWriteLock(&tdc->lock);
2838 afs_PutDCache(tdc); /* drop ref count */
2840 avc->f.states &= ~CUnique; /* For the dfs xlator */
2841 ReleaseWriteLock(&avc->lock);
2844 if (sysState.allocked)
2845 osi_FreeLargeSpace(bufp);
2850 * VIOC_VENUSLOG (34) - Enable/Disable venus logging
2854 * \retval EINVAL Error if some of the standard args aren't set
2856 * \notes Obsoleted, perhaps should be PBogus
2858 DECL_PIOCTL(PVenusLogging)
2860 return EINVAL; /* OBSOLETE */
2864 * VIOC_GETCELLSTATUS (35) - Get cell status info
2868 * \param[in] ain The cell you want status information on
2869 * \param[out] aout cell state (as a struct)
2871 * \retval EIO Error if the afs daemon hasn't started yet
2872 * \retval ENOENT Error if the cell doesn't exist
2874 * \post Returns the state of the cell as defined in a struct cell
2876 DECL_PIOCTL(PGetCellStatus)
2878 register struct cell *tcell;
2881 AFS_STATCNT(PGetCellStatus);
2882 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2883 return EIO; /* Inappropriate ioctl for device */
2885 tcell = afs_GetCellByName(ain, READ_LOCK);
2888 temp = tcell->states;
2889 afs_PutCell(tcell, READ_LOCK);
2890 memcpy(aout, (char *)&temp, sizeof(afs_int32));
2891 *aoutSize = sizeof(afs_int32);
2896 * VIOC_SETCELLSTATUS (36) - Set corresponding info
2900 * \param[in] ain The cell you want to set information about, and the values you want to set
2901 * \param[out] aout not in use
2903 * \retval EIO Error if the afs daemon hasn't started yet
2904 * \retval EACCES Error if the user doesn't have super-user credentials
2906 * \post Set the state of the cell in a defined struct cell, based on whether or not SetUID is allowed
2908 DECL_PIOCTL(PSetCellStatus)
2910 register struct cell *tcell;
2913 if (!afs_osi_suser(*acred))
2915 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2916 return EIO; /* Inappropriate ioctl for device */
2918 tcell = afs_GetCellByName(ain + 2 * sizeof(afs_int32), WRITE_LOCK);
2921 memcpy((char *)&temp, ain, sizeof(afs_int32));
2923 tcell->states |= CNoSUID;
2925 tcell->states &= ~CNoSUID;
2926 afs_PutCell(tcell, WRITE_LOCK);
2931 * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
2935 * \param[in] ain not in use (args in avc)
2936 * \param[out] aout not in use
2938 * \retval EINVAL Error if some of the standard args aren't set
2939 * \retval EIO Error if the afs daemon hasn't started yet
2941 * \post Wipe everything on the volume. This is done dependent on which platform this is for.
2943 * \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.
2945 DECL_PIOCTL(PFlushVolumeData)
2947 register afs_int32 i;
2948 register struct dcache *tdc;
2949 register struct vcache *tvc;
2950 register struct volume *tv;
2951 afs_int32 cell, volume;
2952 struct afs_q *tq, *uq;
2953 #ifdef AFS_DARWIN80_ENV
2957 AFS_STATCNT(PFlushVolumeData);
2960 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2961 return EIO; /* Inappropriate ioctl for device */
2963 volume = avc->f.fid.Fid.Volume; /* who to zap */
2964 cell = avc->f.fid.Cell;
2967 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
2968 * the vcaches associated with the volume.
2971 ObtainReadLock(&afs_xvcache);
2972 i = VCHashV(&avc->f.fid);
2973 for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
2976 if (tvc->f.fid.Fid.Volume == volume && tvc->f.fid.Cell == cell) {
2977 if (tvc->f.states & CVInit) {
2978 ReleaseReadLock(&afs_xvcache);
2979 afs_osi_Sleep(&tvc->f.states);
2982 #ifdef AFS_DARWIN80_ENV
2983 if (tvc->f.states & CDeadVnode) {
2984 ReleaseReadLock(&afs_xvcache);
2985 afs_osi_Sleep(&tvc->f.states);
2989 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
2990 VN_HOLD(AFSTOV(tvc));
2991 #elif defined(AFS_DARWIN80_ENV)
2995 if (vnode_ref(vp)) {
3001 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
3004 VREFCOUNT_INC(tvc); /* AIX, apparently */
3006 ReleaseReadLock(&afs_xvcache);
3007 #ifdef AFS_BOZONLOCK_ENV
3008 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3010 ObtainWriteLock(&tvc->lock, 232);
3012 ObtainWriteLock(&afs_xcbhash, 458);
3013 afs_DequeueCallback(tvc);
3014 tvc->f.states &= ~(CStatd | CDirty);
3015 ReleaseWriteLock(&afs_xcbhash);
3016 if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
3017 osi_dnlc_purgedp(tvc);
3018 afs_TryToSmush(tvc, *acred, 1);
3019 ReleaseWriteLock(&tvc->lock);
3020 #ifdef AFS_BOZONLOCK_ENV
3021 afs_BozonUnlock(&tvc->pvnLock, tvc);
3023 #ifdef AFS_DARWIN80_ENV
3024 vnode_put(AFSTOV(tvc));
3026 ObtainReadLock(&afs_xvcache);
3028 /* our tvc ptr is still good until now */
3032 ReleaseReadLock(&afs_xvcache);
3035 MObtainWriteLock(&afs_xdcache, 328); /* needed if you're going to flush any stuff */
3036 for (i = 0; i < afs_cacheFiles; i++) {
3037 if (!(afs_indexFlags[i] & IFEverUsed))
3038 continue; /* never had any data */
3039 tdc = afs_GetDSlot(i, NULL);
3040 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
3041 ReleaseReadLock(&tdc->tlock);
3042 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
3043 if (!(afs_indexFlags[i] & IFDataMod)) {
3044 /* if the file is modified, but has a ref cnt of only 1, then
3045 * someone probably has the file open and is writing into it.
3046 * Better to skip flushing such a file, it will be brought back
3047 * immediately on the next write anyway.
3049 * If we *must* flush, then this code has to be rearranged to call
3050 * afs_storeAllSegments() first */
3051 afs_FlushDCache(tdc);
3055 ReleaseReadLock(&tdc->tlock);
3057 afs_PutDCache(tdc); /* bumped by getdslot */
3059 MReleaseWriteLock(&afs_xdcache);
3061 ObtainReadLock(&afs_xvolume);
3062 for (i = 0; i < NVOLS; i++) {
3063 for (tv = afs_volumes[i]; tv; tv = tv->next) {
3064 if (tv->volume == volume) {
3065 afs_ResetVolumeInfo(tv);
3070 ReleaseReadLock(&afs_xvolume);
3072 /* probably, a user is doing this, probably, because things are screwed up.
3073 * maybe it's the dnlc's fault? */
3080 * VIOCGETVCXSTATUS (41) - gets vnode x status
3084 * \param[in] ain not in use (avc used)
3085 * \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
3087 * \retval EINVAL Error if some of the initial default arguments aren't set
3088 * \retval EACCES Error if access to check the mode bits is denied
3090 * \post gets stats for the vnode, a struct listed in vcxstat
3092 DECL_PIOCTL(PGetVnodeXStatus)
3094 register afs_int32 code;
3095 struct vcxstat stat;
3098 /* AFS_STATCNT(PGetVnodeXStatus); */
3101 code = afs_VerifyVCache(avc, areq);
3104 if (vType(avc) == VDIR)
3105 mode = PRSFS_LOOKUP;
3108 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3111 memset(&stat, 0, sizeof(struct vcxstat));
3112 stat.fid = avc->f.fid;
3113 hset32(stat.DataVersion, hgetlo(avc->f.m.DataVersion));
3114 stat.lock = avc->lock;
3115 stat.parentVnode = avc->f.parent.vnode;
3116 stat.parentUnique = avc->f.parent.unique;
3117 hset(stat.flushDV, avc->flushDV);
3118 hset(stat.mapDV, avc->mapDV);
3119 stat.truncPos = avc->f.truncPos;
3120 { /* just grab the first two - won't break anything... */
3121 struct axscache *ac;
3123 for (i = 0, ac = avc->Access; ac && i < CPSIZE; i++, ac = ac->next) {
3124 stat.randomUid[i] = ac->uid;
3125 stat.randomAccess[i] = ac->axess;
3128 stat.callback = afs_data_pointer_to_int32(avc->callback);
3129 stat.cbExpires = avc->cbExpires;
3130 stat.anyAccess = avc->f.anyAccess;
3131 stat.opens = avc->opens;
3132 stat.execsOrWriters = avc->execsOrWriters;
3133 stat.flockCount = avc->flockCount;
3134 stat.mvstat = avc->mvstat;
3135 stat.states = avc->f.states;
3136 memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
3137 *aoutSize = sizeof(struct vcxstat);
3142 DECL_PIOCTL(PGetVnodeXStatus2)
3144 register afs_int32 code;
3145 struct vcxstat2 stat;
3150 code = afs_VerifyVCache(avc, areq);
3153 if (vType(avc) == VDIR)
3154 mode = PRSFS_LOOKUP;
3157 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3160 memset(&stat, 0, sizeof(struct vcxstat2));
3162 stat.cbExpires = avc->cbExpires;
3163 stat.anyAccess = avc->f.anyAccess;
3164 stat.mvstat = avc->mvstat;
3165 stat.callerAccess = afs_GetAccessBits(avc, ~0, areq);
3167 memcpy(aout, (char *)&stat, sizeof(struct vcxstat2));
3168 *aoutSize = sizeof(struct vcxstat2);
3174 * VIOC_AFS_SYSNAME (38) - Change @sys value
3178 * \param[in] ain new value for @sys
3179 * \param[out] aout count, entry, list (debug values?)
3181 * \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"
3182 * \retval ENODEV Error if there isn't already a system named that ("I THINK")
3183 * \retval EACCES Error if the user doesn't have super-user credentials
3185 * \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
3187 * \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.
3189 DECL_PIOCTL(PSetSysName)
3191 char *cp, *cp2 = NULL, inname[MAXSYSNAME], outname[MAXSYSNAME];
3192 afs_int32 setsysname;
3194 register struct afs_exporter *exporter;
3195 register struct unixuser *au;
3196 register afs_int32 pag, error;
3197 int t, count, num = 0, allpags = 0;
3200 AFS_STATCNT(PSetSysName);
3201 if (!afs_globalVFS) {
3202 /* Afsd is NOT running; disable it */
3203 #if defined(KERNEL_HAVE_UERROR)
3204 return (setuerror(EINVAL), EINVAL);
3209 memset(inname, 0, MAXSYSNAME);
3210 memcpy(&setsysname, ain, sizeof(afs_int32));
3211 ain += sizeof(afs_int32);
3212 if (setsysname & 0x8000) {
3214 setsysname &= ~0x8000;
3219 if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
3222 for (cp = ain, count = 0; count < setsysname; count++) {
3223 /* won't go past end of ain since maxsysname*num < ain length */
3225 if (t >= MAXSYSNAME || t <= 0)
3227 /* check for names that can shoot us in the foot */
3228 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
3234 /* inname gets first entry in case we're being a translator */
3236 memcpy(inname, ain, t + 1); /* include terminating null */
3240 if ((*acred)->cr_gid == RMTUSER_REQ ||
3241 (*acred)->cr_gid == RMTUSER_REQ_PRIV) { /* Handles all exporters */
3242 if (allpags && (*acred)->cr_gid != RMTUSER_REQ_PRIV) {
3245 pag = PagInCred(*acred);
3247 return EINVAL; /* Better than panicing */
3249 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
3250 return EINVAL; /* Better than panicing */
3252 if (!(exporter = au->exporter)) {
3253 afs_PutUser(au, READ_LOCK);
3254 return EINVAL; /* Better than panicing */
3256 error = EXP_SYSNAME(exporter, (setsysname ? cp2 : NULL), &sysnamelist,
3259 if (error == ENODEV)
3260 foundname = 0; /* sysname not set yet! */
3262 afs_PutUser(au, READ_LOCK);
3267 strcpy(outname, sysnamelist[0]);
3269 afs_PutUser(au, READ_LOCK);
3273 /* Not xlating, so local case */
3275 osi_Panic("PSetSysName: !afs_sysname\n");
3276 if (!setsysname) { /* user just wants the info */
3277 strcpy(outname, afs_sysname);
3278 foundname = afs_sysnamecount;
3279 sysnamelist = afs_sysnamelist;
3280 } else { /* Local guy; only root can change sysname */
3281 if (!afs_osi_suser(*acred))
3284 /* allpags makes no sense for local use */
3288 /* clear @sys entries from the dnlc, once afs_lookup can
3289 * do lookups of @sys entries and thinks it can trust them */
3290 /* privs ok, store the entry, ... */
3291 strcpy(afs_sysname, inname);
3292 if (setsysname > 1) { /* ... or list */
3294 for (count = 1; count < setsysname; ++count) {
3295 if (!afs_sysnamelist[count])
3297 ("PSetSysName: no afs_sysnamelist entry to write\n");
3299 memcpy(afs_sysnamelist[count], cp, t + 1); /* include null */
3303 afs_sysnamecount = setsysname;
3308 cp = aout; /* not changing so report back the count and ... */
3309 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
3310 cp += sizeof(afs_int32);
3312 strcpy(cp, outname); /* ... the entry, ... */
3313 cp += strlen(outname) + 1;
3314 for (count = 1; count < foundname; ++count) { /* ... or list. */
3315 if (!sysnamelist[count])
3317 ("PSetSysName: no afs_sysnamelist entry to read\n");
3318 t = strlen(sysnamelist[count]);
3319 if (t >= MAXSYSNAME)
3320 osi_Panic("PSetSysName: sysname entry garbled\n");
3321 strcpy(cp, sysnamelist[count]);
3325 *aoutSize = cp - aout;
3330 /* sequential search through the list of touched cells is not a good
3331 * long-term solution here. For small n, though, it should be just
3332 * fine. Should consider special-casing the local cell for large n.
3333 * Likewise for PSetSPrefs.
3335 * s - number of ids in array l[] -- NOT index of last id
3336 * l - array of cell ids which have volumes that need to be sorted
3337 * vlonly - sort vl servers or file servers?
3340 ReSortCells_cb(struct cell *cell, void *arg)
3342 afs_int32 *p = (afs_int32 *) arg;
3343 afs_int32 *l = p + 1;
3346 for (i = 0; i < s; i++) {
3347 if (l[i] == cell->cellNum) {
3348 ObtainWriteLock(&cell->lock, 690);
3349 afs_SortServers(cell->cellHosts, MAXCELLHOSTS);
3350 ReleaseWriteLock(&cell->lock);
3358 ReSortCells(int s, afs_int32 * l, int vlonly)
3366 p = (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * (s + 1));
3368 memcpy(p + 1, l, s * sizeof(afs_int32));
3369 afs_TraverseCells(&ReSortCells_cb, p);
3370 afs_osi_Free(p, sizeof(afs_int32) * (s + 1));
3374 ObtainReadLock(&afs_xvolume);
3375 for (i = 0; i < NVOLS; i++) {
3376 for (j = afs_volumes[i]; j; j = j->next) {
3377 for (k = 0; k < s; k++)
3378 if (j->cell == l[k]) {
3379 ObtainWriteLock(&j->lock, 233);
3380 afs_SortServers(j->serverHost, MAXHOSTS);
3381 ReleaseWriteLock(&j->lock);
3386 ReleaseReadLock(&afs_xvolume);
3390 static int debugsetsp = 0;
3392 afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
3395 int i, j, k, matches, touchedSize;
3396 struct server *srvr = NULL;
3397 afs_int32 touched[34];
3401 for (k = 0; k < num; sp++, k++) {
3403 printf("sp host=%x, rank=%d\n", sp->host.s_addr, sp->rank);
3406 ObtainReadLock(&afs_xserver);
3408 i = SHash(sp->host.s_addr);
3409 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
3410 if (sa->sa_ip == sp->host.s_addr) {
3412 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3413 || (sa->sa_portal == AFS_FSPORT);
3414 if ((!vlonly && isfs) || (vlonly && !isfs)) {
3421 if (sa && matches) { /* found one! */
3423 printf("sa ip=%x, ip_rank=%d\n", sa->sa_ip, sa->sa_iprank);
3425 sa->sa_iprank = sp->rank + afs_randomMod15();
3426 afs_SortOneServer(sa->server);
3429 /* if we don't know yet what cell it's in, this is moot */
3430 for (j = touchedSize - 1;
3431 j >= 0 && touched[j] != srvr->cell->cellNum; j--)
3432 /* is it in our list of touched cells ? */ ;
3433 if (j < 0) { /* no, it's not */
3434 touched[touchedSize++] = srvr->cell->cellNum;
3435 if (touchedSize >= 32) { /* watch for ovrflow */
3436 ReleaseReadLock(&afs_xserver);
3437 ReSortCells(touchedSize, touched, vlonly);
3439 ObtainReadLock(&afs_xserver);
3445 ReleaseReadLock(&afs_xserver);
3446 /* if we didn't find one, start to create one. */
3447 /* Note that it doesn't have a cell yet... */
3449 afs_uint32 temp = sp->host.s_addr;
3451 afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
3452 WRITE_LOCK, (afsUUID *) 0, 0);
3453 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3454 afs_PutServer(srvr, WRITE_LOCK);
3456 } /* for all cited preferences */
3458 ReSortCells(touchedSize, touched, vlonly);
3463 * VIOC_SETPREFS (46) - Set server ranks
3465 * \param[in] ain the sprefs value you want the sprefs to be set to
3466 * \param[out] aout not in use
3468 * \retval EIO Error if the afs daemon hasn't started yet
3469 * \retval EACCES Error if the user doesn't have super-user credentials
3470 * \retval EINVAL Error if the struct setsprefs is too large or if it multiplied by the number of servers is too large
3472 * \post set the sprefs using the afs_setsprefs() function
3474 DECL_PIOCTL(PSetSPrefs)
3476 struct setspref *ssp;
3477 AFS_STATCNT(PSetSPrefs);
3479 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3480 return EIO; /* Inappropriate ioctl for device */
3482 if (!afs_osi_suser(*acred))
3485 if (ainSize < sizeof(struct setspref))
3488 ssp = (struct setspref *)ain;
3489 if (ainSize < sizeof(struct spref) * ssp->num_servers)
3492 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
3493 (ssp->flags & DBservers));
3498 * VIOC_SETPREFS33 (42) - Set server ranks (deprecated)
3500 * \param[in] ain the server preferences to be set
3501 * \param[out] aout not in use
3503 * \retval EIO Error if the afs daemon hasn't started yet
3504 * \retval EACCES Error if the user doesn't have super-user credentials
3506 * \post set the server preferences, calling a function
3508 * \notes this may only be performed by the local root user.
3510 DECL_PIOCTL(PSetSPrefs33)
3513 AFS_STATCNT(PSetSPrefs);
3514 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3515 return EIO; /* Inappropriate ioctl for device */
3518 if (!afs_osi_suser(*acred))
3521 sp = (struct spref *)ain;
3522 afs_setsprefs(sp, ainSize / (sizeof(struct spref)), 0 /*!vlonly */ );
3527 * VIOC_GETSPREFS (43) - Get server ranks
3531 * \param[in] ain the server preferences to get
3532 * \param[out] aout the server preferences information
3534 * \retval EIO Error if the afs daemon hasn't started yet
3535 * \retval ENOENT Error if the sprefrequest is too large
3537 * \post Get the sprefs
3539 * \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.
3541 DECL_PIOCTL(PGetSPrefs)
3543 struct sprefrequest *spin; /* input */
3544 struct sprefinfo *spout; /* output */
3545 struct spref *srvout; /* one output component */
3546 int i, j; /* counters for hash table traversal */
3547 struct server *srvr; /* one of CM's server structs */
3549 int vlonly; /* just return vlservers ? */
3552 AFS_STATCNT(PGetSPrefs);
3553 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3554 return EIO; /* Inappropriate ioctl for device */
3557 if (ainSize < sizeof(struct sprefrequest_33)) {
3560 spin = ((struct sprefrequest *)ain);
3563 if (ainSize > sizeof(struct sprefrequest_33)) {
3564 vlonly = (spin->flags & DBservers);
3568 /* struct sprefinfo includes 1 server struct... that size gets added
3569 * in during the loop that follows.
3571 *aoutSize = sizeof(struct sprefinfo) - sizeof(struct spref);
3572 spout = (struct sprefinfo *)aout;
3573 spout->next_offset = spin->offset;
3574 spout->num_servers = 0;
3575 srvout = spout->servers;
3577 ObtainReadLock(&afs_xserver);
3578 for (i = 0, j = 0; j < NSERVERS; j++) { /* sift through hash table */
3579 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3580 if (spin->offset > (unsigned short)i) {
3581 continue; /* catch up to where we left off */
3583 spout->next_offset++;
3586 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3587 || (sa->sa_portal == AFS_FSPORT);
3589 if ((vlonly && isfs) || (!vlonly && !isfs)) {
3590 /* only report ranks for vl servers */
3594 srvout->host.s_addr = sa->sa_ip;
3595 srvout->rank = sa->sa_iprank;
3596 *aoutSize += sizeof(struct spref);
3597 spout->num_servers++;
3600 if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3601 ReleaseReadLock(&afs_xserver); /* no more room! */
3606 ReleaseReadLock(&afs_xserver);
3608 spout->next_offset = 0; /* start over from the beginning next time */
3612 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3613 int afs_NFSRootOnly = 1;
3615 * VIOC_EXPORTAFS (39) - Export afs to nfs clients
3619 * \param[in] ain a struct Vic * EIOctl containing export values needed to change between nfs and afs
3620 * \param[out] aout a struct of the exporter states (exporter->exp_states)
3622 * \retval ENODEV Error if the exporter doesn't exist
3623 * \retval EACCES Error if the user doesn't have super-user credentials
3625 * \post Changes the state of various values to reflect the change of the export values between nfs and afs.
3627 * \notes Legacy code obtained from IBM.
3629 DECL_PIOCTL(PExportAfs)
3631 afs_int32 export, newint =
3632 0, type, changestate, handleValue, convmode, pwsync, smounts;
3633 afs_int32 rempags = 0, pagcb = 0;
3634 register struct afs_exporter *exporter;
3636 AFS_STATCNT(PExportAfs);
3637 memcpy((char *)&handleValue, ain, sizeof(afs_int32));
3638 type = handleValue >> 24;
3643 exporter = exporter_find(type);
3645 export = handleValue & 3;
3646 changestate = handleValue & 0xfff;
3647 smounts = (handleValue >> 2) & 3;
3648 pwsync = (handleValue >> 4) & 3;
3649 convmode = (handleValue >> 6) & 3;
3650 rempags = (handleValue >> 8) & 3;
3651 pagcb = (handleValue >> 10) & 3;
3653 changestate = (handleValue >> 16) & 0x1;
3654 convmode = (handleValue >> 16) & 0x2;
3655 pwsync = (handleValue >> 16) & 0x4;
3656 smounts = (handleValue >> 16) & 0x8;
3657 export = handleValue & 0xff;
3660 /* Failed finding desired exporter; */
3664 handleValue = exporter->exp_states;
3665 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3666 *aoutSize = sizeof(afs_int32);
3668 if (!afs_osi_suser(*acred))
3669 return EACCES; /* Only superuser can do this */
3673 exporter->exp_states |= EXP_EXPORTED;
3675 exporter->exp_states &= ~EXP_EXPORTED;
3679 exporter->exp_states |= EXP_UNIXMODE;
3681 exporter->exp_states &= ~EXP_UNIXMODE;
3685 exporter->exp_states |= EXP_PWSYNC;
3687 exporter->exp_states &= ~EXP_PWSYNC;
3691 afs_NFSRootOnly = 0;
3692 exporter->exp_states |= EXP_SUBMOUNTS;
3694 afs_NFSRootOnly = 1;
3695 exporter->exp_states &= ~EXP_SUBMOUNTS;
3700 exporter->exp_states |= EXP_CLIPAGS;
3702 exporter->exp_states &= ~EXP_CLIPAGS;
3706 exporter->exp_states |= EXP_CALLBACK;
3708 exporter->exp_states &= ~EXP_CALLBACK;
3710 handleValue = exporter->exp_states;
3711 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3712 *aoutSize = sizeof(afs_int32);
3715 exporter->exp_states |= EXP_EXPORTED;
3717 exporter->exp_states &= ~EXP_EXPORTED;
3719 exporter->exp_states |= EXP_UNIXMODE;
3721 exporter->exp_states &= ~EXP_UNIXMODE;
3723 exporter->exp_states |= EXP_PWSYNC;
3725 exporter->exp_states &= ~EXP_PWSYNC;
3727 afs_NFSRootOnly = 0;
3728 exporter->exp_states |= EXP_SUBMOUNTS;
3730 afs_NFSRootOnly = 1;
3731 exporter->exp_states &= ~EXP_SUBMOUNTS;
3740 * VIOC_GAG (44) - Silence Cache Manager
3744 * \param[in] ain the flags to either gag or de-gag the cache manager
3745 * \param[out] aout not in use
3747 * \retval EACCES Error if the user doesn't have super-user credentials
3749 * \post set the gag flags, then show these flags
3753 struct gaginfo *gagflags;
3755 if (!afs_osi_suser(*acred))
3758 gagflags = (struct gaginfo *)ain;
3759 afs_showflags = gagflags->showflags;
3765 * VIOC_TWIDDLE (45) - Adjust RX knobs
3769 * \param[in] ain the previous settings of the 'knobs'
3770 * \param[out] aout not in use
3772 * \retval EACCES Error if the user doesn't have super-user credentials
3774 * \post build out the struct rxp, from a struct rx
3776 DECL_PIOCTL(PTwiddleRx)
3778 struct rxparams *rxp;
3780 if (!afs_osi_suser(*acred))
3783 rxp = (struct rxparams *)ain;
3785 if (rxp->rx_initReceiveWindow)
3786 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3787 if (rxp->rx_maxReceiveWindow)
3788 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3789 if (rxp->rx_initSendWindow)
3790 rx_initSendWindow = rxp->rx_initSendWindow;
3791 if (rxp->rx_maxSendWindow)
3792 rx_maxSendWindow = rxp->rx_maxSendWindow;
3793 if (rxp->rxi_nSendFrags)
3794 rxi_nSendFrags = rxp->rxi_nSendFrags;
3795 if (rxp->rxi_nRecvFrags)
3796 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3797 if (rxp->rxi_OrphanFragSize)
3798 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3799 if (rxp->rx_maxReceiveSize) {
3800 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3801 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3803 if (rxp->rx_MyMaxSendSize)
3804 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3810 * VIOC_GETINITPARAMS (49) - Get initial cache manager parameters
3814 * \param[in] ain not in use
3815 * \param[out] aout initial cache manager params
3817 * \retval E2BIG Error if the initial parameters are bigger than some PIGGYSIZE
3819 * \post return the initial cache manager parameters
3821 DECL_PIOCTL(PGetInitParams)
3823 if (sizeof(struct cm_initparams) > PIGGYSIZE)
3826 memcpy(aout, (char *)&cm_initParams, sizeof(struct cm_initparams));
3827 *aoutSize = sizeof(struct cm_initparams);
3831 #ifdef AFS_SGI65_ENV
3832 /* They took crget() from us, so fake it. */
3837 cr = crdup(get_current_cred());
3838 memset(cr, 0, sizeof(cred_t));
3839 #if CELL || CELL_PREPARE
3847 * VIOC_GETRXKCRYPT (55) - Get rxkad encryption flag
3851 * \param[in] ain not in use
3852 * \param[out] aout value of cryptall
3854 * \post get the value of cryptall (presumably whether or not things should be encrypted)
3856 DECL_PIOCTL(PGetRxkcrypt)
3858 memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3859 *aoutSize = sizeof(afs_int32);
3864 * VIOC_SETRXKCRYPT (56) - Set rxkad encryption flag
3868 * \param[in] ain the argument whether or not things should be encrypted
3869 * \param[out] aout not in use
3871 * \retval EPERM Error if the user doesn't have super-user credentials
3872 * \retval EINVAL Error if the input is too big, or if the input is outside the bounds of what it can be set to
3874 * \post set whether or not things should be encrypted
3876 * \notes may need to be modified at a later date to take into account other values for cryptall (beyond true or false)
3878 DECL_PIOCTL(PSetRxkcrypt)
3882 if (!afs_osi_suser(*acred))
3884 if (ainSize != sizeof(afs_int32) || ain == NULL)
3886 memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3887 /* if new mappings added later this will need to be changed */
3888 if (tmpval != 0 && tmpval != 1)
3894 #ifdef AFS_NEED_CLIENTCONTEXT
3896 * Create new credentials to correspond to a remote user with given
3897 * <hostaddr, uid, g0, g1>. This allows a server running as root to
3898 * provide pioctl (and other) services to foreign clients (i.e. nfs
3899 * clients) by using this call to `become' the client.
3902 #define PIOCTL_HEADER 6
3904 HandleClientContext(struct afs_ioctl *ablob, int *com,
3905 afs_ucred_t **acred, AFS_UCRED *credp)
3908 afs_uint32 hostaddr;
3909 afs_int32 uid, g0, g1, i, code, pag, exporter_type, isroot = 0;
3910 struct afs_exporter *exporter, *outexporter;
3911 afs_ucred_t *newcred;
3912 struct unixuser *au;
3913 afs_uint32 comp = *com & 0xff00;
3916 #if defined(AFS_SGIMP_ENV)
3917 osi_Assert(ISAFS_GLOCK());
3919 AFS_STATCNT(HandleClientContext);
3920 if (ablob->in_size < PIOCTL_HEADER * sizeof(afs_int32)) {
3921 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3922 return EINVAL; /* Too small to be good */
3924 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3925 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER * sizeof(afs_int32), code);
3927 osi_FreeLargeSpace(inData);
3931 /* Extract information for remote user */
3932 hostaddr = *((afs_uint32 *) ain);
3933 ain += sizeof(hostaddr);
3934 uid = *((afs_uint32 *) ain);
3936 g0 = *((afs_uint32 *) ain);
3938 g1 = *((afs_uint32 *) ain);
3940 *com = *((afs_uint32 *) ain);
3941 ain += sizeof(afs_int32);
3942 exporter_type = *((afs_uint32 *) ain); /* In case we support more than NFS */
3945 * Of course, one must be root for most of these functions, but
3946 * we'll allow (for knfs) you to set things if the pag is 0 and
3947 * you're setting tokens or unlogging.
3950 if (!afs_osi_suser(credp)) {
3951 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI64_ENV)
3952 /* Since SGI's suser() returns explicit failure after the call.. */
3955 /* check for acceptable opcodes for normal folks, which are, so far,
3956 * get/set tokens, sysname, and unlog.
3958 if (i != 9 && i != 3 && i != 38 && i != 8) {
3959 osi_FreeLargeSpace(inData);
3964 ablob->in_size -= PIOCTL_HEADER * sizeof(afs_int32);
3965 ablob->in += PIOCTL_HEADER * sizeof(afs_int32);
3966 osi_FreeLargeSpace(inData);
3969 * We map uid 0 to nobody to match the mapping that the nfs
3970 * server does and to ensure that the suser() calls in the afs
3971 * code fails for remote client roots.
3973 uid = afs_nobody; /* NFS_NOBODY == -2 */
3977 #ifdef AFS_AIX41_ENV
3980 newcred->cr_gid = isroot ? RMTUSER_REQ_PRIV : RMTUSER_REQ;
3981 #ifdef AFS_AIX51_ENV
3982 newcred->cr_groupset.gs_union.un_groups[0] = g0;
3983 newcred->cr_groupset.gs_union.un_groups[1] = g1;
3984 #elif defined(AFS_LINUX26_ENV)
3985 #ifdef AFS_LINUX26_ONEGROUP_ENV
3986 newcred->cr_group_info = groups_alloc(1); /* not that anything sets this */
3987 l = (((g0-0x3f00) & 0x3fff) << 14) | ((g1-0x3f00) & 0x3fff);
3988 h = ((g0-0x3f00) >> 14);
3989 h = ((g1-0x3f00) >> 14) + h + h + h;
3990 GROUP_AT(newcred->cr_group_info, 0) = ((h << 28) | l);
3992 newcred->cr_group_info = groups_alloc(2);
3993 GROUP_AT(newcred->cr_group_info, 0) = g0;
3994 GROUP_AT(newcred->cr_group_info, 1) = g1;
3997 newcred->cr_groups[0] = g0;
3998 newcred->cr_groups[1] = g1;
4001 newcred->cr_ngrps = 2;
4002 #elif !defined(AFS_LINUX26_ENV)
4003 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
4004 newcred->cr_ngroups = 2;
4006 for (i = 2; i < NGROUPS; i++)
4007 newcred->cr_groups[i] = NOGROUP;
4010 if (!(exporter = exporter_find(exporter_type))) {
4011 /* Exporter wasn't initialized or an invalid exporter type */
4015 if (exporter->exp_states & EXP_PWSYNC) {
4016 if (uid != credp->cr_uid) {
4018 return ENOEXEC; /* XXX Find a better errno XXX */
4021 newcred->cr_uid = uid; /* Only temporary */
4022 code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
4023 /* The client's pag is the only unique identifier for it */
4024 newcred->cr_uid = pag;
4026 if (!code && *com == PSETPAG) {
4027 /* Special case for 'setpag' */
4028 afs_uint32 pagvalue = genpag();
4030 au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
4032 * Note that we leave the 'outexporter' struct held so it won't
4035 au->exporter = outexporter;
4036 if (ablob->out_size >= 4) {
4037 AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32),
4040 afs_PutUser(au, WRITE_LOCK);
4043 return PSETPAG; /* Special return for setpag */
4045 EXP_RELE(outexporter);
4048 *com = (*com) | comp;
4051 #endif /* AFS_NEED_CLIENTCONTEXT */
4055 * VIOC_GETCPREFS (50) - Get client interface
4059 * \param[in] ain sprefrequest input
4060 * \param[out] aout spref information
4062 * \retval EIO Error if the afs daemon hasn't started yet
4063 * \retval EINVAL Error if some of the standard args aren't set
4065 * \post get all interface addresses and other information of the client interface
4067 DECL_PIOCTL(PGetCPrefs)
4069 struct sprefrequest *spin; /* input */
4070 struct sprefinfo *spout; /* output */
4071 struct spref *srvout; /* one output component */
4075 AFS_STATCNT(PGetCPrefs);
4076 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4077 return EIO; /* Inappropriate ioctl for device */
4079 if (ainSize < sizeof(struct sprefrequest))
4082 spin = (struct sprefrequest *)ain;
4083 spout = (struct sprefinfo *)aout;
4085 maxNumber = spin->num_servers; /* max addrs this time */
4086 srvout = spout->servers;
4088 ObtainReadLock(&afs_xinterface);
4090 /* copy out the client interface information from the
4091 ** kernel data structure "interface" to the output buffer
4093 for (i = spin->offset, j = 0; (i < afs_cb_interface.numberOfInterfaces)
4094 && (j < maxNumber); i++, j++, srvout++)
4095 srvout->host.s_addr = afs_cb_interface.addr_in[i];
4097 spout->num_servers = j;
4098 *aoutSize = sizeof(struct sprefinfo) + (j - 1) * sizeof(struct spref);
4100 if (i >= afs_cb_interface.numberOfInterfaces)
4101 spout->next_offset = 0; /* start from beginning again */
4103 spout->next_offset = spin->offset + j;
4105 ReleaseReadLock(&afs_xinterface);
4110 * VIOC_SETCPREFS (51) - Set client interface
4114 * \param[in] ain the interfaces you want set
4115 * \param[out] aout not in use
4117 * \retval EIO Error if the afs daemon hasn't started yet
4118 * \retval EINVAL Error if the input is too large for the struct
4119 * \retval ENOMEM Error if there are too many servers
4121 * \post set the callbak interfaces addresses to those of the hosts
4123 DECL_PIOCTL(PSetCPrefs)
4125 struct setspref *sin;
4128 AFS_STATCNT(PSetCPrefs);
4129 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4130 return EIO; /* Inappropriate ioctl for device */
4132 sin = (struct setspref *)ain;
4134 if (ainSize < sizeof(struct setspref))
4136 #if 0 /* num_servers is unsigned */
4137 if (sin->num_servers < 0)
4140 if (sin->num_servers > AFS_MAX_INTERFACE_ADDR)
4143 ObtainWriteLock(&afs_xinterface, 412);
4144 afs_cb_interface.numberOfInterfaces = sin->num_servers;
4145 for (i = 0; (unsigned short)i < sin->num_servers; i++)
4146 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
4148 ReleaseWriteLock(&afs_xinterface);
4153 * VIOC_AFS_FLUSHMOUNT (52) - Flush mount symlink data
4157 * \param[in] ain the last part of a path to a mount point, which tells us what to flush
4158 * \param[out] aout not in use
4160 * \retval EINVAL Error if some of the initial arguments aren't set
4161 * \retval ENOTDIR Error if the initial argument for the mount point isn't a directory
4162 * \retval ENOENT Error if the dcache entry isn't set
4164 * \post remove all of the mount data from the dcache regarding a certain mount point
4166 DECL_PIOCTL(PFlushMount)
4168 register afs_int32 code;
4169 register struct vcache *tvc;
4170 register struct dcache *tdc;
4171 struct VenusFid tfid;
4173 struct sysname_info sysState;
4174 afs_size_t offset, len;
4176 AFS_STATCNT(PFlushMount);
4179 code = afs_VerifyVCache(avc, areq);
4182 if (vType(avc) != VDIR) {
4185 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
4188 Check_AtSys(avc, ain, &sysState, areq);
4189 ObtainReadLock(&tdc->lock);
4191 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
4192 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
4193 ReleaseReadLock(&tdc->lock);
4194 afs_PutDCache(tdc); /* we're done with the data */
4195 bufp = sysState.name;
4199 tfid.Cell = avc->f.fid.Cell;
4200 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
4201 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
4202 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
4204 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4210 if (tvc->mvstat != 1) {
4215 #ifdef AFS_BOZONLOCK_ENV
4216 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
4218 ObtainWriteLock(&tvc->lock, 649);
4219 ObtainWriteLock(&afs_xcbhash, 650);
4220 afs_DequeueCallback(tvc);
4221 tvc->f.states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
4222 ReleaseWriteLock(&afs_xcbhash);
4223 /* now find the disk cache entries */
4224 afs_TryToSmush(tvc, *acred, 1);
4225 osi_dnlc_purgedp(tvc);
4226 if (tvc->linkData && !(tvc->f.states & CCore)) {
4227 afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
4228 tvc->linkData = NULL;
4230 ReleaseWriteLock(&tvc->lock);
4231 #ifdef AFS_BOZONLOCK_ENV
4232 afs_BozonUnlock(&tvc->pvnLock, tvc);
4236 if (sysState.allocked)
4237 osi_FreeLargeSpace(bufp);
4242 * VIOC_RXSTAT_PROC (53) - Control process RX statistics
4246 * \param[in] ain the flags that control which stats to use
4247 * \param[out] aout not in use
4249 * \retval EACCES Error if the user doesn't have super-user credentials
4250 * \retval EINVAL Error if the flag input is too long
4252 * \post either enable process RPCStats, disable process RPCStats, or clear the process RPCStats
4254 DECL_PIOCTL(PRxStatProc)
4259 if (!afs_osi_suser(*acred)) {
4263 if (ainSize != sizeof(afs_int32)) {
4267 memcpy((char *)&flags, ain, sizeof(afs_int32));
4268 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4272 if (flags & AFSCALL_RXSTATS_ENABLE) {
4273 rx_enableProcessRPCStats();
4275 if (flags & AFSCALL_RXSTATS_DISABLE) {
4276 rx_disableProcessRPCStats();
4278 if (flags & AFSCALL_RXSTATS_CLEAR) {
4279 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
4288 * VIOC_RXSTAT_PEER (54) - Control peer RX statistics
4292 * \param[in] ain the flags that control which statistics to use
4293 * \param[out] aout not in use
4295 * \retval EACCES Error if the user doesn't have super-user credentials
4296 * \retval EINVAL Error if the flag input is too long
4298 * \post either enable peer RPCStatws, disable peer RPCStats, or clear the peer RPCStats
4300 DECL_PIOCTL(PRxStatPeer)
4305 if (!afs_osi_suser(*acred)) {
4309 if (ainSize != sizeof(afs_int32)) {
4313 memcpy((char *)&flags, ain, sizeof(afs_int32));
4314 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4318 if (flags & AFSCALL_RXSTATS_ENABLE) {
4319 rx_enablePeerRPCStats();
4321 if (flags & AFSCALL_RXSTATS_DISABLE) {
4322 rx_disablePeerRPCStats();
4324 if (flags & AFSCALL_RXSTATS_CLEAR) {
4325 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
4332 DECL_PIOCTL(PPrefetchFromTape)
4334 register afs_int32 code, code1;
4336 struct afs_conn *tc;
4337 struct rx_call *tcall;
4338 struct AFSVolSync tsync;
4339 struct AFSFetchStatus OutStatus;
4340 struct AFSCallBack CallBack;
4341 struct VenusFid tfid;
4345 AFS_STATCNT(PSetAcl);
4349 if (ain && (ainSize == 3 * sizeof(afs_int32)))
4350 Fid = (struct AFSFid *)ain;
4352 Fid = &avc->f.fid.Fid;
4353 tfid.Cell = avc->f.fid.Cell;
4354 tfid.Fid.Volume = Fid->Volume;
4355 tfid.Fid.Vnode = Fid->Vnode;
4356 tfid.Fid.Unique = Fid->Unique;
4358 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4360 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4361 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &avc->f.fid);
4364 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4365 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &tvc->f.fid);
4368 tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
4372 tcall = rx_NewCall(tc->id);
4374 StartRXAFS_FetchData(tcall, (struct AFSFid *)&tvc->f.fid.Fid, 0,
4377 bytes = rx_Read(tcall, (char *)aout, sizeof(afs_int32));
4379 EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
4381 code1 = rx_EndCall(tcall, code);
4385 } while (afs_Analyze
4386 (tc, code, &tvc->f.fid, areq, AFS_STATS_FS_RPCIDX_RESIDENCYRPCS,
4387 SHARED_LOCK, NULL));
4388 /* This call is done only to have the callback things handled correctly */
4389 afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
4393 *aoutSize = sizeof(afs_int32);
4400 register afs_int32 code;
4401 struct afs_conn *tc;
4403 struct FsCmdInputs *Inputs;
4404 struct FsCmdOutputs *Outputs;
4405 struct VenusFid tfid;
4408 Inputs = (struct FsCmdInputs *)ain;
4409 Outputs = (struct FsCmdOutputs *)aout;
4412 if (!ain || ainSize != sizeof(struct FsCmdInputs))
4417 Fid = &avc->f.fid.Fid;
4419 tfid.Cell = avc->f.fid.Cell;
4420 tfid.Fid.Volume = Fid->Volume;
4421 tfid.Fid.Vnode = Fid->Vnode;
4422 tfid.Fid.Unique = Fid->Unique;
4424 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4425 afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD, ICL_TYPE_POINTER, tvc,
4426 ICL_TYPE_INT32, Inputs->command, ICL_TYPE_FID, &tfid);
4430 if (Inputs->command) {
4432 tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
4436 RXAFS_FsCmd(tc->id, Fid, Inputs,
4437 (struct FsCmdOutputs *)aout);
4441 } while (afs_Analyze
4442 (tc, code, &tvc->f.fid, areq,
4443 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK, NULL));
4444 /* This call is done to have the callback things handled correctly */
4445 afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4446 } else { /* just a status request, return also link data */
4448 Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4449 Outputs->chars[0] = 0;
4450 if (vType(tvc) == VLNK) {
4451 ObtainWriteLock(&tvc->lock, 555);
4452 if (afs_HandleLink(tvc, areq) == 0)
4453 strncpy((char *)&Outputs->chars, tvc->linkData, MAXCMDCHARS);
4454 ReleaseWriteLock(&tvc->lock);
4461 *aoutSize = sizeof(struct FsCmdOutputs);
4466 DECL_PIOCTL(PNewUuid)
4468 /*AFS_STATCNT(PNewUuid); */
4469 if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4470 return EIO; /* Inappropriate ioctl for device */
4472 if (!afs_osi_suser(acred))
4475 ObtainWriteLock(&afs_xinterface, 555);
4476 afs_uuid_create(&afs_cb_interface.uuid);
4477 ReleaseWriteLock(&afs_xinterface);
4478 ForceAllNewConnections();
4482 #if defined(AFS_CACHE_BYPASS)
4484 DECL_PIOCTL(PSetCachingThreshold)
4489 setting = getting = 1;
4491 if (ain == NULL || ainSize < sizeof(afs_int32))
4497 if (setting == 0 && getting == 0)
4501 * If setting, set first, and return the value now in effect
4504 afs_int32 threshold;
4506 if (!afs_osi_suser(*acred))
4508 memcpy((char *)&threshold, ain, sizeof(afs_int32));
4509 cache_bypass_threshold = threshold;
4510 afs_warn("Cache Bypass Threshold set to: %d\n", threshold);
4511 /* TODO: move to separate pioctl, or enhance pioctl */
4512 cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
4516 /* Return the current size threshold */
4517 afs_int32 oldThreshold = cache_bypass_threshold;
4518 memcpy(aout, (char *)&oldThreshold, sizeof(afs_int32));
4519 *aoutSize = sizeof(afs_int32);
4525 #endif /* defined(AFS_CACHE_BYPASS) */
4527 DECL_PIOCTL(PCallBackAddr)
4530 afs_uint32 addr, code;
4534 struct afs_conn *tc;
4536 struct unixuser *tu;
4537 struct srvAddr **addrs;
4539 /*AFS_STATCNT(PCallBackAddr); */
4540 if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4541 return EIO; /* Inappropriate ioctl for device */
4543 if (!afs_osi_suser(acred))
4546 if (ainSize < sizeof(afs_int32))
4549 memcpy(&addr, ain, sizeof(afs_int32));
4551 ObtainReadLock(&afs_xinterface);
4552 for (i = 0; (unsigned short)i < afs_cb_interface.numberOfInterfaces; i++) {
4553 if (afs_cb_interface.addr_in[i] == addr)
4557 ReleaseWriteLock(&afs_xinterface);
4559 if (afs_cb_interface.addr_in[i] != addr)
4562 ObtainReadLock(&afs_xserver); /* Necessary? */
4563 ObtainReadLock(&afs_xsrvAddr);
4566 for (i = 0; i < NSERVERS; i++) {
4567 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4572 addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
4574 for (i = 0; i < NSERVERS; i++) {
4575 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4576 if (j >= srvAddrCount)
4582 ReleaseReadLock(&afs_xsrvAddr);
4583 ReleaseReadLock(&afs_xserver);
4585 for (i = 0; i < j; i++) {
4591 /* vlserver has no callback conn */
4592 if (sa->sa_portal == AFS_VLPORT) {
4596 if (!ts->cell) /* not really an active server, anyway, it must */
4597 continue; /* have just been added by setsprefs */
4599 /* get a connection, even if host is down; bumps conn ref count */
4600 tu = afs_GetUser(areq->uid, ts->cell->cellNum, SHARED_LOCK);
4601 tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
4602 1 /*force */ , 1 /*create */ , SHARED_LOCK);
4603 afs_PutUser(tu, SHARED_LOCK);
4607 if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(ts)) {
4608 if (sa->sa_flags & SRVADDR_ISDOWN) {
4609 rx_SetConnDeadTime(tc->id, 3);
4611 #ifdef RX_ENABLE_LOCKS
4613 #endif /* RX_ENABLE_LOCKS */
4614 code = RXAFS_CallBackRxConnAddr(tc->id, &addr);
4615 #ifdef RX_ENABLE_LOCKS
4617 #endif /* RX_ENABLE_LOCKS */
4619 afs_PutConn(tc, SHARED_LOCK); /* done with it now */
4620 } /* Outer loop over addrs */
4621 #endif /* UKERNEL */
4625 DECL_PIOCTL(PDiscon)
4627 #ifdef AFS_DISCON_ENV
4628 static afs_int32 mode = 1; /* Start up in 'off' */
4629 afs_int32 force = 0;
4634 if (!afs_osi_suser(*acred))
4640 afs_ConflictPolicy = ain[1] - 1;
4645 * All of these numbers are hard coded in fs.c. If they
4646 * change here, they should change there and vice versa
4649 case 0: /* Disconnect ("offline" mode), breaking all callbacks */
4650 if (!AFS_IS_DISCONNECTED) {
4651 ObtainWriteLock(&afs_discon_lock, 999);
4652 afs_DisconGiveUpCallbacks();
4653 afs_RemoveAllConns();
4654 afs_is_disconnected = 1;
4655 afs_is_discon_rw = 1;
4656 ReleaseWriteLock(&afs_discon_lock);
4659 case 1: /* Fully connected, ("online" mode). */
4660 ObtainWriteLock(&afs_discon_lock, 998);
4663 afs_MarkAllServersUp();
4664 code = afs_ResyncDisconFiles(areq, *acred);
4667 if (code && !force) {
4668 printf("Files not synchronized properly, still in discon state. \n"
4669 "Please retry or use \"force\".\n");
4673 afs_DisconDiscardAll(*acred);
4675 afs_ClearAllStatdFlag();
4676 afs_is_disconnected = 0;
4677 afs_is_discon_rw = 0;
4678 printf("\nSync succeeded. You are back online.\n");
4681 ReleaseWriteLock(&afs_discon_lock);
4690 memcpy(aout, &mode, sizeof(afs_int32));
4691 *aoutSize = sizeof(afs_int32);
4698 DECL_PIOCTL(PNFSNukeCreds)
4701 register afs_int32 i;
4702 register struct unixuser *tu;
4704 AFS_STATCNT(PUnlog);
4705 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4706 return EIO; /* Inappropriate ioctl for device */
4708 if (ainSize < sizeof(afs_int32))
4710 memcpy(&addr, ain, sizeof(afs_int32));
4712 if ((*acred)->cr_gid == RMTUSER_REQ_PRIV && !addr) {
4713 tu = afs_GetUser(areq->uid, -1, SHARED_LOCK);
4714 if (!tu->exporter || !(addr = EXP_GETHOST(tu->exporter))) {
4715 afs_PutUser(tu, SHARED_LOCK);
4718 afs_PutUser(tu, SHARED_LOCK);
4719 } else if (!afs_osi_suser(acred)) {
4723 ObtainWriteLock(&afs_xuser, 227);
4724 for (i = 0; i < NUSERS; i++) {
4725 for (tu = afs_users[i]; tu; tu = tu->next) {
4726 if (tu->exporter && EXP_CHECKHOST(tu->exporter, addr)) {
4728 tu->states &= ~UHasTokens;
4729 /* security is not having to say you're sorry */
4730 memset(&tu->ct, 0, sizeof(struct ClearToken));
4732 ReleaseWriteLock(&afs_xuser);
4733 afs_ResetUserConns(tu);
4735 ObtainWriteLock(&afs_xuser, 228);
4737 /* set the expire times to 0, causes
4738 * afs_GCUserData to remove this entry
4740 tu->ct.EndTimestamp = 0;
4742 #endif /* UKERNEL */
4746 ReleaseWriteLock(&afs_xuser);