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 * \post get PAG value for the caller's cred
2347 DECL_PIOCTL(PGetPAG)
2351 pag = PagInCred(*acred);
2353 memcpy(aout, (char *)&pag, sizeof(afs_int32));
2354 *aoutSize = sizeof(afs_int32);
2358 DECL_PIOCTL(PPrecache)
2362 /*AFS_STATCNT(PPrecache);*/
2363 if (!afs_osi_suser(*acred))
2365 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2366 afs_preCache = newValue*1024;
2371 * VIOCSETCACHESIZE (24) - Set venus cache size in 1000 units
2375 * \param[in] ain the size the venus cache should be set to
2376 * \param[out] aout not in use
2378 * \retval EACCES Error if the user doesn't have super-user credentials
2379 * \retval EROFS Error if the cache is set to be in memory
2381 * \post Set the cache size based on user input. If no size is given, set it to the default OpenAFS cache size.
2383 * \notes recompute the general cache parameters for every single block allocated
2385 DECL_PIOCTL(PSetCacheSize)
2390 AFS_STATCNT(PSetCacheSize);
2391 if (!afs_osi_suser(*acred))
2393 /* too many things are setup initially in mem cache version */
2394 if (cacheDiskType == AFS_FCACHE_TYPE_MEM)
2396 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2398 afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2400 if (newValue < afs_min_cache)
2401 afs_cacheBlocks = afs_min_cache;
2403 afs_cacheBlocks = newValue;
2405 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2406 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2407 afs_MaybeWakeupTruncateDaemon();
2408 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2409 afs_osi_Wait(1000, 0, 0);
2410 afs_MaybeWakeupTruncateDaemon();
2415 #define MAXGCSTATS 16
2417 * VIOCGETCACHEPARMS (40) - Get cache stats
2421 * \param[in] ain afs index flags
2422 * \param[out] aout cache blocks, blocks used, blocks files (in an array)
2424 * \post Get the cache blocks, and how many of the cache blocks there are
2426 DECL_PIOCTL(PGetCacheSize)
2428 afs_int32 results[MAXGCSTATS];
2430 register struct dcache * tdc;
2433 AFS_STATCNT(PGetCacheSize);
2435 if (sizeof(afs_int32) == ainSize){
2436 memcpy((char *)&flags, ain, sizeof(afs_int32));
2437 } else if (0 == ainSize){
2443 memset(results, 0, sizeof(results));
2444 results[0] = afs_cacheBlocks;
2445 results[1] = afs_blocksUsed;
2446 results[2] = afs_cacheFiles;
2449 for (i = 0; i < afs_cacheFiles; i++) {
2450 if (afs_indexFlags[i] & IFFree) results[3]++;
2452 } else if (2 == flags){
2453 for (i = 0; i < afs_cacheFiles; i++) {
2454 if (afs_indexFlags[i] & IFFree) results[3]++;
2455 if (afs_indexFlags[i] & IFEverUsed) results[4]++;
2456 if (afs_indexFlags[i] & IFDataMod) results[5]++;
2457 if (afs_indexFlags[i] & IFDirtyPages) results[6]++;
2458 if (afs_indexFlags[i] & IFAnyPages) results[7]++;
2459 if (afs_indexFlags[i] & IFDiscarded) results[8]++;
2461 tdc = afs_indexTable[i];
2464 size = tdc->validPos;
2465 if ( 0 < size && size < (1<<12) ) results[10]++;
2466 else if (size < (1<<14) ) results[11]++;
2467 else if (size < (1<<16) ) results[12]++;
2468 else if (size < (1<<18) ) results[13]++;
2469 else if (size < (1<<20) ) results[14]++;
2470 else if (size >= (1<<20) ) results[15]++;
2474 memcpy(aout, (char *)results, sizeof(results));
2475 *aoutSize = sizeof(results);
2480 * VIOCFLUSHCB (25) - Flush callback only
2484 * \param[in] ain not in use
2485 * \param[out] aout not in use
2487 * \retval EINVAL Error if some of the standard args aren't set
2488 * \retval 0 0 returned if the volume is set to read-only
2490 * \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.
2492 DECL_PIOCTL(PRemoveCallBack)
2494 register struct afs_conn *tc;
2495 register afs_int32 code = 0;
2496 struct AFSCallBack CallBacks_Array[1];
2497 struct AFSCBFids theFids;
2498 struct AFSCBs theCBs;
2501 AFS_STATCNT(PRemoveCallBack);
2504 if (avc->f.states & CRO)
2505 return 0; /* read-only-ness can't change */
2506 ObtainWriteLock(&avc->lock, 229);
2507 theFids.AFSCBFids_len = 1;
2508 theCBs.AFSCBs_len = 1;
2509 theFids.AFSCBFids_val = (struct AFSFid *)&avc->f.fid.Fid;
2510 theCBs.AFSCBs_val = CallBacks_Array;
2511 CallBacks_Array[0].CallBackType = CB_DROPPED;
2512 if (avc->callback) {
2514 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
2516 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2518 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2522 /* don't set code on failure since we wouldn't use it */
2523 } while (afs_Analyze
2524 (tc, code, &avc->f.fid, areq,
2525 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK, NULL));
2527 ObtainWriteLock(&afs_xcbhash, 457);
2528 afs_DequeueCallback(avc);
2530 avc->f.states &= ~(CStatd | CUnique);
2531 ReleaseWriteLock(&afs_xcbhash);
2532 if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2533 osi_dnlc_purgedp(avc);
2535 ReleaseWriteLock(&avc->lock);
2540 * VIOCNEWCELL (26) - Configure new cell
2544 * \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
2545 * \param[out] aout not in use
2547 * \retval EIO Error if the afs daemon hasn't started yet
2548 * \retval EACCES Error if the user doesn't have super-user cedentials
2549 * \retval EINVAL Error if some 'magic' var doesn't have a certain bit set
2551 * \post creates a new cell
2553 DECL_PIOCTL(PNewCell)
2555 /* create a new cell */
2556 afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic = 0;
2557 char *newcell = 0, *linkedcell = 0, *tp = ain;
2558 register afs_int32 code, linkedstate = 0, ls;
2559 u_short fsport = 0, vlport = 0;
2562 AFS_STATCNT(PNewCell);
2563 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2564 return EIO; /* Inappropriate ioctl for device */
2566 if (!afs_osi_suser(*acred))
2569 memcpy((char *)&magic, tp, sizeof(afs_int32));
2570 tp += sizeof(afs_int32);
2571 if (magic != 0x12345678)
2574 /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2575 * server addresses while the 3.5 fs newcell command passes
2576 * MAXHOSTS. To figure out which is which, check if the cellname
2579 newcell = tp + (MAXCELLHOSTS + 3) * sizeof(afs_int32);
2580 scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2582 /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2583 memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
2584 tp += (scount * sizeof(afs_int32));
2586 lp = (afs_int32 *) tp;
2590 fsport = 0; /* Privileged ports not allowed */
2592 vlport = 0; /* Privileged ports not allowed */
2593 tp += (3 * sizeof(afs_int32));
2595 if ((ls = *lp) & 1) {
2596 linkedcell = tp + strlen(newcell) + 1;
2597 linkedstate |= CLinkedCell;
2600 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2602 afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport,
2607 DECL_PIOCTL(PNewAlias)
2609 /* create a new cell alias */
2611 register afs_int32 code;
2612 char *realName, *aliasName;
2614 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2615 return EIO; /* Inappropriate ioctl for device */
2617 if (!afs_osi_suser(*acred))
2621 tp += strlen(aliasName) + 1;
2624 code = afs_NewCellAlias(aliasName, realName);
2630 * VIOCGETCELL (27) - Get cell info
2634 * \param[in] ain The cell index of a specific cell
2635 * \param[out] aout list of servers in the cell
2637 * \retval EIO Error if the afs daemon hasn't started yet
2638 * \retval EDOM Error if there is no cell asked about
2640 * \post Lists the cell's server names and and addresses
2642 DECL_PIOCTL(PListCells)
2644 afs_int32 whichCell;
2645 register struct cell *tcell = 0;
2646 register afs_int32 i;
2647 register char *cp, *tp = ain;
2649 AFS_STATCNT(PListCells);
2650 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2651 return EIO; /* Inappropriate ioctl for device */
2653 memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2654 tp += sizeof(afs_int32);
2655 tcell = afs_GetCellByIndex(whichCell, READ_LOCK);
2658 memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
2659 for (i = 0; i < MAXCELLHOSTS; i++) {
2660 if (tcell->cellHosts[i] == 0)
2662 memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip,
2664 cp += sizeof(afs_int32);
2666 cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2667 strcpy(cp, tcell->cellName);
2668 cp += strlen(tcell->cellName) + 1;
2669 *aoutSize = cp - aout;
2670 afs_PutCell(tcell, READ_LOCK);
2678 DECL_PIOCTL(PListAliases)
2680 afs_int32 whichAlias;
2681 register struct cell_alias *tcalias = 0;
2682 register char *cp, *tp = ain;
2684 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2685 return EIO; /* Inappropriate ioctl for device */
2686 if (ainSize < sizeof(afs_int32))
2689 memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2690 tp += sizeof(afs_int32);
2692 tcalias = afs_GetCellAlias(whichAlias);
2695 strcpy(cp, tcalias->alias);
2696 cp += strlen(tcalias->alias) + 1;
2697 strcpy(cp, tcalias->cell);
2698 cp += strlen(tcalias->cell) + 1;
2699 *aoutSize = cp - aout;
2700 afs_PutCellAlias(tcalias);
2709 * VIOC_AFS_DELETE_MT_PT (28) - Delete mount point
2713 * \param[in] ain the name of the file in this dir to remove
2714 * \param[out] aout not in use
2716 * \retval EINVAL Error if some of the standard args aren't set
2717 * \retval ENOTDIR Error if the argument to remove is not a directory
2718 * \retval ENOENT Error if there is no cache to remove the mount point from or if a vcache doesn't exist
2720 * \post Ensure that everything is OK before deleting the mountpoint. If not, don't delete. Delete a mount point based on a file id.
2722 DECL_PIOCTL(PRemoveMount)
2724 register afs_int32 code;
2726 struct sysname_info sysState;
2727 afs_size_t offset, len;
2728 register struct afs_conn *tc;
2729 register struct dcache *tdc;
2730 register struct vcache *tvc;
2731 struct AFSFetchStatus OutDirStatus;
2732 struct VenusFid tfid;
2733 struct AFSVolSync tsync;
2737 /* "ain" is the name of the file in this dir to remove */
2739 AFS_STATCNT(PRemoveMount);
2742 code = afs_VerifyVCache(avc, areq);
2745 if (vType(avc) != VDIR)
2748 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1); /* test for error below */
2751 Check_AtSys(avc, ain, &sysState, areq);
2752 ObtainReadLock(&tdc->lock);
2754 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
2755 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2756 ReleaseReadLock(&tdc->lock);
2757 bufp = sysState.name;
2762 tfid.Cell = avc->f.fid.Cell;
2763 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
2764 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
2765 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
2767 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
2774 if (tvc->mvstat != 1) {
2780 ObtainWriteLock(&tvc->lock, 230);
2781 code = afs_HandleLink(tvc, areq);
2783 if (tvc->linkData) {
2784 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2789 ReleaseWriteLock(&tvc->lock);
2790 osi_dnlc_purgedp(tvc);
2796 ObtainWriteLock(&avc->lock, 231);
2797 osi_dnlc_remove(avc, bufp, tvc);
2799 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
2801 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2804 RXAFS_RemoveFile(tc->id, (struct AFSFid *)&avc->f.fid.Fid, bufp,
2805 &OutDirStatus, &tsync);
2810 } while (afs_Analyze
2811 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_REMOVEFILE,
2812 SHARED_LOCK, NULL));
2817 ReleaseWriteLock(&avc->lock);
2821 /* we have the thing in the cache */
2822 ObtainWriteLock(&tdc->lock, 661);
2823 if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2824 /* we can do it locally */
2825 code = afs_dir_Delete(tdc, bufp);
2827 ZapDCE(tdc); /* surprise error -- invalid value */
2831 ReleaseWriteLock(&tdc->lock);
2832 afs_PutDCache(tdc); /* drop ref count */
2834 avc->f.states &= ~CUnique; /* For the dfs xlator */
2835 ReleaseWriteLock(&avc->lock);
2838 if (sysState.allocked)
2839 osi_FreeLargeSpace(bufp);
2844 * VIOC_VENUSLOG (34) - Enable/Disable venus logging
2848 * \retval EINVAL Error if some of the standard args aren't set
2850 * \notes Obsoleted, perhaps should be PBogus
2852 DECL_PIOCTL(PVenusLogging)
2854 return EINVAL; /* OBSOLETE */
2858 * VIOC_GETCELLSTATUS (35) - Get cell status info
2862 * \param[in] ain The cell you want status information on
2863 * \param[out] aout cell state (as a struct)
2865 * \retval EIO Error if the afs daemon hasn't started yet
2866 * \retval ENOENT Error if the cell doesn't exist
2868 * \post Returns the state of the cell as defined in a struct cell
2870 DECL_PIOCTL(PGetCellStatus)
2872 register struct cell *tcell;
2875 AFS_STATCNT(PGetCellStatus);
2876 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2877 return EIO; /* Inappropriate ioctl for device */
2879 tcell = afs_GetCellByName(ain, READ_LOCK);
2882 temp = tcell->states;
2883 afs_PutCell(tcell, READ_LOCK);
2884 memcpy(aout, (char *)&temp, sizeof(afs_int32));
2885 *aoutSize = sizeof(afs_int32);
2890 * VIOC_SETCELLSTATUS (36) - Set corresponding info
2894 * \param[in] ain The cell you want to set information about, and the values you want to set
2895 * \param[out] aout not in use
2897 * \retval EIO Error if the afs daemon hasn't started yet
2898 * \retval EACCES Error if the user doesn't have super-user credentials
2900 * \post Set the state of the cell in a defined struct cell, based on whether or not SetUID is allowed
2902 DECL_PIOCTL(PSetCellStatus)
2904 register struct cell *tcell;
2907 if (!afs_osi_suser(*acred))
2909 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2910 return EIO; /* Inappropriate ioctl for device */
2912 tcell = afs_GetCellByName(ain + 2 * sizeof(afs_int32), WRITE_LOCK);
2915 memcpy((char *)&temp, ain, sizeof(afs_int32));
2917 tcell->states |= CNoSUID;
2919 tcell->states &= ~CNoSUID;
2920 afs_PutCell(tcell, WRITE_LOCK);
2925 * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
2929 * \param[in] ain not in use (args in avc)
2930 * \param[out] aout not in use
2932 * \retval EINVAL Error if some of the standard args aren't set
2933 * \retval EIO Error if the afs daemon hasn't started yet
2935 * \post Wipe everything on the volume. This is done dependent on which platform this is for.
2937 * \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.
2939 DECL_PIOCTL(PFlushVolumeData)
2941 register afs_int32 i;
2942 register struct dcache *tdc;
2943 register struct vcache *tvc;
2944 register struct volume *tv;
2945 afs_int32 cell, volume;
2946 struct afs_q *tq, *uq;
2947 #ifdef AFS_DARWIN80_ENV
2951 AFS_STATCNT(PFlushVolumeData);
2954 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2955 return EIO; /* Inappropriate ioctl for device */
2957 volume = avc->f.fid.Fid.Volume; /* who to zap */
2958 cell = avc->f.fid.Cell;
2961 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
2962 * the vcaches associated with the volume.
2965 ObtainReadLock(&afs_xvcache);
2966 i = VCHashV(&avc->f.fid);
2967 for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
2970 if (tvc->f.fid.Fid.Volume == volume && tvc->f.fid.Cell == cell) {
2971 if (tvc->f.states & CVInit) {
2972 ReleaseReadLock(&afs_xvcache);
2973 afs_osi_Sleep(&tvc->f.states);
2976 #ifdef AFS_DARWIN80_ENV
2977 if (tvc->f.states & CDeadVnode) {
2978 ReleaseReadLock(&afs_xvcache);
2979 afs_osi_Sleep(&tvc->f.states);
2983 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
2984 VN_HOLD(AFSTOV(tvc));
2985 #elif defined(AFS_DARWIN80_ENV)
2989 if (vnode_ref(vp)) {
2995 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
2998 VREFCOUNT_INC(tvc); /* AIX, apparently */
3000 ReleaseReadLock(&afs_xvcache);
3001 #ifdef AFS_BOZONLOCK_ENV
3002 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3004 ObtainWriteLock(&tvc->lock, 232);
3006 ObtainWriteLock(&afs_xcbhash, 458);
3007 afs_DequeueCallback(tvc);
3008 tvc->f.states &= ~(CStatd | CDirty);
3009 ReleaseWriteLock(&afs_xcbhash);
3010 if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
3011 osi_dnlc_purgedp(tvc);
3012 afs_TryToSmush(tvc, *acred, 1);
3013 ReleaseWriteLock(&tvc->lock);
3014 #ifdef AFS_BOZONLOCK_ENV
3015 afs_BozonUnlock(&tvc->pvnLock, tvc);
3017 #ifdef AFS_DARWIN80_ENV
3018 vnode_put(AFSTOV(tvc));
3020 ObtainReadLock(&afs_xvcache);
3022 /* our tvc ptr is still good until now */
3026 ReleaseReadLock(&afs_xvcache);
3029 ObtainWriteLock(&afs_xdcache, 328); /* needed if you're going to flush any stuff */
3030 for (i = 0; i < afs_cacheFiles; i++) {
3031 if (!(afs_indexFlags[i] & IFEverUsed))
3032 continue; /* never had any data */
3033 tdc = afs_GetDSlot(i, NULL);
3034 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
3035 ReleaseReadLock(&tdc->tlock);
3036 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
3037 if (!(afs_indexFlags[i] & IFDataMod)) {
3038 /* if the file is modified, but has a ref cnt of only 1, then
3039 * someone probably has the file open and is writing into it.
3040 * Better to skip flushing such a file, it will be brought back
3041 * immediately on the next write anyway.
3043 * If we *must* flush, then this code has to be rearranged to call
3044 * afs_storeAllSegments() first */
3045 afs_FlushDCache(tdc);
3049 ReleaseReadLock(&tdc->tlock);
3051 afs_PutDCache(tdc); /* bumped by getdslot */
3053 ReleaseWriteLock(&afs_xdcache);
3055 ObtainReadLock(&afs_xvolume);
3056 for (i = 0; i < NVOLS; i++) {
3057 for (tv = afs_volumes[i]; tv; tv = tv->next) {
3058 if (tv->volume == volume) {
3059 afs_ResetVolumeInfo(tv);
3064 ReleaseReadLock(&afs_xvolume);
3066 /* probably, a user is doing this, probably, because things are screwed up.
3067 * maybe it's the dnlc's fault? */
3074 * VIOCGETVCXSTATUS (41) - gets vnode x status
3078 * \param[in] ain not in use (avc used)
3079 * \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
3081 * \retval EINVAL Error if some of the initial default arguments aren't set
3082 * \retval EACCES Error if access to check the mode bits is denied
3084 * \post gets stats for the vnode, a struct listed in vcxstat
3086 DECL_PIOCTL(PGetVnodeXStatus)
3088 register afs_int32 code;
3089 struct vcxstat stat;
3092 /* AFS_STATCNT(PGetVnodeXStatus); */
3095 code = afs_VerifyVCache(avc, areq);
3098 if (vType(avc) == VDIR)
3099 mode = PRSFS_LOOKUP;
3102 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3105 memset(&stat, 0, sizeof(struct vcxstat));
3106 stat.fid = avc->f.fid;
3107 hset32(stat.DataVersion, hgetlo(avc->f.m.DataVersion));
3108 stat.lock = avc->lock;
3109 stat.parentVnode = avc->f.parent.vnode;
3110 stat.parentUnique = avc->f.parent.unique;
3111 hset(stat.flushDV, avc->flushDV);
3112 hset(stat.mapDV, avc->mapDV);
3113 stat.truncPos = avc->f.truncPos;
3114 { /* just grab the first two - won't break anything... */
3115 struct axscache *ac;
3117 for (i = 0, ac = avc->Access; ac && i < CPSIZE; i++, ac = ac->next) {
3118 stat.randomUid[i] = ac->uid;
3119 stat.randomAccess[i] = ac->axess;
3122 stat.callback = afs_data_pointer_to_int32(avc->callback);
3123 stat.cbExpires = avc->cbExpires;
3124 stat.anyAccess = avc->f.anyAccess;
3125 stat.opens = avc->opens;
3126 stat.execsOrWriters = avc->execsOrWriters;
3127 stat.flockCount = avc->flockCount;
3128 stat.mvstat = avc->mvstat;
3129 stat.states = avc->f.states;
3130 memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
3131 *aoutSize = sizeof(struct vcxstat);
3136 DECL_PIOCTL(PGetVnodeXStatus2)
3138 register afs_int32 code;
3139 struct vcxstat2 stat;
3144 code = afs_VerifyVCache(avc, areq);
3147 if (vType(avc) == VDIR)
3148 mode = PRSFS_LOOKUP;
3151 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3154 memset(&stat, 0, sizeof(struct vcxstat2));
3156 stat.cbExpires = avc->cbExpires;
3157 stat.anyAccess = avc->f.anyAccess;
3158 stat.mvstat = avc->mvstat;
3159 stat.callerAccess = afs_GetAccessBits(avc, ~0, areq);
3161 memcpy(aout, (char *)&stat, sizeof(struct vcxstat2));
3162 *aoutSize = sizeof(struct vcxstat2);
3168 * VIOC_AFS_SYSNAME (38) - Change @sys value
3172 * \param[in] ain new value for @sys
3173 * \param[out] aout count, entry, list (debug values?)
3175 * \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"
3176 * \retval ENODEV Error if there isn't already a system named that ("I THINK")
3177 * \retval EACCES Error if the user doesn't have super-user credentials
3179 * \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
3181 * \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.
3183 DECL_PIOCTL(PSetSysName)
3185 char *cp, *cp2 = NULL, inname[MAXSYSNAME], outname[MAXSYSNAME];
3186 afs_int32 setsysname;
3188 register struct afs_exporter *exporter;
3189 register struct unixuser *au;
3190 register afs_int32 pag, error;
3191 int t, count, num = 0, allpags = 0;
3194 AFS_STATCNT(PSetSysName);
3195 if (!afs_globalVFS) {
3196 /* Afsd is NOT running; disable it */
3197 #if defined(KERNEL_HAVE_UERROR)
3198 return (setuerror(EINVAL), EINVAL);
3203 memset(inname, 0, MAXSYSNAME);
3204 memcpy(&setsysname, ain, sizeof(afs_int32));
3205 ain += sizeof(afs_int32);
3206 if (setsysname & 0x8000) {
3208 setsysname &= ~0x8000;
3213 if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
3216 for (cp = ain, count = 0; count < setsysname; count++) {
3217 /* won't go past end of ain since maxsysname*num < ain length */
3219 if (t >= MAXSYSNAME || t <= 0)
3221 /* check for names that can shoot us in the foot */
3222 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
3228 /* inname gets first entry in case we're being a translator */
3230 memcpy(inname, ain, t + 1); /* include terminating null */
3234 if (afs_cr_gid(*acred) == RMTUSER_REQ ||
3235 afs_cr_gid(*acred) == RMTUSER_REQ_PRIV) { /* Handles all exporters */
3236 if (allpags && afs_cr_gid(*acred) != RMTUSER_REQ_PRIV) {
3239 pag = PagInCred(*acred);
3241 return EINVAL; /* Better than panicing */
3243 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
3244 return EINVAL; /* Better than panicing */
3246 if (!(exporter = au->exporter)) {
3247 afs_PutUser(au, READ_LOCK);
3248 return EINVAL; /* Better than panicing */
3250 error = EXP_SYSNAME(exporter, (setsysname ? cp2 : NULL), &sysnamelist,
3253 if (error == ENODEV)
3254 foundname = 0; /* sysname not set yet! */
3256 afs_PutUser(au, READ_LOCK);
3261 strcpy(outname, sysnamelist[0]);
3263 afs_PutUser(au, READ_LOCK);
3267 /* Not xlating, so local case */
3269 osi_Panic("PSetSysName: !afs_sysname\n");
3270 if (!setsysname) { /* user just wants the info */
3271 strcpy(outname, afs_sysname);
3272 foundname = afs_sysnamecount;
3273 sysnamelist = afs_sysnamelist;
3274 } else { /* Local guy; only root can change sysname */
3275 if (!afs_osi_suser(*acred))
3278 /* allpags makes no sense for local use */
3282 /* clear @sys entries from the dnlc, once afs_lookup can
3283 * do lookups of @sys entries and thinks it can trust them */
3284 /* privs ok, store the entry, ... */
3285 strcpy(afs_sysname, inname);
3286 if (setsysname > 1) { /* ... or list */
3288 for (count = 1; count < setsysname; ++count) {
3289 if (!afs_sysnamelist[count])
3291 ("PSetSysName: no afs_sysnamelist entry to write\n");
3293 memcpy(afs_sysnamelist[count], cp, t + 1); /* include null */
3297 afs_sysnamecount = setsysname;
3302 cp = aout; /* not changing so report back the count and ... */
3303 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
3304 cp += sizeof(afs_int32);
3306 strcpy(cp, outname); /* ... the entry, ... */
3307 cp += strlen(outname) + 1;
3308 for (count = 1; count < foundname; ++count) { /* ... or list. */
3309 if (!sysnamelist[count])
3311 ("PSetSysName: no afs_sysnamelist entry to read\n");
3312 t = strlen(sysnamelist[count]);
3313 if (t >= MAXSYSNAME)
3314 osi_Panic("PSetSysName: sysname entry garbled\n");
3315 strcpy(cp, sysnamelist[count]);
3319 *aoutSize = cp - aout;
3324 /* sequential search through the list of touched cells is not a good
3325 * long-term solution here. For small n, though, it should be just
3326 * fine. Should consider special-casing the local cell for large n.
3327 * Likewise for PSetSPrefs.
3329 * s - number of ids in array l[] -- NOT index of last id
3330 * l - array of cell ids which have volumes that need to be sorted
3331 * vlonly - sort vl servers or file servers?
3334 ReSortCells_cb(struct cell *cell, void *arg)
3336 afs_int32 *p = (afs_int32 *) arg;
3337 afs_int32 *l = p + 1;
3340 for (i = 0; i < s; i++) {
3341 if (l[i] == cell->cellNum) {
3342 ObtainWriteLock(&cell->lock, 690);
3343 afs_SortServers(cell->cellHosts, MAXCELLHOSTS);
3344 ReleaseWriteLock(&cell->lock);
3352 ReSortCells(int s, afs_int32 * l, int vlonly)
3360 p = (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * (s + 1));
3362 memcpy(p + 1, l, s * sizeof(afs_int32));
3363 afs_TraverseCells(&ReSortCells_cb, p);
3364 afs_osi_Free(p, sizeof(afs_int32) * (s + 1));
3368 ObtainReadLock(&afs_xvolume);
3369 for (i = 0; i < NVOLS; i++) {
3370 for (j = afs_volumes[i]; j; j = j->next) {
3371 for (k = 0; k < s; k++)
3372 if (j->cell == l[k]) {
3373 ObtainWriteLock(&j->lock, 233);
3374 afs_SortServers(j->serverHost, MAXHOSTS);
3375 ReleaseWriteLock(&j->lock);
3380 ReleaseReadLock(&afs_xvolume);
3384 static int debugsetsp = 0;
3386 afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
3389 int i, j, k, matches, touchedSize;
3390 struct server *srvr = NULL;
3391 afs_int32 touched[34];
3395 for (k = 0; k < num; sp++, k++) {
3397 printf("sp host=%x, rank=%d\n", sp->host.s_addr, sp->rank);
3400 ObtainReadLock(&afs_xserver);
3402 i = SHash(sp->host.s_addr);
3403 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
3404 if (sa->sa_ip == sp->host.s_addr) {
3406 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3407 || (sa->sa_portal == AFS_FSPORT);
3408 if ((!vlonly && isfs) || (vlonly && !isfs)) {
3415 if (sa && matches) { /* found one! */
3417 printf("sa ip=%x, ip_rank=%d\n", sa->sa_ip, sa->sa_iprank);
3419 sa->sa_iprank = sp->rank + afs_randomMod15();
3420 afs_SortOneServer(sa->server);
3423 /* if we don't know yet what cell it's in, this is moot */
3424 for (j = touchedSize - 1;
3425 j >= 0 && touched[j] != srvr->cell->cellNum; j--)
3426 /* is it in our list of touched cells ? */ ;
3427 if (j < 0) { /* no, it's not */
3428 touched[touchedSize++] = srvr->cell->cellNum;
3429 if (touchedSize >= 32) { /* watch for ovrflow */
3430 ReleaseReadLock(&afs_xserver);
3431 ReSortCells(touchedSize, touched, vlonly);
3433 ObtainReadLock(&afs_xserver);
3439 ReleaseReadLock(&afs_xserver);
3440 /* if we didn't find one, start to create one. */
3441 /* Note that it doesn't have a cell yet... */
3443 afs_uint32 temp = sp->host.s_addr;
3445 afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
3446 WRITE_LOCK, (afsUUID *) 0, 0);
3447 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3448 afs_PutServer(srvr, WRITE_LOCK);
3450 } /* for all cited preferences */
3452 ReSortCells(touchedSize, touched, vlonly);
3457 * VIOC_SETPREFS (46) - Set server ranks
3459 * \param[in] ain the sprefs value you want the sprefs to be set to
3460 * \param[out] aout not in use
3462 * \retval EIO Error if the afs daemon hasn't started yet
3463 * \retval EACCES Error if the user doesn't have super-user credentials
3464 * \retval EINVAL Error if the struct setsprefs is too large or if it multiplied by the number of servers is too large
3466 * \post set the sprefs using the afs_setsprefs() function
3468 DECL_PIOCTL(PSetSPrefs)
3470 struct setspref *ssp;
3471 AFS_STATCNT(PSetSPrefs);
3473 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3474 return EIO; /* Inappropriate ioctl for device */
3476 if (!afs_osi_suser(*acred))
3479 if (ainSize < sizeof(struct setspref))
3482 ssp = (struct setspref *)ain;
3483 if (ainSize < sizeof(struct spref) * ssp->num_servers)
3486 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
3487 (ssp->flags & DBservers));
3492 * VIOC_SETPREFS33 (42) - Set server ranks (deprecated)
3494 * \param[in] ain the server preferences to be set
3495 * \param[out] aout not in use
3497 * \retval EIO Error if the afs daemon hasn't started yet
3498 * \retval EACCES Error if the user doesn't have super-user credentials
3500 * \post set the server preferences, calling a function
3502 * \notes this may only be performed by the local root user.
3504 DECL_PIOCTL(PSetSPrefs33)
3507 AFS_STATCNT(PSetSPrefs);
3508 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3509 return EIO; /* Inappropriate ioctl for device */
3512 if (!afs_osi_suser(*acred))
3515 sp = (struct spref *)ain;
3516 afs_setsprefs(sp, ainSize / (sizeof(struct spref)), 0 /*!vlonly */ );
3521 * VIOC_GETSPREFS (43) - Get server ranks
3525 * \param[in] ain the server preferences to get
3526 * \param[out] aout the server preferences information
3528 * \retval EIO Error if the afs daemon hasn't started yet
3529 * \retval ENOENT Error if the sprefrequest is too large
3531 * \post Get the sprefs
3533 * \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.
3535 DECL_PIOCTL(PGetSPrefs)
3537 struct sprefrequest *spin; /* input */
3538 struct sprefinfo *spout; /* output */
3539 struct spref *srvout; /* one output component */
3540 int i, j; /* counters for hash table traversal */
3541 struct server *srvr; /* one of CM's server structs */
3543 int vlonly; /* just return vlservers ? */
3546 AFS_STATCNT(PGetSPrefs);
3547 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3548 return EIO; /* Inappropriate ioctl for device */
3551 if (ainSize < sizeof(struct sprefrequest_33)) {
3554 spin = ((struct sprefrequest *)ain);
3557 if (ainSize > sizeof(struct sprefrequest_33)) {
3558 vlonly = (spin->flags & DBservers);
3562 /* struct sprefinfo includes 1 server struct... that size gets added
3563 * in during the loop that follows.
3565 *aoutSize = sizeof(struct sprefinfo) - sizeof(struct spref);
3566 spout = (struct sprefinfo *)aout;
3567 spout->next_offset = spin->offset;
3568 spout->num_servers = 0;
3569 srvout = spout->servers;
3571 ObtainReadLock(&afs_xserver);
3572 for (i = 0, j = 0; j < NSERVERS; j++) { /* sift through hash table */
3573 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3574 if (spin->offset > (unsigned short)i) {
3575 continue; /* catch up to where we left off */
3577 spout->next_offset++;
3580 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3581 || (sa->sa_portal == AFS_FSPORT);
3583 if ((vlonly && isfs) || (!vlonly && !isfs)) {
3584 /* only report ranks for vl servers */
3588 srvout->host.s_addr = sa->sa_ip;
3589 srvout->rank = sa->sa_iprank;
3590 *aoutSize += sizeof(struct spref);
3591 spout->num_servers++;
3594 if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3595 ReleaseReadLock(&afs_xserver); /* no more room! */
3600 ReleaseReadLock(&afs_xserver);
3602 spout->next_offset = 0; /* start over from the beginning next time */
3606 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3607 int afs_NFSRootOnly = 1;
3609 * VIOC_EXPORTAFS (39) - Export afs to nfs clients
3613 * \param[in] ain a struct Vic * EIOctl containing export values needed to change between nfs and afs
3614 * \param[out] aout a struct of the exporter states (exporter->exp_states)
3616 * \retval ENODEV Error if the exporter doesn't exist
3617 * \retval EACCES Error if the user doesn't have super-user credentials
3619 * \post Changes the state of various values to reflect the change of the export values between nfs and afs.
3621 * \notes Legacy code obtained from IBM.
3623 DECL_PIOCTL(PExportAfs)
3625 afs_int32 export, newint =
3626 0, type, changestate, handleValue, convmode, pwsync, smounts;
3627 afs_int32 rempags = 0, pagcb = 0;
3628 register struct afs_exporter *exporter;
3630 AFS_STATCNT(PExportAfs);
3631 memcpy((char *)&handleValue, ain, sizeof(afs_int32));
3632 type = handleValue >> 24;
3637 exporter = exporter_find(type);
3639 export = handleValue & 3;
3640 changestate = handleValue & 0xfff;
3641 smounts = (handleValue >> 2) & 3;
3642 pwsync = (handleValue >> 4) & 3;
3643 convmode = (handleValue >> 6) & 3;
3644 rempags = (handleValue >> 8) & 3;
3645 pagcb = (handleValue >> 10) & 3;
3647 changestate = (handleValue >> 16) & 0x1;
3648 convmode = (handleValue >> 16) & 0x2;
3649 pwsync = (handleValue >> 16) & 0x4;
3650 smounts = (handleValue >> 16) & 0x8;
3651 export = handleValue & 0xff;
3654 /* Failed finding desired exporter; */
3658 handleValue = exporter->exp_states;
3659 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3660 *aoutSize = sizeof(afs_int32);
3662 if (!afs_osi_suser(*acred))
3663 return EACCES; /* Only superuser can do this */
3667 exporter->exp_states |= EXP_EXPORTED;
3669 exporter->exp_states &= ~EXP_EXPORTED;
3673 exporter->exp_states |= EXP_UNIXMODE;
3675 exporter->exp_states &= ~EXP_UNIXMODE;
3679 exporter->exp_states |= EXP_PWSYNC;
3681 exporter->exp_states &= ~EXP_PWSYNC;
3685 afs_NFSRootOnly = 0;
3686 exporter->exp_states |= EXP_SUBMOUNTS;
3688 afs_NFSRootOnly = 1;
3689 exporter->exp_states &= ~EXP_SUBMOUNTS;
3694 exporter->exp_states |= EXP_CLIPAGS;
3696 exporter->exp_states &= ~EXP_CLIPAGS;
3700 exporter->exp_states |= EXP_CALLBACK;
3702 exporter->exp_states &= ~EXP_CALLBACK;
3704 handleValue = exporter->exp_states;
3705 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3706 *aoutSize = sizeof(afs_int32);
3709 exporter->exp_states |= EXP_EXPORTED;
3711 exporter->exp_states &= ~EXP_EXPORTED;
3713 exporter->exp_states |= EXP_UNIXMODE;
3715 exporter->exp_states &= ~EXP_UNIXMODE;
3717 exporter->exp_states |= EXP_PWSYNC;
3719 exporter->exp_states &= ~EXP_PWSYNC;
3721 afs_NFSRootOnly = 0;
3722 exporter->exp_states |= EXP_SUBMOUNTS;
3724 afs_NFSRootOnly = 1;
3725 exporter->exp_states &= ~EXP_SUBMOUNTS;
3734 * VIOC_GAG (44) - Silence Cache Manager
3738 * \param[in] ain the flags to either gag or de-gag the cache manager
3739 * \param[out] aout not in use
3741 * \retval EACCES Error if the user doesn't have super-user credentials
3743 * \post set the gag flags, then show these flags
3747 struct gaginfo *gagflags;
3749 if (!afs_osi_suser(*acred))
3752 gagflags = (struct gaginfo *)ain;
3753 afs_showflags = gagflags->showflags;
3759 * VIOC_TWIDDLE (45) - Adjust RX knobs
3763 * \param[in] ain the previous settings of the 'knobs'
3764 * \param[out] aout not in use
3766 * \retval EACCES Error if the user doesn't have super-user credentials
3768 * \post build out the struct rxp, from a struct rx
3770 DECL_PIOCTL(PTwiddleRx)
3772 struct rxparams *rxp;
3774 if (!afs_osi_suser(*acred))
3777 rxp = (struct rxparams *)ain;
3779 if (rxp->rx_initReceiveWindow)
3780 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3781 if (rxp->rx_maxReceiveWindow)
3782 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3783 if (rxp->rx_initSendWindow)
3784 rx_initSendWindow = rxp->rx_initSendWindow;
3785 if (rxp->rx_maxSendWindow)
3786 rx_maxSendWindow = rxp->rx_maxSendWindow;
3787 if (rxp->rxi_nSendFrags)
3788 rxi_nSendFrags = rxp->rxi_nSendFrags;
3789 if (rxp->rxi_nRecvFrags)
3790 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3791 if (rxp->rxi_OrphanFragSize)
3792 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3793 if (rxp->rx_maxReceiveSize) {
3794 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3795 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3797 if (rxp->rx_MyMaxSendSize)
3798 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3804 * VIOC_GETINITPARAMS (49) - Get initial cache manager parameters
3808 * \param[in] ain not in use
3809 * \param[out] aout initial cache manager params
3811 * \retval E2BIG Error if the initial parameters are bigger than some PIGGYSIZE
3813 * \post return the initial cache manager parameters
3815 DECL_PIOCTL(PGetInitParams)
3817 if (sizeof(struct cm_initparams) > PIGGYSIZE)
3820 memcpy(aout, (char *)&cm_initParams, sizeof(struct cm_initparams));
3821 *aoutSize = sizeof(struct cm_initparams);
3825 #ifdef AFS_SGI65_ENV
3826 /* They took crget() from us, so fake it. */
3831 cr = crdup(get_current_cred());
3832 memset(cr, 0, sizeof(cred_t));
3833 #if CELL || CELL_PREPARE
3841 * VIOC_GETRXKCRYPT (55) - Get rxkad encryption flag
3845 * \param[in] ain not in use
3846 * \param[out] aout value of cryptall
3848 * \post get the value of cryptall (presumably whether or not things should be encrypted)
3850 DECL_PIOCTL(PGetRxkcrypt)
3852 memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3853 *aoutSize = sizeof(afs_int32);
3858 * VIOC_SETRXKCRYPT (56) - Set rxkad encryption flag
3862 * \param[in] ain the argument whether or not things should be encrypted
3863 * \param[out] aout not in use
3865 * \retval EPERM Error if the user doesn't have super-user credentials
3866 * \retval EINVAL Error if the input is too big, or if the input is outside the bounds of what it can be set to
3868 * \post set whether or not things should be encrypted
3870 * \notes may need to be modified at a later date to take into account other values for cryptall (beyond true or false)
3872 DECL_PIOCTL(PSetRxkcrypt)
3876 if (!afs_osi_suser(*acred))
3878 if (ainSize != sizeof(afs_int32) || ain == NULL)
3880 memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3881 /* if new mappings added later this will need to be changed */
3882 if (tmpval != 0 && tmpval != 1)
3888 #ifdef AFS_NEED_CLIENTCONTEXT
3890 * Create new credentials to correspond to a remote user with given
3891 * <hostaddr, uid, g0, g1>. This allows a server running as root to
3892 * provide pioctl (and other) services to foreign clients (i.e. nfs
3893 * clients) by using this call to `become' the client.
3896 #define PIOCTL_HEADER 6
3898 HandleClientContext(struct afs_ioctl *ablob, int *com,
3899 afs_ucred_t **acred, AFS_UCRED *credp)
3902 afs_uint32 hostaddr;
3903 afs_int32 uid, g0, g1, i, code, pag, exporter_type, isroot = 0;
3904 struct afs_exporter *exporter, *outexporter;
3905 afs_ucred_t *newcred;
3906 struct unixuser *au;
3907 afs_uint32 comp = *com & 0xff00;
3910 #if defined(AFS_SGIMP_ENV)
3911 osi_Assert(ISAFS_GLOCK());
3913 AFS_STATCNT(HandleClientContext);
3914 if (ablob->in_size < PIOCTL_HEADER * sizeof(afs_int32)) {
3915 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3916 return EINVAL; /* Too small to be good */
3918 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3919 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER * sizeof(afs_int32), code);
3921 osi_FreeLargeSpace(inData);
3925 /* Extract information for remote user */
3926 hostaddr = *((afs_uint32 *) ain);
3927 ain += sizeof(hostaddr);
3928 uid = *((afs_uint32 *) ain);
3930 g0 = *((afs_uint32 *) ain);
3932 g1 = *((afs_uint32 *) ain);
3934 *com = *((afs_uint32 *) ain);
3935 ain += sizeof(afs_int32);
3936 exporter_type = *((afs_uint32 *) ain); /* In case we support more than NFS */
3939 * Of course, one must be root for most of these functions, but
3940 * we'll allow (for knfs) you to set things if the pag is 0 and
3941 * you're setting tokens or unlogging.
3944 if (!afs_osi_suser(credp)) {
3945 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI64_ENV)
3946 /* Since SGI's suser() returns explicit failure after the call.. */
3949 /* check for acceptable opcodes for normal folks, which are, so far,
3950 * get/set tokens, sysname, and unlog.
3952 if (i != 9 && i != 3 && i != 38 && i != 8) {
3953 osi_FreeLargeSpace(inData);
3958 ablob->in_size -= PIOCTL_HEADER * sizeof(afs_int32);
3959 ablob->in += PIOCTL_HEADER * sizeof(afs_int32);
3960 osi_FreeLargeSpace(inData);
3963 * We map uid 0 to nobody to match the mapping that the nfs
3964 * server does and to ensure that the suser() calls in the afs
3965 * code fails for remote client roots.
3967 uid = afs_nobody; /* NFS_NOBODY == -2 */
3971 #ifdef AFS_AIX41_ENV
3974 afs_set_cr_gid(newcred, isroot ? RMTUSER_REQ_PRIV : RMTUSER_REQ);
3975 #ifdef AFS_AIX51_ENV
3976 newcred->cr_groupset.gs_union.un_groups[0] = g0;
3977 newcred->cr_groupset.gs_union.un_groups[1] = g1;
3978 #elif defined(AFS_LINUX26_ENV)
3979 #ifdef AFS_LINUX26_ONEGROUP_ENV
3980 set_cr_group_info(newcred, groups_alloc(1)); /* not that anything sets this */
3981 l = (((g0-0x3f00) & 0x3fff) << 14) | ((g1-0x3f00) & 0x3fff);
3982 h = ((g0-0x3f00) >> 14);
3983 h = ((g1-0x3f00) >> 14) + h + h + h;
3984 GROUP_AT(cr_group_info(newcred), 0) = ((h << 28) | l);
3986 set_cr_group_info(newcred, groups_alloc(2));
3987 GROUP_AT(cr_group_info(newcred), 0) = g0;
3988 GROUP_AT(cr_group_info(newcred), 1) = g1;
3991 newcred->cr_groups[0] = g0;
3992 newcred->cr_groups[1] = g1;
3995 newcred->cr_ngrps = 2;
3996 #elif !defined(AFS_LINUX26_ENV)
3997 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
3998 newcred->cr_ngroups = 2;
4000 for (i = 2; i < NGROUPS; i++)
4001 newcred->cr_groups[i] = NOGROUP;
4004 if (!(exporter = exporter_find(exporter_type))) {
4005 /* Exporter wasn't initialized or an invalid exporter type */
4009 if (exporter->exp_states & EXP_PWSYNC) {
4010 if (uid != afs_cr_uid(credp)) {
4012 return ENOEXEC; /* XXX Find a better errno XXX */
4015 afs_set_cr_uid(newcred, uid); /* Only temporary */
4016 code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
4017 /* The client's pag is the only unique identifier for it */
4018 afs_set_cr_uid(newcred, pag);
4020 if (!code && *com == PSETPAG) {
4021 /* Special case for 'setpag' */
4022 afs_uint32 pagvalue = genpag();
4024 au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
4026 * Note that we leave the 'outexporter' struct held so it won't
4029 au->exporter = outexporter;
4030 if (ablob->out_size >= 4) {
4031 AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32),
4034 afs_PutUser(au, WRITE_LOCK);
4037 return PSETPAG; /* Special return for setpag */
4039 EXP_RELE(outexporter);
4042 *com = (*com) | comp;
4045 #endif /* AFS_NEED_CLIENTCONTEXT */
4049 * VIOC_GETCPREFS (50) - Get client interface
4053 * \param[in] ain sprefrequest input
4054 * \param[out] aout spref information
4056 * \retval EIO Error if the afs daemon hasn't started yet
4057 * \retval EINVAL Error if some of the standard args aren't set
4059 * \post get all interface addresses and other information of the client interface
4061 DECL_PIOCTL(PGetCPrefs)
4063 struct sprefrequest *spin; /* input */
4064 struct sprefinfo *spout; /* output */
4065 struct spref *srvout; /* one output component */
4069 AFS_STATCNT(PGetCPrefs);
4070 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4071 return EIO; /* Inappropriate ioctl for device */
4073 if (ainSize < sizeof(struct sprefrequest))
4076 spin = (struct sprefrequest *)ain;
4077 spout = (struct sprefinfo *)aout;
4079 maxNumber = spin->num_servers; /* max addrs this time */
4080 srvout = spout->servers;
4082 ObtainReadLock(&afs_xinterface);
4084 /* copy out the client interface information from the
4085 ** kernel data structure "interface" to the output buffer
4087 for (i = spin->offset, j = 0; (i < afs_cb_interface.numberOfInterfaces)
4088 && (j < maxNumber); i++, j++, srvout++)
4089 srvout->host.s_addr = afs_cb_interface.addr_in[i];
4091 spout->num_servers = j;
4092 *aoutSize = sizeof(struct sprefinfo) + (j - 1) * sizeof(struct spref);
4094 if (i >= afs_cb_interface.numberOfInterfaces)
4095 spout->next_offset = 0; /* start from beginning again */
4097 spout->next_offset = spin->offset + j;
4099 ReleaseReadLock(&afs_xinterface);
4104 * VIOC_SETCPREFS (51) - Set client interface
4108 * \param[in] ain the interfaces you want set
4109 * \param[out] aout not in use
4111 * \retval EIO Error if the afs daemon hasn't started yet
4112 * \retval EINVAL Error if the input is too large for the struct
4113 * \retval ENOMEM Error if there are too many servers
4115 * \post set the callbak interfaces addresses to those of the hosts
4117 DECL_PIOCTL(PSetCPrefs)
4119 struct setspref *sin;
4122 AFS_STATCNT(PSetCPrefs);
4123 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4124 return EIO; /* Inappropriate ioctl for device */
4126 sin = (struct setspref *)ain;
4128 if (ainSize < sizeof(struct setspref))
4130 #if 0 /* num_servers is unsigned */
4131 if (sin->num_servers < 0)
4134 if (sin->num_servers > AFS_MAX_INTERFACE_ADDR)
4137 ObtainWriteLock(&afs_xinterface, 412);
4138 afs_cb_interface.numberOfInterfaces = sin->num_servers;
4139 for (i = 0; (unsigned short)i < sin->num_servers; i++)
4140 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
4142 ReleaseWriteLock(&afs_xinterface);
4147 * VIOC_AFS_FLUSHMOUNT (52) - Flush mount symlink data
4151 * \param[in] ain the last part of a path to a mount point, which tells us what to flush
4152 * \param[out] aout not in use
4154 * \retval EINVAL Error if some of the initial arguments aren't set
4155 * \retval ENOTDIR Error if the initial argument for the mount point isn't a directory
4156 * \retval ENOENT Error if the dcache entry isn't set
4158 * \post remove all of the mount data from the dcache regarding a certain mount point
4160 DECL_PIOCTL(PFlushMount)
4162 register afs_int32 code;
4163 register struct vcache *tvc;
4164 register struct dcache *tdc;
4165 struct VenusFid tfid;
4167 struct sysname_info sysState;
4168 afs_size_t offset, len;
4170 AFS_STATCNT(PFlushMount);
4173 code = afs_VerifyVCache(avc, areq);
4176 if (vType(avc) != VDIR) {
4179 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
4182 Check_AtSys(avc, ain, &sysState, areq);
4183 ObtainReadLock(&tdc->lock);
4185 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
4186 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
4187 ReleaseReadLock(&tdc->lock);
4188 afs_PutDCache(tdc); /* we're done with the data */
4189 bufp = sysState.name;
4193 tfid.Cell = avc->f.fid.Cell;
4194 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
4195 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
4196 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
4198 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4204 if (tvc->mvstat != 1) {
4209 #ifdef AFS_BOZONLOCK_ENV
4210 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
4212 ObtainWriteLock(&tvc->lock, 649);
4213 ObtainWriteLock(&afs_xcbhash, 650);
4214 afs_DequeueCallback(tvc);
4215 tvc->f.states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
4216 ReleaseWriteLock(&afs_xcbhash);
4217 /* now find the disk cache entries */
4218 afs_TryToSmush(tvc, *acred, 1);
4219 osi_dnlc_purgedp(tvc);
4220 if (tvc->linkData && !(tvc->f.states & CCore)) {
4221 afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
4222 tvc->linkData = NULL;
4224 ReleaseWriteLock(&tvc->lock);
4225 #ifdef AFS_BOZONLOCK_ENV
4226 afs_BozonUnlock(&tvc->pvnLock, tvc);
4230 if (sysState.allocked)
4231 osi_FreeLargeSpace(bufp);
4236 * VIOC_RXSTAT_PROC (53) - Control process RX statistics
4240 * \param[in] ain the flags that control which stats to use
4241 * \param[out] aout not in use
4243 * \retval EACCES Error if the user doesn't have super-user credentials
4244 * \retval EINVAL Error if the flag input is too long
4246 * \post either enable process RPCStats, disable process RPCStats, or clear the process RPCStats
4248 DECL_PIOCTL(PRxStatProc)
4253 if (!afs_osi_suser(*acred)) {
4257 if (ainSize != sizeof(afs_int32)) {
4261 memcpy((char *)&flags, ain, sizeof(afs_int32));
4262 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4266 if (flags & AFSCALL_RXSTATS_ENABLE) {
4267 rx_enableProcessRPCStats();
4269 if (flags & AFSCALL_RXSTATS_DISABLE) {
4270 rx_disableProcessRPCStats();
4272 if (flags & AFSCALL_RXSTATS_CLEAR) {
4273 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
4282 * VIOC_RXSTAT_PEER (54) - Control peer RX statistics
4286 * \param[in] ain the flags that control which statistics to use
4287 * \param[out] aout not in use
4289 * \retval EACCES Error if the user doesn't have super-user credentials
4290 * \retval EINVAL Error if the flag input is too long
4292 * \post either enable peer RPCStatws, disable peer RPCStats, or clear the peer RPCStats
4294 DECL_PIOCTL(PRxStatPeer)
4299 if (!afs_osi_suser(*acred)) {
4303 if (ainSize != sizeof(afs_int32)) {
4307 memcpy((char *)&flags, ain, sizeof(afs_int32));
4308 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4312 if (flags & AFSCALL_RXSTATS_ENABLE) {
4313 rx_enablePeerRPCStats();
4315 if (flags & AFSCALL_RXSTATS_DISABLE) {
4316 rx_disablePeerRPCStats();
4318 if (flags & AFSCALL_RXSTATS_CLEAR) {
4319 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
4326 DECL_PIOCTL(PPrefetchFromTape)
4328 register afs_int32 code, code1;
4330 struct afs_conn *tc;
4331 struct rx_call *tcall;
4332 struct AFSVolSync tsync;
4333 struct AFSFetchStatus OutStatus;
4334 struct AFSCallBack CallBack;
4335 struct VenusFid tfid;
4339 AFS_STATCNT(PSetAcl);
4343 if (ain && (ainSize == 3 * sizeof(afs_int32)))
4344 Fid = (struct AFSFid *)ain;
4346 Fid = &avc->f.fid.Fid;
4347 tfid.Cell = avc->f.fid.Cell;
4348 tfid.Fid.Volume = Fid->Volume;
4349 tfid.Fid.Vnode = Fid->Vnode;
4350 tfid.Fid.Unique = Fid->Unique;
4352 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4354 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4355 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &avc->f.fid);
4358 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4359 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &tvc->f.fid);
4362 tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
4366 tcall = rx_NewCall(tc->id);
4368 StartRXAFS_FetchData(tcall, (struct AFSFid *)&tvc->f.fid.Fid, 0,
4371 bytes = rx_Read(tcall, (char *)aout, sizeof(afs_int32));
4373 EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
4375 code1 = rx_EndCall(tcall, code);
4379 } while (afs_Analyze
4380 (tc, code, &tvc->f.fid, areq, AFS_STATS_FS_RPCIDX_RESIDENCYRPCS,
4381 SHARED_LOCK, NULL));
4382 /* This call is done only to have the callback things handled correctly */
4383 afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
4387 *aoutSize = sizeof(afs_int32);
4394 register afs_int32 code;
4395 struct afs_conn *tc;
4397 struct FsCmdInputs *Inputs;
4398 struct FsCmdOutputs *Outputs;
4399 struct VenusFid tfid;
4402 Inputs = (struct FsCmdInputs *)ain;
4403 Outputs = (struct FsCmdOutputs *)aout;
4406 if (!ain || ainSize != sizeof(struct FsCmdInputs))
4411 Fid = &avc->f.fid.Fid;
4413 tfid.Cell = avc->f.fid.Cell;
4414 tfid.Fid.Volume = Fid->Volume;
4415 tfid.Fid.Vnode = Fid->Vnode;
4416 tfid.Fid.Unique = Fid->Unique;
4418 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4419 afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD, ICL_TYPE_POINTER, tvc,
4420 ICL_TYPE_INT32, Inputs->command, ICL_TYPE_FID, &tfid);