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 #if defined(AFS_FBSD80_ENV) /* XXX check on 7x */
841 #endif /* AFS_FBSD80_ENV */
842 #endif /* AFS_LINUX22_ENV */
843 #endif /* AFS_AIX41_ENV */
847 #if defined(KERNEL_HAVE_UERROR)
855 #if defined(AFS_SUN510_ENV)
856 if (vp && !IsAfsVnode(vp)) {
857 struct vnode *realvp;
859 #ifdef AFS_SUN511_ENV
860 (VOP_REALVP(vp, &realvp, NULL) == 0)
862 (VOP_REALVP(vp, &realvp) == 0)
865 struct vnode *oldvp = vp;
873 /* now make the call if we were passed no file, or were passed an AFS file */
874 if (!vp || IsAfsVnode(vp)) {
875 #if defined(AFS_SUN5_ENV)
876 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
877 #elif defined(AFS_AIX41_ENV)
879 struct ucred *cred1, *cred2;
882 cred1 = cred2 = foreigncreds;
884 cred1 = cred2 = credp;
886 code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
887 if (cred1 != cred2) {
888 /* something changed the creds */
892 #elif defined(AFS_HPUX101_ENV)
894 struct ucred *cred = p_cred(u.u_procp);
895 code = afs_HandlePioctl(vp, com, &data, follow, &cred);
897 #elif defined(AFS_SGI_ENV)
900 credp = OSI_GET_CURRENT_CRED();
901 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
903 #elif defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
904 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
906 code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
909 #if defined(KERNEL_HAVE_UERROR)
912 code = EINVAL; /* not in /afs */
917 #if defined(AFS_NEED_CLIENTCONTEXT)
920 crset(tmpcred); /* restore original credentials */
922 #if defined(AFS_HPUX101_ENV)
923 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
924 #elif defined(AFS_SGI_ENV)
925 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
926 #elif defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
927 credp = tmpcred; /* restore original credentials */
929 osi_curcred() = tmpcred; /* restore original credentials */
930 #endif /* AFS_HPUX101_ENV */
931 crfree(foreigncreds);
934 #endif /* AFS_NEED_CLIENTCONTEXT */
936 #ifdef AFS_LINUX22_ENV
939 #if defined(AFS_FBSD80_ENV)
940 if (VOP_ISLOCKED(vp))
942 #endif /* AFS_FBSD80_ENV */
943 AFS_RELE(vp); /* put vnode back */
947 #if defined(KERNEL_HAVE_UERROR)
950 return (getuerror());
956 #ifdef AFS_DARWIN100_ENV
958 afs_syscall_pioctl(char * path, unsigned int com, caddr_t cmarg,
959 int follow, afs_ucred_t *credp)
961 return afs_syscall64_pioctl(CAST_USER_ADDR_T(path), com,
962 CAST_USER_ADDR_T((unsigned int)cmarg), follow,
967 #define MAXPIOCTLTOKENLEN \
968 (3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
971 afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
972 register struct afs_ioctl *ablob, int afollow,
976 struct vrequest treq;
977 register afs_int32 code;
978 register afs_int32 function, device;
979 afs_int32 inSize, outSize, outSizeMax;
980 char *inData, *outData;
981 pioctlFunction *pioctlSw;
983 struct afs_fakestat_state fakestate;
985 avc = avp ? VTOAFS(avp) : NULL;
986 afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
987 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
988 AFS_STATCNT(HandlePioctl);
989 if ((code = afs_InitReq(&treq, *acred)))
991 afs_InitFakeStat(&fakestate);
993 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
995 afs_PutFakeStat(&fakestate);
999 device = (acom & 0xff00) >> 8;
1001 case 'V': /* Original pioctls */
1002 pioctlSw = VpioctlSw;
1003 pioctlSwSize = sizeof(VpioctlSw);
1005 case 'C': /* Coordinated/common pioctls */
1006 pioctlSw = CpioctlSw;
1007 pioctlSwSize = sizeof(CpioctlSw);
1009 case 'O': /* Coordinated/common pioctls */
1010 pioctlSw = OpioctlSw;
1011 pioctlSwSize = sizeof(OpioctlSw);
1014 afs_PutFakeStat(&fakestate);
1017 function = acom & 0xff;
1018 if (function >= (pioctlSwSize / sizeof(char *))) {
1019 afs_PutFakeStat(&fakestate);
1020 return EINVAL; /* out of range */
1022 inSize = ablob->in_size;
1024 /* Do all range checking before continuing */
1025 if (inSize > MAXPIOCTLTOKENLEN || inSize < 0 || ablob->out_size < 0)
1028 /* Note that we use osi_Alloc for large allocs and osi_AllocLargeSpace for small ones */
1029 if (inSize > AFS_LRALLOCSIZ) {
1030 inData = osi_Alloc(inSize + 1);
1032 inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1037 AFS_COPYIN(ablob->in, inData, inSize, code);
1038 inData[inSize] = '\0';
1042 if (inSize > AFS_LRALLOCSIZ) {
1043 osi_Free(inData, inSize + 1);
1045 osi_FreeLargeSpace(inData);
1047 afs_PutFakeStat(&fakestate);
1050 if (function == 8 && device == 'V') { /* PGetTokens */
1051 outSizeMax = MAXPIOCTLTOKENLEN;
1052 outData = osi_Alloc(outSizeMax);
1054 outSizeMax = AFS_LRALLOCSIZ;
1055 outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1058 if (inSize > AFS_LRALLOCSIZ) {
1059 osi_Free(inData, inSize + 1);
1061 osi_FreeLargeSpace(inData);
1063 afs_PutFakeStat(&fakestate);
1068 (*pioctlSw[function]) (avc, function, &treq, inData, outData, inSize,
1070 if (inSize > AFS_LRALLOCSIZ) {
1071 osi_Free(inData, inSize + 1);
1073 osi_FreeLargeSpace(inData);
1075 if (code == 0 && ablob->out_size > 0) {
1076 if (outSize > ablob->out_size) {
1077 code = E2BIG; /* data wont fit in user buffer */
1078 } else if (outSize) {
1079 AFS_COPYOUT(outData, ablob->out, outSize, code);
1082 if (outSizeMax > AFS_LRALLOCSIZ) {
1083 osi_Free(outData, outSizeMax);
1085 osi_FreeLargeSpace(outData);
1087 afs_PutFakeStat(&fakestate);
1088 return afs_CheckCode(code, &treq, 41);
1092 * VIOCGETFID (22) - Get file ID quickly
1096 * \param[in] ain not in use
1097 * \param[out] aout fid of requested file
1099 * \retval EINVAL Error if some of the initial arguments aren't set
1101 * \post get the file id of some file
1103 DECL_PIOCTL(PGetFID)
1105 AFS_STATCNT(PGetFID);
1108 memcpy(aout, (char *)&avc->f.fid, sizeof(struct VenusFid));
1109 *aoutSize = sizeof(struct VenusFid);
1114 * VIOCSETAL (1) - Set access control list
1118 * \param[in] ain the ACL being set
1119 * \param[out] aout the ACL being set returned
1121 * \retval EINVAL Error if some of the standard args aren't set
1123 * \post Changed ACL, via direct writing to the wire
1125 int dummy_PSetAcl(char *ain, char *aout)
1130 DECL_PIOCTL(PSetAcl)
1132 register afs_int32 code;
1133 struct afs_conn *tconn;
1134 struct AFSOpaque acl;
1135 struct AFSVolSync tsync;
1136 struct AFSFetchStatus OutStatus;
1139 AFS_STATCNT(PSetAcl);
1142 if ((acl.AFSOpaque_len = strlen(ain) + 1) > 1024 /* AFSOPAQUEMAX */)
1145 acl.AFSOpaque_val = ain;
1147 tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1149 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1152 RXAFS_StoreACL(tconn->id, (struct AFSFid *)&avc->f.fid.Fid,
1153 &acl, &OutStatus, &tsync);
1158 } while (afs_Analyze
1159 (tconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_STOREACL,
1160 SHARED_LOCK, NULL));
1162 /* now we've forgotten all of the access info */
1163 ObtainWriteLock(&afs_xcbhash, 455);
1165 afs_DequeueCallback(avc);
1166 avc->f.states &= ~(CStatd | CUnique);
1167 ReleaseWriteLock(&afs_xcbhash);
1168 if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1169 osi_dnlc_purgedp(avc);
1171 /* SXW - Should we flush metadata here? */
1175 int afs_defaultAsynchrony = 0;
1178 * VIOC_STOREBEHIND (47) Adjust store asynchrony
1182 * \param[in] ain sbstruct (store behind structure) input
1183 * \param[out] aout resulting sbstruct
1185 * \retval EPERM Error if the user doesn't have super-user credentials
1186 * \retval EACCES Error if there isn't enough access to not check the mode bits
1188 * \post sets asynchrony based on a file, from a struct sbstruct "I THINK"
1190 DECL_PIOCTL(PStoreBehind)
1193 struct sbstruct *sbr;
1195 sbr = (struct sbstruct *)ain;
1196 if (sbr->sb_default != -1) {
1197 if (afs_osi_suser(*acred))
1198 afs_defaultAsynchrony = sbr->sb_default;
1203 if (avc && (sbr->sb_thisfile != -1)) {
1205 (avc, PRSFS_WRITE | PRSFS_ADMINISTER, areq, DONT_CHECK_MODE_BITS))
1206 avc->asynchrony = sbr->sb_thisfile;
1211 *aoutSize = sizeof(struct sbstruct);
1212 sbr = (struct sbstruct *)aout;
1213 sbr->sb_default = afs_defaultAsynchrony;
1215 sbr->sb_thisfile = avc->asynchrony;
1222 * VIOC_GCPAGS (48) - Disable automatic PAG gc'ing
1226 * \param[in] ain not in use
1227 * \param[out] aout not in use
1229 * \retval EACCES Error if the user doesn't have super-user credentials
1231 * \post set the gcpags to GCPAGS_USERDISABLED
1233 DECL_PIOCTL(PGCPAGs)
1235 if (!afs_osi_suser(*acred)) {
1238 afs_gcpags = AFS_GCPAGS_USERDISABLED;
1243 * VIOCGETAL (2) - Get access control list
1247 * \param[in] ain not in use
1248 * \param[out] aout the ACL
1250 * \retval EINVAL Error if some of the standard args aren't set
1251 * \retval ERANGE Error if the vnode of the file id is too large
1252 * \retval -1 Error if getting the ACL failed
1254 * \post Obtain the ACL, based on file ID
1256 * \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
1258 DECL_PIOCTL(PGetAcl)
1260 struct AFSOpaque acl;
1261 struct AFSVolSync tsync;
1262 struct AFSFetchStatus OutStatus;
1264 struct afs_conn *tconn;
1268 AFS_STATCNT(PGetAcl);
1271 Fid.Volume = avc->f.fid.Fid.Volume;
1272 Fid.Vnode = avc->f.fid.Fid.Vnode;
1273 Fid.Unique = avc->f.fid.Fid.Unique;
1274 if (avc->f.states & CForeign) {
1276 * For a dfs xlator acl we have a special hack so that the
1277 * xlator will distinguish which type of acl will return. So
1278 * we currently use the top 2-bytes (vals 0-4) to tell which
1279 * type of acl to bring back. Horrible hack but this will
1280 * cause the least number of changes to code size and interfaces.
1282 if (Fid.Vnode & 0xc0000000)
1284 Fid.Vnode |= (ainSize << 30);
1286 acl.AFSOpaque_val = aout;
1288 tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1291 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1293 code = RXAFS_FetchACL(tconn->id, &Fid, &acl, &OutStatus, &tsync);
1298 } while (afs_Analyze
1299 (tconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_FETCHACL,
1300 SHARED_LOCK, NULL));
1303 *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1309 * PNoop returns success. Used for functions which are not implemented or are no longer in use.
1313 * \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
1322 * PBogus returns fail. Used for functions which are not implemented or are no longer in use.
1326 * \retval EINVAL Error if some of the standard args aren't set
1328 * \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;
1332 AFS_STATCNT(PBogus);
1337 * VIOC_FILE_CELL_NAME (30) - Get cell in which file lives
1341 * \param[in] ain not in use (avc used to pass in file id)
1342 * \param[out] aout cell name
1344 * \retval EINVAL Error if some of the standard args aren't set
1345 * \retval ESRCH Error if the file isn't part of a cell
1347 * \post Get a cell based on a passed in file id
1349 DECL_PIOCTL(PGetFileCell)
1351 register struct cell *tcell;
1353 AFS_STATCNT(PGetFileCell);
1356 tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
1359 strcpy(aout, tcell->cellName);
1360 afs_PutCell(tcell, READ_LOCK);
1361 *aoutSize = strlen(aout) + 1;
1366 * VIOC_GET_WS_CELL (31) - Get cell in which workstation lives
1370 * \param[in] ain not in use
1371 * \param[out] aout cell name
1373 * \retval EIO Error if the afs daemon hasn't started yet
1374 * \retval ESRCH Error if the machine isn't part of a cell, for whatever reason
1376 * \post Get the primary cell that the machine is a part of.
1378 DECL_PIOCTL(PGetWSCell)
1380 struct cell *tcell = NULL;
1382 AFS_STATCNT(PGetWSCell);
1383 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1384 return EIO; /* Inappropriate ioctl for device */
1386 tcell = afs_GetPrimaryCell(READ_LOCK);
1387 if (!tcell) /* no primary cell? */
1389 strcpy(aout, tcell->cellName);
1390 *aoutSize = strlen(aout) + 1;
1391 afs_PutCell(tcell, READ_LOCK);
1396 * VIOC_GET_PRIMARY_CELL (33) - Get primary cell for caller
1400 * \param[in] ain not in use (user id found via areq)
1401 * \param[out] aout cell name
1403 * \retval ESRCH Error if the user id doesn't have a primary cell specified
1405 * \post Get the primary cell for a certain user, based on the user's uid
1407 DECL_PIOCTL(PGetUserCell)
1409 register afs_int32 i;
1410 register struct unixuser *tu;
1411 register struct cell *tcell;
1413 AFS_STATCNT(PGetUserCell);
1414 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1415 return EIO; /* Inappropriate ioctl for device */
1417 /* return the cell name of the primary cell for this user */
1418 i = UHash(areq->uid);
1419 ObtainWriteLock(&afs_xuser, 224);
1420 for (tu = afs_users[i]; tu; tu = tu->next) {
1421 if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1423 ReleaseWriteLock(&afs_xuser);
1428 tcell = afs_GetCell(tu->cell, READ_LOCK);
1429 afs_PutUser(tu, WRITE_LOCK);
1433 strcpy(aout, tcell->cellName);
1434 afs_PutCell(tcell, READ_LOCK);
1435 *aoutSize = strlen(aout) + 1; /* 1 for the null */
1438 ReleaseWriteLock(&afs_xuser);
1446 * VIOCSETTOK (3) - Set authentication tokens
1450 * \param[in] ain the krb tickets from which to set the afs tokens
1451 * \param[out] aout not in use
1453 * \retval EINVAL Error if the ticket is either too long or too short
1454 * \retval EIO Error if the AFS initState is below 101
1455 * \retval ESRCH Error if the cell for which the Token is being set can't be found
1457 * \post Set the Tokens for a specific cell name, unless there is none set, then default to primary
1460 DECL_PIOCTL(PSetTokens)
1463 register struct unixuser *tu;
1464 struct ClearToken clear;
1465 register struct cell *tcell;
1468 struct vrequest treq;
1469 afs_int32 flag, set_parent_pag = 0;
1471 AFS_STATCNT(PSetTokens);
1472 if (!afs_resourceinit_flag) {
1475 memcpy((char *)&i, ain, sizeof(afs_int32));
1476 ain += sizeof(afs_int32);
1477 stp = ain; /* remember where the ticket is */
1478 if (i < 0 || i > MAXKTCTICKETLEN)
1479 return EINVAL; /* malloc may fail */
1481 ain += i; /* skip over ticket */
1482 memcpy((char *)&i, ain, sizeof(afs_int32));
1483 ain += sizeof(afs_int32);
1484 if (i != sizeof(struct ClearToken)) {
1487 memcpy((char *)&clear, ain, sizeof(struct ClearToken));
1488 if (clear.AuthHandle == -1)
1489 clear.AuthHandle = 999; /* more rxvab compat stuff */
1490 ain += sizeof(struct ClearToken);
1491 if (ainSize != 2 * sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1492 /* still stuff left? we've got primary flag and cell name. Set these */
1493 memcpy((char *)&flag, ain, sizeof(afs_int32)); /* primary id flag */
1494 ain += sizeof(afs_int32); /* skip id field */
1495 /* rest is cell name, look it up */
1496 /* some versions of gcc appear to need != 0 in order to get this right */
1497 if ((flag & 0x8000) != 0) { /* XXX Use Constant XXX */
1501 tcell = afs_GetCellByName(ain, READ_LOCK);
1505 /* default to primary cell, primary id */
1506 flag = 1; /* primary id */
1507 tcell = afs_GetPrimaryCell(READ_LOCK);
1512 afs_PutCell(tcell, READ_LOCK);
1513 if (set_parent_pag) {
1515 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1516 # if defined(AFS_DARWIN_ENV)
1517 afs_proc_t *p = current_proc(); /* XXX */
1519 afs_proc_t *p = curproc; /* XXX */
1521 # ifndef AFS_DARWIN80_ENV
1522 uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1523 p->p_pid, p->p_comm);
1525 if (!setpag(p, acred, -1, &pag, 1)) {
1527 if (!setpag(acred, -1, &pag, 1)) {
1529 afs_InitReq(&treq, *acred);
1533 /* now we just set the tokens */
1534 tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1535 tu->vid = clear.ViceId;
1536 if (tu->stp != NULL) {
1537 afs_osi_Free(tu->stp, tu->stLen);
1539 tu->stp = (char *)afs_osi_Alloc(stLen);
1540 if (tu->stp == NULL) {
1544 memcpy(tu->stp, stp, stLen);
1547 afs_stats_cmfullperf.authent.TicketUpdates++;
1548 afs_ComputePAGStats();
1549 #endif /* AFS_NOSTATS */
1550 tu->states |= UHasTokens;
1551 tu->states &= ~UTokensBad;
1552 afs_SetPrimary(tu, flag);
1553 tu->tokenTime = osi_Time();
1554 afs_ResetUserConns(tu);
1555 afs_PutUser(tu, WRITE_LOCK);
1571 * VIOCGETVOLSTAT (4) - Get volume status
1575 * \param[in] ain not in use
1576 * \param[out] aout status of the volume
1578 * \retval EINVAL Error if some of the standard args aren't set
1580 * \post The status of a volume (based on the FID of the volume), or an offline message /motd
1582 DECL_PIOCTL(PGetVolumeStatus)
1585 char *offLineMsg = afs_osi_Alloc(256);
1586 char *motd = afs_osi_Alloc(256);
1587 register struct afs_conn *tc;
1588 register afs_int32 code = 0;
1589 struct AFSFetchVolumeStatus volstat;
1591 char *Name, *OfflineMsg, *MOTD;
1594 AFS_STATCNT(PGetVolumeStatus);
1600 OfflineMsg = offLineMsg;
1603 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1605 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1608 RXAFS_GetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &volstat,
1609 &Name, &OfflineMsg, &MOTD);
1614 } while (afs_Analyze
1615 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1616 SHARED_LOCK, NULL));
1620 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1622 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1623 cp += sizeof(VolumeStatus);
1624 strcpy(cp, volName);
1625 cp += strlen(volName) + 1;
1626 strcpy(cp, offLineMsg);
1627 cp += strlen(offLineMsg) + 1;
1629 cp += strlen(motd) + 1;
1630 *aoutSize = (cp - aout);
1632 afs_osi_Free(offLineMsg, 256);
1633 afs_osi_Free(motd, 256);
1638 * VIOCSETVOLSTAT (5) - Set volume status
1642 * \param[in] ain values to set the status at, offline message, message of the day, volume name, minimum quota, maximum quota
1643 * \param[out] aout status of a volume, offlines messages, minimum quota, maximumm quota
1645 * \retval EINVAL Error if some of the standard args aren't set
1646 * \retval EROFS Error if the volume is read only, or a backup volume
1647 * \retval ENODEV Error if the volume can't be accessed
1648 * \retval E2BIG Error if the volume name, offline message, and motd are too big
1650 * \post Set the status of a volume, including any offline messages, a minimum quota, and a maximum quota
1652 DECL_PIOCTL(PSetVolumeStatus)
1655 char *offLineMsg = afs_osi_Alloc(256);
1656 char *motd = afs_osi_Alloc(256);
1657 register struct afs_conn *tc;
1658 register afs_int32 code = 0;
1659 struct AFSFetchVolumeStatus volstat;
1660 struct AFSStoreVolumeStatus storeStat;
1661 register struct volume *tvp;
1665 AFS_STATCNT(PSetVolumeStatus);
1671 tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
1673 if (tvp->states & (VRO | VBackup)) {
1674 afs_PutVolume(tvp, READ_LOCK);
1678 afs_PutVolume(tvp, READ_LOCK);
1683 /* Copy the junk out, using cp as a roving pointer. */
1685 memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
1686 cp += sizeof(AFSFetchVolumeStatus);
1687 if (strlen(cp) >= sizeof(volName)) {
1691 strcpy(volName, cp);
1692 cp += strlen(volName) + 1;
1693 if (strlen(cp) >= sizeof(offLineMsg)) {
1697 strcpy(offLineMsg, cp);
1698 cp += strlen(offLineMsg) + 1;
1699 if (strlen(cp) >= sizeof(motd)) {
1705 if (volstat.MinQuota != -1) {
1706 storeStat.MinQuota = volstat.MinQuota;
1707 storeStat.Mask |= AFS_SETMINQUOTA;
1709 if (volstat.MaxQuota != -1) {
1710 storeStat.MaxQuota = volstat.MaxQuota;
1711 storeStat.Mask |= AFS_SETMAXQUOTA;
1714 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1716 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1719 RXAFS_SetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &storeStat,
1720 volName, offLineMsg, motd);
1725 } while (afs_Analyze
1726 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1727 SHARED_LOCK, NULL));
1731 /* we are sending parms back to make compat. with prev system. should
1732 * change interface later to not ask for current status, just set new status */
1734 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1735 cp += sizeof(VolumeStatus);
1736 strcpy(cp, volName);
1737 cp += strlen(volName) + 1;
1738 strcpy(cp, offLineMsg);
1739 cp += strlen(offLineMsg) + 1;
1741 cp += strlen(motd) + 1;
1742 *aoutSize = cp - aout;
1744 afs_osi_Free(offLineMsg, 256);
1745 afs_osi_Free(motd, 256);
1750 * VIOCFLUSH (6) - Invalidate cache entry
1754 * \param[in] ain not in use
1755 * \param[out] aout not in use
1757 * \retval EINVAL Error if some of the standard args aren't set
1759 * \post Flush any information the cache manager has on an entry
1763 AFS_STATCNT(PFlush);
1766 #ifdef AFS_BOZONLOCK_ENV
1767 afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
1769 ObtainWriteLock(&avc->lock, 225);
1770 afs_ResetVCache(avc, *acred);
1771 ReleaseWriteLock(&avc->lock);
1772 #ifdef AFS_BOZONLOCK_ENV
1773 afs_BozonUnlock(&avc->pvnLock, avc);
1779 * VIOC_AFS_STAT_MT_PT (29) - Stat mount point
1783 * \param[in] ain the last component in a path, related to mountpoint that we're looking for information about
1784 * \param[out] aout volume, cell, link data
1786 * \retval EINVAL Error if some of the standard args aren't set
1787 * \retval ENOTDIR Error if the 'mount point' argument isn't a directory
1788 * \retval EIO Error if the link data can't be accessed
1790 * \post Get the volume, and cell, as well as the link data for a mount point
1792 DECL_PIOCTL(PNewStatMount)
1794 register afs_int32 code;
1795 register struct vcache *tvc;
1796 register struct dcache *tdc;
1797 struct VenusFid tfid;
1799 struct sysname_info sysState;
1800 afs_size_t offset, len;
1802 AFS_STATCNT(PNewStatMount);
1805 code = afs_VerifyVCache(avc, areq);
1808 if (vType(avc) != VDIR) {
1811 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
1814 Check_AtSys(avc, ain, &sysState, areq);
1815 ObtainReadLock(&tdc->lock);
1817 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
1818 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1819 ReleaseReadLock(&tdc->lock);
1820 afs_PutDCache(tdc); /* we're done with the data */
1821 bufp = sysState.name;
1825 tfid.Cell = avc->f.fid.Cell;
1826 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
1827 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
1828 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
1830 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
1836 if (tvc->mvstat != 1) {
1841 ObtainWriteLock(&tvc->lock, 226);
1842 code = afs_HandleLink(tvc, areq);
1844 if (tvc->linkData) {
1845 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1848 /* we have the data */
1849 strcpy(aout, tvc->linkData);
1850 *aoutSize = strlen(tvc->linkData) + 1;
1855 ReleaseWriteLock(&tvc->lock);
1858 if (sysState.allocked)
1859 osi_FreeLargeSpace(bufp);
1864 * VIOCGETTOK (8) - Get authentication tokens
1868 * \param[in] ain userid
1869 * \param[out] aout token
1871 * \retval EIO Error if the afs daemon hasn't started yet
1872 * \retval EDOM Error if the input parameter is out of the bounds of the available tokens
1873 * \retval ENOTCONN Error if there aren't tokens for this cell
1875 * \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
1877 * \notes "it's a weird interface (from comments in the code)"
1880 DECL_PIOCTL(PGetTokens)
1882 register struct cell *tcell;
1883 register afs_int32 i;
1884 register struct unixuser *tu;
1886 afs_int32 iterator = 0;
1889 AFS_STATCNT(PGetTokens);
1890 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1891 return EIO; /* Inappropriate ioctl for device */
1893 /* weird interface. If input parameter is present, it is an integer and
1894 * we're supposed to return the parm'th tokens for this unix uid.
1895 * If not present, we just return tokens for cell 1.
1896 * If counter out of bounds, return EDOM.
1897 * If no tokens for the particular cell, return ENOTCONN.
1898 * Also, if this mysterious parm is present, we return, along with the
1899 * tokens, the primary cell indicator (an afs_int32 0) and the cell name
1900 * at the end, in that order.
1902 if ((newStyle = (ainSize > 0))) {
1903 memcpy((char *)&iterator, ain, sizeof(afs_int32));
1905 i = UHash(areq->uid);
1906 ObtainReadLock(&afs_xuser);
1907 for (tu = afs_users[i]; tu; tu = tu->next) {
1909 if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1910 if (iterator-- == 0)
1911 break; /* are we done yet? */
1914 if (tu->uid == areq->uid && afs_IsPrimaryCellNum(tu->cell))
1920 * No need to hold a read lock on each user entry
1924 ReleaseReadLock(&afs_xuser);
1929 if (((tu->states & UHasTokens) == 0)
1930 || (tu->ct.EndTimestamp < osi_Time())) {
1931 tu->states |= (UTokensBad | UNeedsReset);
1932 afs_PutUser(tu, READ_LOCK);
1935 /* use iterator for temp */
1937 iterator = tu->stLen; /* for compat, we try to return 56 byte tix if they fit */
1939 iterator = 56; /* # of bytes we're returning */
1940 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1941 cp += sizeof(afs_int32);
1942 memcpy(cp, tu->stp, tu->stLen); /* copy out st */
1944 iterator = sizeof(struct ClearToken);
1945 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1946 cp += sizeof(afs_int32);
1947 memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
1948 cp += sizeof(struct ClearToken);
1950 /* put out primary id and cell name, too */
1951 iterator = (tu->states & UPrimary ? 1 : 0);
1952 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1953 cp += sizeof(afs_int32);
1954 tcell = afs_GetCell(tu->cell, READ_LOCK);
1956 strcpy(cp, tcell->cellName);
1957 cp += strlen(tcell->cellName) + 1;
1958 afs_PutCell(tcell, READ_LOCK);
1962 *aoutSize = cp - aout;
1963 afs_PutUser(tu, READ_LOCK);
1968 * VIOCUNLOG (9) - Invalidate tokens
1972 * \param[in] ain not in use
1973 * \param[out] aout not in use
1975 * \retval EIO Error if the afs daemon hasn't been started yet
1977 * \post remove tokens from a user, specified by the user id
1979 * \notes sets the token's time to 0, which then causes it to be removed
1980 * \notes Unlog is the same as un-pag in OpenAFS
1984 register afs_int32 i;
1985 register struct unixuser *tu;
1987 AFS_STATCNT(PUnlog);
1988 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1989 return EIO; /* Inappropriate ioctl for device */
1991 i = UHash(areq->uid);
1992 ObtainWriteLock(&afs_xuser, 227);
1993 for (tu = afs_users[i]; tu; tu = tu->next) {
1994 if (tu->uid == areq->uid) {
1996 tu->states &= ~UHasTokens;
1997 /* security is not having to say you're sorry */
1998 memset(&tu->ct, 0, sizeof(struct ClearToken));
2000 ReleaseWriteLock(&afs_xuser);
2001 /* We have to drop the lock over the call to afs_ResetUserConns, since
2002 * it obtains the afs_xvcache lock. We could also keep the lock, and
2003 * modify ResetUserConns to take parm saying we obtained the lock
2004 * already, but that is overkill. By keeping the "tu" pointer
2005 * held over the released lock, we guarantee that we won't lose our
2006 * place, and that we'll pass over every user conn that existed when
2007 * we began this call.
2009 afs_ResetUserConns(tu);
2011 ObtainWriteLock(&afs_xuser, 228);
2013 /* set the expire times to 0, causes
2014 * afs_GCUserData to remove this entry
2016 tu->ct.EndTimestamp = 0;
2018 #endif /* UKERNEL */
2021 ReleaseWriteLock(&afs_xuser);
2026 * VIOC_AFS_MARINER_HOST (32) - Get/set mariner (cache manager monitor) host
2030 * \param[in] ain host address to be set
2031 * \param[out] aout old host address
2033 * \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
2035 * \notes Errors turn off mariner
2037 DECL_PIOCTL(PMariner)
2039 afs_int32 newHostAddr;
2040 afs_int32 oldHostAddr;
2042 AFS_STATCNT(PMariner);
2044 memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost,
2047 oldHostAddr = 0xffffffff; /* disabled */
2049 memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
2050 if (newHostAddr == 0xffffffff) {
2051 /* disable mariner operations */
2053 } else if (newHostAddr) {
2055 afs_marinerHost = newHostAddr;
2057 memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
2058 *aoutSize = sizeof(afs_int32);
2063 * VIOCCKSERV (10) - Check that servers are up
2067 * \param[in] ain name of the cell
2068 * \param[out] aout current down server list
2070 * \retval EIO Error if the afs daemon hasn't started yet
2071 * \retval EACCES Error if the user doesn't have super-user credentials
2072 * \retval ENOENT Error if we are unable to obtain the cell
2074 * \post Either a fast check (where it doesn't contact servers) or a local check (checks local cell only)
2076 DECL_PIOCTL(PCheckServers)
2078 register char *cp = 0;
2080 register struct server *ts;
2081 afs_int32 temp, *lp = (afs_int32 *) ain, havecell = 0;
2083 struct chservinfo *pcheck;
2085 AFS_STATCNT(PCheckServers);
2087 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2088 return EIO; /* Inappropriate ioctl for device */
2090 if (*lp == 0x12345678) { /* For afs3.3 version */
2091 pcheck = (struct chservinfo *)ain;
2092 if (pcheck->tinterval >= 0) {
2094 memcpy(cp, (char *)&afs_probe_interval, sizeof(afs_int32));
2095 *aoutSize = sizeof(afs_int32);
2096 if (pcheck->tinterval > 0) {
2097 if (!afs_osi_suser(*acred))
2099 afs_probe_interval = pcheck->tinterval;
2105 temp = pcheck->tflags;
2106 cp = pcheck->tbuffer;
2107 } else { /* For pre afs3.3 versions */
2108 memcpy((char *)&temp, ain, sizeof(afs_int32));
2109 cp = ain + sizeof(afs_int32);
2110 if (ainSize > sizeof(afs_int32))
2115 * 1: fast check, don't contact servers.
2116 * 2: local cell only.
2119 /* have cell name, too */
2120 cellp = afs_GetCellByName(cp, READ_LOCK);
2125 if (!cellp && (temp & 2)) {
2126 /* use local cell */
2127 cellp = afs_GetPrimaryCell(READ_LOCK);
2129 if (!(temp & 1)) { /* if not fast, call server checker routine */
2130 afs_CheckServers(1, cellp); /* check down servers */
2131 afs_CheckServers(0, cellp); /* check up servers */
2133 /* now return the current down server list */
2135 ObtainReadLock(&afs_xserver);
2136 for (i = 0; i < NSERVERS; i++) {
2137 for (ts = afs_servers[i]; ts; ts = ts->next) {
2138 if (cellp && ts->cell != cellp)
2139 continue; /* cell spec'd and wrong */
2140 if ((ts->flags & SRVR_ISDOWN)
2141 && ts->addr->sa_portal != ts->cell->vlport) {
2142 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2143 cp += sizeof(afs_int32);
2147 ReleaseReadLock(&afs_xserver);
2149 afs_PutCell(cellp, READ_LOCK);
2150 *aoutSize = cp - aout;
2155 * VIOCCKBACK (11) - Check backup volume mappings
2159 * \param[in] ain not in use
2160 * \param[out] aout not in use
2162 * \retval EIO Error if the afs daemon hasn't started yet
2164 * \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
2166 DECL_PIOCTL(PCheckVolNames)
2168 AFS_STATCNT(PCheckVolNames);
2169 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2170 return EIO; /* Inappropriate ioctl for device */
2172 afs_CheckRootVolume();
2173 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE | AFS_VOLCHECK_EXPIRED |
2174 AFS_VOLCHECK_BUSY | AFS_VOLCHECK_MTPTS);
2179 * VIOCCKCONN (12) - Check connections for a user
2183 * \param[in] ain not in use
2184 * \param[out] aout not in use
2186 * \retval EACCESS Error if no user is specififed, the user has no tokens set, or if the user's tokens are bad
2188 * \post check to see if a user has the correct authentication. If so, allow access.
2190 * \notes Check the connections to all the servers specified
2192 DECL_PIOCTL(PCheckAuth)
2196 struct afs_conn *tc;
2197 struct unixuser *tu;
2200 AFS_STATCNT(PCheckAuth);
2201 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2202 return EIO; /* Inappropriate ioctl for device */
2205 tu = afs_GetUser(areq->uid, 1, READ_LOCK); /* check local cell authentication */
2209 /* we have a user */
2210 ObtainReadLock(&afs_xsrvAddr);
2211 ObtainReadLock(&afs_xconn);
2213 /* any tokens set? */
2214 if ((tu->states & UHasTokens) == 0)
2216 /* all connections in cell 1 working? */
2217 for (i = 0; i < NSERVERS; i++) {
2218 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2219 for (tc = sa->conns; tc; tc = tc->next) {
2220 if (tc->user == tu && (tu->states & UTokensBad))
2225 ReleaseReadLock(&afs_xsrvAddr);
2226 ReleaseReadLock(&afs_xconn);
2227 afs_PutUser(tu, READ_LOCK);
2229 memcpy(aout, (char *)&retValue, sizeof(afs_int32));
2230 *aoutSize = sizeof(afs_int32);
2235 Prefetch(uparmtype apath, struct afs_ioctl *adata, int afollow,
2239 register afs_int32 code;
2240 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
2246 AFS_STATCNT(Prefetch);
2249 tp = osi_AllocLargeSpace(1024);
2250 AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2252 osi_FreeLargeSpace(tp);
2255 if (afs_BBusy()) { /* do this as late as possible */
2256 osi_FreeLargeSpace(tp);
2257 return EWOULDBLOCK; /* pretty close */
2259 afs_BQueue(BOP_PATH, (struct vcache *)0, 0, 0, acred, (afs_size_t) 0,
2260 (afs_size_t) 0, tp);
2265 * VIOCWHEREIS (14) - Find out where a volume is located
2269 * \param[in] ain not in use
2270 * \param[out] aout volume location
2272 * \retval EINVAL Error if some of the default arguments don't exist
2273 * \retval ENODEV Error if there is no such volume
2275 * \post fine a volume, based on a volume file id
2277 * \notes check each of the servers specified
2279 DECL_PIOCTL(PFindVolume)
2281 register struct volume *tvp;
2282 register struct server *ts;
2283 register afs_int32 i;
2286 AFS_STATCNT(PFindVolume);
2289 tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
2292 for (i = 0; i < AFS_MAXHOSTS; i++) {
2293 ts = tvp->serverHost[i];
2296 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2297 cp += sizeof(afs_int32);
2299 if (i < AFS_MAXHOSTS) {
2300 /* still room for terminating NULL, add it on */
2301 ainSize = 0; /* reuse vbl */
2302 memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
2303 cp += sizeof(afs_int32);
2305 *aoutSize = cp - aout;
2306 afs_PutVolume(tvp, READ_LOCK);
2313 * VIOCACCESS (20) - Access using PRS_FS bits
2317 * \param[in] ain PRS_FS bits
2318 * \param[out] aout not in use
2320 * \retval EINVAL Error if some of the initial arguments aren't set
2321 * \retval EACCES Error if access is denied
2323 * \post check to make sure access is allowed
2325 DECL_PIOCTL(PViceAccess)
2327 register afs_int32 code;
2330 AFS_STATCNT(PViceAccess);
2333 code = afs_VerifyVCache(avc, areq);
2336 memcpy((char *)&temp, ain, sizeof(afs_int32));
2337 code = afs_AccessOK(avc, temp, areq, CHECK_MODE_BITS);
2345 * VIOC_GETPAG (13) - Get PAG value
2349 * \param[in] ain not in use
2350 * \param[out] aout PAG value or NOPAG
2352 * \post get PAG value for the caller's cred
2354 DECL_PIOCTL(PGetPAG)
2358 pag = PagInCred(*acred);
2360 memcpy(aout, (char *)&pag, sizeof(afs_int32));
2361 *aoutSize = sizeof(afs_int32);
2365 DECL_PIOCTL(PPrecache)
2369 /*AFS_STATCNT(PPrecache);*/
2370 if (!afs_osi_suser(*acred))
2372 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2373 afs_preCache = newValue*1024;
2378 * VIOCSETCACHESIZE (24) - Set venus cache size in 1000 units
2382 * \param[in] ain the size the venus cache should be set to
2383 * \param[out] aout not in use
2385 * \retval EACCES Error if the user doesn't have super-user credentials
2386 * \retval EROFS Error if the cache is set to be in memory
2388 * \post Set the cache size based on user input. If no size is given, set it to the default OpenAFS cache size.
2390 * \notes recompute the general cache parameters for every single block allocated
2392 DECL_PIOCTL(PSetCacheSize)
2397 AFS_STATCNT(PSetCacheSize);
2398 if (!afs_osi_suser(*acred))
2400 /* too many things are setup initially in mem cache version */
2401 if (cacheDiskType == AFS_FCACHE_TYPE_MEM)
2403 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2405 afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2407 if (newValue < afs_min_cache)
2408 afs_cacheBlocks = afs_min_cache;
2410 afs_cacheBlocks = newValue;
2412 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2413 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2414 afs_MaybeWakeupTruncateDaemon();
2415 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2416 afs_osi_Wait(1000, 0, 0);
2417 afs_MaybeWakeupTruncateDaemon();
2422 #define MAXGCSTATS 16
2424 * VIOCGETCACHEPARMS (40) - Get cache stats
2428 * \param[in] ain afs index flags
2429 * \param[out] aout cache blocks, blocks used, blocks files (in an array)
2431 * \post Get the cache blocks, and how many of the cache blocks there are
2433 DECL_PIOCTL(PGetCacheSize)
2435 afs_int32 results[MAXGCSTATS];
2437 register struct dcache * tdc;
2440 AFS_STATCNT(PGetCacheSize);
2442 if (sizeof(afs_int32) == ainSize){
2443 memcpy((char *)&flags, ain, sizeof(afs_int32));
2444 } else if (0 == ainSize){
2450 memset(results, 0, sizeof(results));
2451 results[0] = afs_cacheBlocks;
2452 results[1] = afs_blocksUsed;
2453 results[2] = afs_cacheFiles;
2456 for (i = 0; i < afs_cacheFiles; i++) {
2457 if (afs_indexFlags[i] & IFFree) results[3]++;
2459 } else if (2 == flags){
2460 for (i = 0; i < afs_cacheFiles; i++) {
2461 if (afs_indexFlags[i] & IFFree) results[3]++;
2462 if (afs_indexFlags[i] & IFEverUsed) results[4]++;
2463 if (afs_indexFlags[i] & IFDataMod) results[5]++;
2464 if (afs_indexFlags[i] & IFDirtyPages) results[6]++;
2465 if (afs_indexFlags[i] & IFAnyPages) results[7]++;
2466 if (afs_indexFlags[i] & IFDiscarded) results[8]++;
2468 tdc = afs_indexTable[i];
2471 size = tdc->validPos;
2472 if ( 0 < size && size < (1<<12) ) results[10]++;
2473 else if (size < (1<<14) ) results[11]++;
2474 else if (size < (1<<16) ) results[12]++;
2475 else if (size < (1<<18) ) results[13]++;
2476 else if (size < (1<<20) ) results[14]++;
2477 else if (size >= (1<<20) ) results[15]++;
2481 memcpy(aout, (char *)results, sizeof(results));
2482 *aoutSize = sizeof(results);
2487 * VIOCFLUSHCB (25) - Flush callback only
2491 * \param[in] ain not in use
2492 * \param[out] aout not in use
2494 * \retval EINVAL Error if some of the standard args aren't set
2495 * \retval 0 0 returned if the volume is set to read-only
2497 * \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.
2499 DECL_PIOCTL(PRemoveCallBack)
2501 register struct afs_conn *tc;
2502 register afs_int32 code = 0;
2503 struct AFSCallBack CallBacks_Array[1];
2504 struct AFSCBFids theFids;
2505 struct AFSCBs theCBs;
2508 AFS_STATCNT(PRemoveCallBack);
2511 if (avc->f.states & CRO)
2512 return 0; /* read-only-ness can't change */
2513 ObtainWriteLock(&avc->lock, 229);
2514 theFids.AFSCBFids_len = 1;
2515 theCBs.AFSCBs_len = 1;
2516 theFids.AFSCBFids_val = (struct AFSFid *)&avc->f.fid.Fid;
2517 theCBs.AFSCBs_val = CallBacks_Array;
2518 CallBacks_Array[0].CallBackType = CB_DROPPED;
2519 if (avc->callback) {
2521 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
2523 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2525 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2529 /* don't set code on failure since we wouldn't use it */
2530 } while (afs_Analyze
2531 (tc, code, &avc->f.fid, areq,
2532 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK, NULL));
2534 ObtainWriteLock(&afs_xcbhash, 457);
2535 afs_DequeueCallback(avc);
2537 avc->f.states &= ~(CStatd | CUnique);
2538 ReleaseWriteLock(&afs_xcbhash);
2539 if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2540 osi_dnlc_purgedp(avc);
2542 ReleaseWriteLock(&avc->lock);
2547 * VIOCNEWCELL (26) - Configure new cell
2551 * \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
2552 * \param[out] aout not in use
2554 * \retval EIO Error if the afs daemon hasn't started yet
2555 * \retval EACCES Error if the user doesn't have super-user cedentials
2556 * \retval EINVAL Error if some 'magic' var doesn't have a certain bit set
2558 * \post creates a new cell
2560 DECL_PIOCTL(PNewCell)
2562 /* create a new cell */
2563 afs_int32 cellHosts[AFS_MAXCELLHOSTS], *lp, magic = 0;
2564 char *newcell = 0, *linkedcell = 0, *tp = ain;
2565 register afs_int32 code, linkedstate = 0, ls;
2566 u_short fsport = 0, vlport = 0;
2569 AFS_STATCNT(PNewCell);
2570 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2571 return EIO; /* Inappropriate ioctl for device */
2573 if (!afs_osi_suser(*acred))
2576 memcpy((char *)&magic, tp, sizeof(afs_int32));
2577 tp += sizeof(afs_int32);
2578 if (magic != 0x12345678)
2581 /* A 3.4 fs newcell command will pass an array of AFS_MAXCELLHOSTS
2582 * server addresses while the 3.5 fs newcell command passes
2583 * AFS_MAXHOSTS. To figure out which is which, check if the cellname
2586 newcell = tp + (AFS_MAXCELLHOSTS + 3) * sizeof(afs_int32);
2587 scount = ((newcell[0] != '\0') ? AFS_MAXCELLHOSTS : AFS_MAXHOSTS);
2589 /* AFS_MAXCELLHOSTS (=8) is less than AFS_MAXHOSTS (=13) */
2590 memcpy((char *)cellHosts, tp, AFS_MAXCELLHOSTS * sizeof(afs_int32));
2591 tp += (scount * sizeof(afs_int32));
2593 lp = (afs_int32 *) tp;
2597 fsport = 0; /* Privileged ports not allowed */
2599 vlport = 0; /* Privileged ports not allowed */
2600 tp += (3 * sizeof(afs_int32));
2602 if ((ls = *lp) & 1) {
2603 linkedcell = tp + strlen(newcell) + 1;
2604 linkedstate |= CLinkedCell;
2607 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2609 afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport,
2614 DECL_PIOCTL(PNewAlias)
2616 /* create a new cell alias */
2618 register afs_int32 code;
2619 char *realName, *aliasName;
2621 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2622 return EIO; /* Inappropriate ioctl for device */
2624 if (!afs_osi_suser(*acred))
2628 tp += strlen(aliasName) + 1;
2631 code = afs_NewCellAlias(aliasName, realName);
2637 * VIOCGETCELL (27) - Get cell info
2641 * \param[in] ain The cell index of a specific cell
2642 * \param[out] aout list of servers in the cell
2644 * \retval EIO Error if the afs daemon hasn't started yet
2645 * \retval EDOM Error if there is no cell asked about
2647 * \post Lists the cell's server names and and addresses
2649 DECL_PIOCTL(PListCells)
2651 afs_int32 whichCell;
2652 register struct cell *tcell = 0;
2653 register afs_int32 i;
2654 register char *cp, *tp = ain;
2656 AFS_STATCNT(PListCells);
2657 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2658 return EIO; /* Inappropriate ioctl for device */
2660 memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2661 tp += sizeof(afs_int32);
2662 tcell = afs_GetCellByIndex(whichCell, READ_LOCK);
2665 memset(cp, 0, AFS_MAXCELLHOSTS * sizeof(afs_int32));
2666 for (i = 0; i < AFS_MAXCELLHOSTS; i++) {
2667 if (tcell->cellHosts[i] == 0)
2669 memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip,
2671 cp += sizeof(afs_int32);
2673 cp = aout + AFS_MAXCELLHOSTS * sizeof(afs_int32);
2674 strcpy(cp, tcell->cellName);
2675 cp += strlen(tcell->cellName) + 1;
2676 *aoutSize = cp - aout;
2677 afs_PutCell(tcell, READ_LOCK);
2685 DECL_PIOCTL(PListAliases)
2687 afs_int32 whichAlias;
2688 register struct cell_alias *tcalias = 0;
2689 register char *cp, *tp = ain;
2691 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2692 return EIO; /* Inappropriate ioctl for device */
2693 if (ainSize < sizeof(afs_int32))
2696 memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2697 tp += sizeof(afs_int32);
2699 tcalias = afs_GetCellAlias(whichAlias);
2702 strcpy(cp, tcalias->alias);
2703 cp += strlen(tcalias->alias) + 1;
2704 strcpy(cp, tcalias->cell);
2705 cp += strlen(tcalias->cell) + 1;
2706 *aoutSize = cp - aout;
2707 afs_PutCellAlias(tcalias);
2716 * VIOC_AFS_DELETE_MT_PT (28) - Delete mount point
2720 * \param[in] ain the name of the file in this dir to remove
2721 * \param[out] aout not in use
2723 * \retval EINVAL Error if some of the standard args aren't set
2724 * \retval ENOTDIR Error if the argument to remove is not a directory
2725 * \retval ENOENT Error if there is no cache to remove the mount point from or if a vcache doesn't exist
2727 * \post Ensure that everything is OK before deleting the mountpoint. If not, don't delete. Delete a mount point based on a file id.
2729 DECL_PIOCTL(PRemoveMount)
2731 register afs_int32 code;
2733 struct sysname_info sysState;
2734 afs_size_t offset, len;
2735 register struct afs_conn *tc;
2736 register struct dcache *tdc;
2737 register struct vcache *tvc;
2738 struct AFSFetchStatus OutDirStatus;
2739 struct VenusFid tfid;
2740 struct AFSVolSync tsync;
2744 /* "ain" is the name of the file in this dir to remove */
2746 AFS_STATCNT(PRemoveMount);
2749 code = afs_VerifyVCache(avc, areq);
2752 if (vType(avc) != VDIR)
2755 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1); /* test for error below */
2758 Check_AtSys(avc, ain, &sysState, areq);
2759 ObtainReadLock(&tdc->lock);
2761 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
2762 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2763 ReleaseReadLock(&tdc->lock);
2764 bufp = sysState.name;
2769 tfid.Cell = avc->f.fid.Cell;
2770 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
2771 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
2772 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
2774 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
2781 if (tvc->mvstat != 1) {
2787 ObtainWriteLock(&tvc->lock, 230);
2788 code = afs_HandleLink(tvc, areq);
2790 if (tvc->linkData) {
2791 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2796 ReleaseWriteLock(&tvc->lock);
2797 osi_dnlc_purgedp(tvc);
2803 ObtainWriteLock(&avc->lock, 231);
2804 osi_dnlc_remove(avc, bufp, tvc);
2806 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
2808 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2811 RXAFS_RemoveFile(tc->id, (struct AFSFid *)&avc->f.fid.Fid, bufp,
2812 &OutDirStatus, &tsync);
2817 } while (afs_Analyze
2818 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_REMOVEFILE,
2819 SHARED_LOCK, NULL));
2824 ReleaseWriteLock(&avc->lock);
2828 /* we have the thing in the cache */
2829 ObtainWriteLock(&tdc->lock, 661);
2830 if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2831 /* we can do it locally */
2832 code = afs_dir_Delete(tdc, bufp);
2834 ZapDCE(tdc); /* surprise error -- invalid value */
2838 ReleaseWriteLock(&tdc->lock);
2839 afs_PutDCache(tdc); /* drop ref count */
2841 avc->f.states &= ~CUnique; /* For the dfs xlator */
2842 ReleaseWriteLock(&avc->lock);
2845 if (sysState.allocked)
2846 osi_FreeLargeSpace(bufp);
2851 * VIOC_VENUSLOG (34) - Enable/Disable venus logging
2855 * \retval EINVAL Error if some of the standard args aren't set
2857 * \notes Obsoleted, perhaps should be PBogus
2859 DECL_PIOCTL(PVenusLogging)
2861 return EINVAL; /* OBSOLETE */
2865 * VIOC_GETCELLSTATUS (35) - Get cell status info
2869 * \param[in] ain The cell you want status information on
2870 * \param[out] aout cell state (as a struct)
2872 * \retval EIO Error if the afs daemon hasn't started yet
2873 * \retval ENOENT Error if the cell doesn't exist
2875 * \post Returns the state of the cell as defined in a struct cell
2877 DECL_PIOCTL(PGetCellStatus)
2879 register struct cell *tcell;
2882 AFS_STATCNT(PGetCellStatus);
2883 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2884 return EIO; /* Inappropriate ioctl for device */
2886 tcell = afs_GetCellByName(ain, READ_LOCK);
2889 temp = tcell->states;
2890 afs_PutCell(tcell, READ_LOCK);
2891 memcpy(aout, (char *)&temp, sizeof(afs_int32));
2892 *aoutSize = sizeof(afs_int32);
2897 * VIOC_SETCELLSTATUS (36) - Set corresponding info
2901 * \param[in] ain The cell you want to set information about, and the values you want to set
2902 * \param[out] aout not in use
2904 * \retval EIO Error if the afs daemon hasn't started yet
2905 * \retval EACCES Error if the user doesn't have super-user credentials
2907 * \post Set the state of the cell in a defined struct cell, based on whether or not SetUID is allowed
2909 DECL_PIOCTL(PSetCellStatus)
2911 register struct cell *tcell;
2914 if (!afs_osi_suser(*acred))
2916 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2917 return EIO; /* Inappropriate ioctl for device */
2919 tcell = afs_GetCellByName(ain + 2 * sizeof(afs_int32), WRITE_LOCK);
2922 memcpy((char *)&temp, ain, sizeof(afs_int32));
2924 tcell->states |= CNoSUID;
2926 tcell->states &= ~CNoSUID;
2927 afs_PutCell(tcell, WRITE_LOCK);
2932 * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
2936 * \param[in] ain not in use (args in avc)
2937 * \param[out] aout not in use
2939 * \retval EINVAL Error if some of the standard args aren't set
2940 * \retval EIO Error if the afs daemon hasn't started yet
2942 * \post Wipe everything on the volume. This is done dependent on which platform this is for.
2944 * \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.
2946 DECL_PIOCTL(PFlushVolumeData)
2948 register afs_int32 i;
2949 register struct dcache *tdc;
2950 register struct vcache *tvc;
2951 register struct volume *tv;
2952 afs_int32 cell, volume;
2953 struct afs_q *tq, *uq;
2954 #ifdef AFS_DARWIN80_ENV
2958 AFS_STATCNT(PFlushVolumeData);
2961 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2962 return EIO; /* Inappropriate ioctl for device */
2964 volume = avc->f.fid.Fid.Volume; /* who to zap */
2965 cell = avc->f.fid.Cell;
2968 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
2969 * the vcaches associated with the volume.
2972 ObtainReadLock(&afs_xvcache);
2973 i = VCHashV(&avc->f.fid);
2974 for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
2977 if (tvc->f.fid.Fid.Volume == volume && tvc->f.fid.Cell == cell) {
2978 if (tvc->f.states & CVInit) {
2979 ReleaseReadLock(&afs_xvcache);
2980 afs_osi_Sleep(&tvc->f.states);
2983 #ifdef AFS_DARWIN80_ENV
2984 if (tvc->f.states & CDeadVnode) {
2985 ReleaseReadLock(&afs_xvcache);
2986 afs_osi_Sleep(&tvc->f.states);
2990 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
2991 VN_HOLD(AFSTOV(tvc));
2992 #elif defined(AFS_DARWIN80_ENV)
2996 if (vnode_ref(vp)) {
3002 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
3005 VREFCOUNT_INC(tvc); /* AIX, apparently */
3007 ReleaseReadLock(&afs_xvcache);
3008 #ifdef AFS_BOZONLOCK_ENV
3009 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3011 ObtainWriteLock(&tvc->lock, 232);
3013 ObtainWriteLock(&afs_xcbhash, 458);
3014 afs_DequeueCallback(tvc);
3015 tvc->f.states &= ~(CStatd | CDirty);
3016 ReleaseWriteLock(&afs_xcbhash);
3017 if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
3018 osi_dnlc_purgedp(tvc);
3019 afs_TryToSmush(tvc, *acred, 1);
3020 ReleaseWriteLock(&tvc->lock);
3021 #ifdef AFS_BOZONLOCK_ENV
3022 afs_BozonUnlock(&tvc->pvnLock, tvc);
3024 #ifdef AFS_DARWIN80_ENV
3025 vnode_put(AFSTOV(tvc));
3027 ObtainReadLock(&afs_xvcache);
3029 /* our tvc ptr is still good until now */
3033 ReleaseReadLock(&afs_xvcache);
3036 ObtainWriteLock(&afs_xdcache, 328); /* needed if you're going to flush any stuff */
3037 for (i = 0; i < afs_cacheFiles; i++) {
3038 if (!(afs_indexFlags[i] & IFEverUsed))
3039 continue; /* never had any data */
3040 tdc = afs_GetDSlot(i, NULL);
3041 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
3042 ReleaseReadLock(&tdc->tlock);
3043 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
3044 if (!(afs_indexFlags[i] & IFDataMod)) {
3045 /* if the file is modified, but has a ref cnt of only 1, then
3046 * someone probably has the file open and is writing into it.
3047 * Better to skip flushing such a file, it will be brought back
3048 * immediately on the next write anyway.
3050 * If we *must* flush, then this code has to be rearranged to call
3051 * afs_storeAllSegments() first */
3052 afs_FlushDCache(tdc);
3056 ReleaseReadLock(&tdc->tlock);
3058 afs_PutDCache(tdc); /* bumped by getdslot */
3060 ReleaseWriteLock(&afs_xdcache);
3062 ObtainReadLock(&afs_xvolume);
3063 for (i = 0; i < NVOLS; i++) {
3064 for (tv = afs_volumes[i]; tv; tv = tv->next) {
3065 if (tv->volume == volume) {
3066 afs_ResetVolumeInfo(tv);
3071 ReleaseReadLock(&afs_xvolume);
3073 /* probably, a user is doing this, probably, because things are screwed up.
3074 * maybe it's the dnlc's fault? */
3081 * VIOCGETVCXSTATUS (41) - gets vnode x status
3085 * \param[in] ain not in use (avc used)
3086 * \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
3088 * \retval EINVAL Error if some of the initial default arguments aren't set
3089 * \retval EACCES Error if access to check the mode bits is denied
3091 * \post gets stats for the vnode, a struct listed in vcxstat
3093 DECL_PIOCTL(PGetVnodeXStatus)
3095 register afs_int32 code;
3096 struct vcxstat stat;
3099 /* AFS_STATCNT(PGetVnodeXStatus); */
3102 code = afs_VerifyVCache(avc, areq);
3105 if (vType(avc) == VDIR)
3106 mode = PRSFS_LOOKUP;
3109 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3112 memset(&stat, 0, sizeof(struct vcxstat));
3113 stat.fid = avc->f.fid;
3114 hset32(stat.DataVersion, hgetlo(avc->f.m.DataVersion));
3115 stat.lock = avc->lock;
3116 stat.parentVnode = avc->f.parent.vnode;
3117 stat.parentUnique = avc->f.parent.unique;
3118 hset(stat.flushDV, avc->flushDV);
3119 hset(stat.mapDV, avc->mapDV);
3120 stat.truncPos = avc->f.truncPos;
3121 { /* just grab the first two - won't break anything... */
3122 struct axscache *ac;
3124 for (i = 0, ac = avc->Access; ac && i < CPSIZE; i++, ac = ac->next) {
3125 stat.randomUid[i] = ac->uid;
3126 stat.randomAccess[i] = ac->axess;
3129 stat.callback = afs_data_pointer_to_int32(avc->callback);
3130 stat.cbExpires = avc->cbExpires;
3131 stat.anyAccess = avc->f.anyAccess;
3132 stat.opens = avc->opens;
3133 stat.execsOrWriters = avc->execsOrWriters;
3134 stat.flockCount = avc->flockCount;
3135 stat.mvstat = avc->mvstat;
3136 stat.states = avc->f.states;
3137 memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
3138 *aoutSize = sizeof(struct vcxstat);
3143 DECL_PIOCTL(PGetVnodeXStatus2)
3145 register afs_int32 code;
3146 struct vcxstat2 stat;
3151 code = afs_VerifyVCache(avc, areq);
3154 if (vType(avc) == VDIR)
3155 mode = PRSFS_LOOKUP;
3158 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3161 memset(&stat, 0, sizeof(struct vcxstat2));
3163 stat.cbExpires = avc->cbExpires;
3164 stat.anyAccess = avc->f.anyAccess;
3165 stat.mvstat = avc->mvstat;
3166 stat.callerAccess = afs_GetAccessBits(avc, ~0, areq);
3168 memcpy(aout, (char *)&stat, sizeof(struct vcxstat2));
3169 *aoutSize = sizeof(struct vcxstat2);
3175 * VIOC_AFS_SYSNAME (38) - Change @sys value
3179 * \param[in] ain new value for @sys
3180 * \param[out] aout count, entry, list (debug values?)
3182 * \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"
3183 * \retval ENODEV Error if there isn't already a system named that ("I THINK")
3184 * \retval EACCES Error if the user doesn't have super-user credentials
3186 * \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
3188 * \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.
3190 DECL_PIOCTL(PSetSysName)
3192 char *cp, *cp2 = NULL, inname[MAXSYSNAME], outname[MAXSYSNAME];
3193 afs_int32 setsysname;
3195 register struct afs_exporter *exporter;
3196 register struct unixuser *au;
3197 register afs_int32 pag, error;
3198 int t, count, num = 0, allpags = 0;
3201 AFS_STATCNT(PSetSysName);
3202 if (!afs_globalVFS) {
3203 /* Afsd is NOT running; disable it */
3204 #if defined(KERNEL_HAVE_UERROR)
3205 return (setuerror(EINVAL), EINVAL);
3210 memset(inname, 0, MAXSYSNAME);
3211 memcpy(&setsysname, ain, sizeof(afs_int32));
3212 ain += sizeof(afs_int32);
3213 if (setsysname & 0x8000) {
3215 setsysname &= ~0x8000;
3220 if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
3223 for (cp = ain, count = 0; count < setsysname; count++) {
3224 /* won't go past end of ain since maxsysname*num < ain length */
3226 if (t >= MAXSYSNAME || t <= 0)
3228 /* check for names that can shoot us in the foot */
3229 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
3235 /* inname gets first entry in case we're being a translator */
3237 memcpy(inname, ain, t + 1); /* include terminating null */
3241 if (afs_cr_gid(*acred) == RMTUSER_REQ ||
3242 afs_cr_gid(*acred) == RMTUSER_REQ_PRIV) { /* Handles all exporters */
3243 if (allpags && afs_cr_gid(*acred) != RMTUSER_REQ_PRIV) {
3246 pag = PagInCred(*acred);
3248 return EINVAL; /* Better than panicing */
3250 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
3251 return EINVAL; /* Better than panicing */
3253 if (!(exporter = au->exporter)) {
3254 afs_PutUser(au, READ_LOCK);
3255 return EINVAL; /* Better than panicing */
3257 error = EXP_SYSNAME(exporter, (setsysname ? cp2 : NULL), &sysnamelist,
3260 if (error == ENODEV)
3261 foundname = 0; /* sysname not set yet! */
3263 afs_PutUser(au, READ_LOCK);
3268 strcpy(outname, sysnamelist[0]);
3270 afs_PutUser(au, READ_LOCK);
3274 /* Not xlating, so local case */
3276 osi_Panic("PSetSysName: !afs_sysname\n");
3277 if (!setsysname) { /* user just wants the info */
3278 strcpy(outname, afs_sysname);
3279 foundname = afs_sysnamecount;
3280 sysnamelist = afs_sysnamelist;
3281 } else { /* Local guy; only root can change sysname */
3282 if (!afs_osi_suser(*acred))
3285 /* allpags makes no sense for local use */
3289 /* clear @sys entries from the dnlc, once afs_lookup can
3290 * do lookups of @sys entries and thinks it can trust them */
3291 /* privs ok, store the entry, ... */
3292 strcpy(afs_sysname, inname);
3293 if (setsysname > 1) { /* ... or list */
3295 for (count = 1; count < setsysname; ++count) {
3296 if (!afs_sysnamelist[count])
3298 ("PSetSysName: no afs_sysnamelist entry to write\n");
3300 memcpy(afs_sysnamelist[count], cp, t + 1); /* include null */
3304 afs_sysnamecount = setsysname;
3309 cp = aout; /* not changing so report back the count and ... */
3310 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
3311 cp += sizeof(afs_int32);
3313 strcpy(cp, outname); /* ... the entry, ... */
3314 cp += strlen(outname) + 1;
3315 for (count = 1; count < foundname; ++count) { /* ... or list. */
3316 if (!sysnamelist[count])
3318 ("PSetSysName: no afs_sysnamelist entry to read\n");
3319 t = strlen(sysnamelist[count]);
3320 if (t >= MAXSYSNAME)
3321 osi_Panic("PSetSysName: sysname entry garbled\n");
3322 strcpy(cp, sysnamelist[count]);
3326 *aoutSize = cp - aout;
3331 /* sequential search through the list of touched cells is not a good
3332 * long-term solution here. For small n, though, it should be just
3333 * fine. Should consider special-casing the local cell for large n.
3334 * Likewise for PSetSPrefs.
3336 * s - number of ids in array l[] -- NOT index of last id
3337 * l - array of cell ids which have volumes that need to be sorted
3338 * vlonly - sort vl servers or file servers?
3341 ReSortCells_cb(struct cell *cell, void *arg)
3343 afs_int32 *p = (afs_int32 *) arg;
3344 afs_int32 *l = p + 1;
3347 for (i = 0; i < s; i++) {
3348 if (l[i] == cell->cellNum) {
3349 ObtainWriteLock(&cell->lock, 690);
3350 afs_SortServers(cell->cellHosts, AFS_MAXCELLHOSTS);
3351 ReleaseWriteLock(&cell->lock);
3359 ReSortCells(int s, afs_int32 * l, int vlonly)
3367 p = (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * (s + 1));
3369 memcpy(p + 1, l, s * sizeof(afs_int32));
3370 afs_TraverseCells(&ReSortCells_cb, p);
3371 afs_osi_Free(p, sizeof(afs_int32) * (s + 1));
3375 ObtainReadLock(&afs_xvolume);
3376 for (i = 0; i < NVOLS; i++) {
3377 for (j = afs_volumes[i]; j; j = j->next) {
3378 for (k = 0; k < s; k++)
3379 if (j->cell == l[k]) {
3380 ObtainWriteLock(&j->lock, 233);
3381 afs_SortServers(j->serverHost, AFS_MAXHOSTS);
3382 ReleaseWriteLock(&j->lock);
3387 ReleaseReadLock(&afs_xvolume);
3391 static int debugsetsp = 0;
3393 afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
3396 int i, j, k, matches, touchedSize;
3397 struct server *srvr = NULL;
3398 afs_int32 touched[34];
3402 for (k = 0; k < num; sp++, k++) {
3404 printf("sp host=%x, rank=%d\n", sp->host.s_addr, sp->rank);
3407 ObtainReadLock(&afs_xserver);
3409 i = SHash(sp->host.s_addr);
3410 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
3411 if (sa->sa_ip == sp->host.s_addr) {
3413 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3414 || (sa->sa_portal == AFS_FSPORT);
3415 if ((!vlonly && isfs) || (vlonly && !isfs)) {
3422 if (sa && matches) { /* found one! */
3424 printf("sa ip=%x, ip_rank=%d\n", sa->sa_ip, sa->sa_iprank);
3426 sa->sa_iprank = sp->rank + afs_randomMod15();
3427 afs_SortOneServer(sa->server);
3430 /* if we don't know yet what cell it's in, this is moot */
3431 for (j = touchedSize - 1;
3432 j >= 0 && touched[j] != srvr->cell->cellNum; j--)
3433 /* is it in our list of touched cells ? */ ;
3434 if (j < 0) { /* no, it's not */
3435 touched[touchedSize++] = srvr->cell->cellNum;
3436 if (touchedSize >= 32) { /* watch for ovrflow */
3437 ReleaseReadLock(&afs_xserver);
3438 ReSortCells(touchedSize, touched, vlonly);
3440 ObtainReadLock(&afs_xserver);
3446 ReleaseReadLock(&afs_xserver);
3447 /* if we didn't find one, start to create one. */
3448 /* Note that it doesn't have a cell yet... */
3450 afs_uint32 temp = sp->host.s_addr;
3452 afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
3453 WRITE_LOCK, (afsUUID *) 0, 0);
3454 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3455 afs_PutServer(srvr, WRITE_LOCK);
3457 } /* for all cited preferences */
3459 ReSortCells(touchedSize, touched, vlonly);
3464 * VIOC_SETPREFS (46) - Set server ranks
3466 * \param[in] ain the sprefs value you want the sprefs to be set to
3467 * \param[out] aout not in use
3469 * \retval EIO Error if the afs daemon hasn't started yet
3470 * \retval EACCES Error if the user doesn't have super-user credentials
3471 * \retval EINVAL Error if the struct setsprefs is too large or if it multiplied by the number of servers is too large
3473 * \post set the sprefs using the afs_setsprefs() function
3475 DECL_PIOCTL(PSetSPrefs)
3477 struct setspref *ssp;
3478 AFS_STATCNT(PSetSPrefs);
3480 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3481 return EIO; /* Inappropriate ioctl for device */
3483 if (!afs_osi_suser(*acred))
3486 if (ainSize < sizeof(struct setspref))
3489 ssp = (struct setspref *)ain;
3490 if (ainSize < sizeof(struct spref) * ssp->num_servers)
3493 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
3494 (ssp->flags & DBservers));
3499 * VIOC_SETPREFS33 (42) - Set server ranks (deprecated)
3501 * \param[in] ain the server preferences to be set
3502 * \param[out] aout not in use
3504 * \retval EIO Error if the afs daemon hasn't started yet
3505 * \retval EACCES Error if the user doesn't have super-user credentials
3507 * \post set the server preferences, calling a function
3509 * \notes this may only be performed by the local root user.
3511 DECL_PIOCTL(PSetSPrefs33)
3514 AFS_STATCNT(PSetSPrefs);
3515 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3516 return EIO; /* Inappropriate ioctl for device */
3519 if (!afs_osi_suser(*acred))
3522 sp = (struct spref *)ain;
3523 afs_setsprefs(sp, ainSize / (sizeof(struct spref)), 0 /*!vlonly */ );
3528 * VIOC_GETSPREFS (43) - Get server ranks
3532 * \param[in] ain the server preferences to get
3533 * \param[out] aout the server preferences information
3535 * \retval EIO Error if the afs daemon hasn't started yet
3536 * \retval ENOENT Error if the sprefrequest is too large
3538 * \post Get the sprefs
3540 * \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.
3542 DECL_PIOCTL(PGetSPrefs)
3544 struct sprefrequest *spin; /* input */
3545 struct sprefinfo *spout; /* output */
3546 struct spref *srvout; /* one output component */
3547 int i, j; /* counters for hash table traversal */
3548 struct server *srvr; /* one of CM's server structs */
3550 int vlonly; /* just return vlservers ? */
3553 AFS_STATCNT(PGetSPrefs);
3554 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3555 return EIO; /* Inappropriate ioctl for device */
3558 if (ainSize < sizeof(struct sprefrequest_33)) {
3561 spin = ((struct sprefrequest *)ain);
3564 if (ainSize > sizeof(struct sprefrequest_33)) {
3565 vlonly = (spin->flags & DBservers);
3569 /* struct sprefinfo includes 1 server struct... that size gets added
3570 * in during the loop that follows.
3572 *aoutSize = sizeof(struct sprefinfo) - sizeof(struct spref);
3573 spout = (struct sprefinfo *)aout;
3574 spout->next_offset = spin->offset;
3575 spout->num_servers = 0;
3576 srvout = spout->servers;
3578 ObtainReadLock(&afs_xserver);
3579 for (i = 0, j = 0; j < NSERVERS; j++) { /* sift through hash table */
3580 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3581 if (spin->offset > (unsigned short)i) {
3582 continue; /* catch up to where we left off */
3584 spout->next_offset++;
3587 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3588 || (sa->sa_portal == AFS_FSPORT);
3590 if ((vlonly && isfs) || (!vlonly && !isfs)) {
3591 /* only report ranks for vl servers */
3595 srvout->host.s_addr = sa->sa_ip;
3596 srvout->rank = sa->sa_iprank;
3597 *aoutSize += sizeof(struct spref);
3598 spout->num_servers++;
3601 if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3602 ReleaseReadLock(&afs_xserver); /* no more room! */
3607 ReleaseReadLock(&afs_xserver);
3609 spout->next_offset = 0; /* start over from the beginning next time */
3613 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3614 int afs_NFSRootOnly = 1;
3616 * VIOC_EXPORTAFS (39) - Export afs to nfs clients
3620 * \param[in] ain a struct Vic * EIOctl containing export values needed to change between nfs and afs
3621 * \param[out] aout a struct of the exporter states (exporter->exp_states)
3623 * \retval ENODEV Error if the exporter doesn't exist
3624 * \retval EACCES Error if the user doesn't have super-user credentials
3626 * \post Changes the state of various values to reflect the change of the export values between nfs and afs.
3628 * \notes Legacy code obtained from IBM.
3630 DECL_PIOCTL(PExportAfs)
3632 afs_int32 export, newint =
3633 0, type, changestate, handleValue, convmode, pwsync, smounts;
3634 afs_int32 rempags = 0, pagcb = 0;
3635 register struct afs_exporter *exporter;
3637 AFS_STATCNT(PExportAfs);
3638 memcpy((char *)&handleValue, ain, sizeof(afs_int32));
3639 type = handleValue >> 24;
3644 exporter = exporter_find(type);
3646 export = handleValue & 3;
3647 changestate = handleValue & 0xfff;
3648 smounts = (handleValue >> 2) & 3;
3649 pwsync = (handleValue >> 4) & 3;
3650 convmode = (handleValue >> 6) & 3;
3651 rempags = (handleValue >> 8) & 3;
3652 pagcb = (handleValue >> 10) & 3;
3654 changestate = (handleValue >> 16) & 0x1;
3655 convmode = (handleValue >> 16) & 0x2;
3656 pwsync = (handleValue >> 16) & 0x4;
3657 smounts = (handleValue >> 16) & 0x8;
3658 export = handleValue & 0xff;
3661 /* Failed finding desired exporter; */
3665 handleValue = exporter->exp_states;
3666 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3667 *aoutSize = sizeof(afs_int32);
3669 if (!afs_osi_suser(*acred))
3670 return EACCES; /* Only superuser can do this */
3674 exporter->exp_states |= EXP_EXPORTED;
3676 exporter->exp_states &= ~EXP_EXPORTED;
3680 exporter->exp_states |= EXP_UNIXMODE;
3682 exporter->exp_states &= ~EXP_UNIXMODE;
3686 exporter->exp_states |= EXP_PWSYNC;
3688 exporter->exp_states &= ~EXP_PWSYNC;
3692 afs_NFSRootOnly = 0;
3693 exporter->exp_states |= EXP_SUBMOUNTS;
3695 afs_NFSRootOnly = 1;
3696 exporter->exp_states &= ~EXP_SUBMOUNTS;
3701 exporter->exp_states |= EXP_CLIPAGS;
3703 exporter->exp_states &= ~EXP_CLIPAGS;
3707 exporter->exp_states |= EXP_CALLBACK;
3709 exporter->exp_states &= ~EXP_CALLBACK;
3711 handleValue = exporter->exp_states;
3712 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3713 *aoutSize = sizeof(afs_int32);
3716 exporter->exp_states |= EXP_EXPORTED;
3718 exporter->exp_states &= ~EXP_EXPORTED;
3720 exporter->exp_states |= EXP_UNIXMODE;
3722 exporter->exp_states &= ~EXP_UNIXMODE;
3724 exporter->exp_states |= EXP_PWSYNC;
3726 exporter->exp_states &= ~EXP_PWSYNC;
3728 afs_NFSRootOnly = 0;
3729 exporter->exp_states |= EXP_SUBMOUNTS;
3731 afs_NFSRootOnly = 1;
3732 exporter->exp_states &= ~EXP_SUBMOUNTS;
3741 * VIOC_GAG (44) - Silence Cache Manager
3745 * \param[in] ain the flags to either gag or de-gag the cache manager
3746 * \param[out] aout not in use
3748 * \retval EACCES Error if the user doesn't have super-user credentials
3750 * \post set the gag flags, then show these flags
3754 struct gaginfo *gagflags;
3756 if (!afs_osi_suser(*acred))
3759 gagflags = (struct gaginfo *)ain;
3760 afs_showflags = gagflags->showflags;
3766 * VIOC_TWIDDLE (45) - Adjust RX knobs
3770 * \param[in] ain the previous settings of the 'knobs'
3771 * \param[out] aout not in use
3773 * \retval EACCES Error if the user doesn't have super-user credentials
3775 * \post build out the struct rxp, from a struct rx
3777 DECL_PIOCTL(PTwiddleRx)
3779 struct rxparams *rxp;
3781 if (!afs_osi_suser(*acred))
3784 rxp = (struct rxparams *)ain;
3786 if (rxp->rx_initReceiveWindow)
3787 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3788 if (rxp->rx_maxReceiveWindow)
3789 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3790 if (rxp->rx_initSendWindow)
3791 rx_initSendWindow = rxp->rx_initSendWindow;
3792 if (rxp->rx_maxSendWindow)
3793 rx_maxSendWindow = rxp->rx_maxSendWindow;
3794 if (rxp->rxi_nSendFrags)
3795 rxi_nSendFrags = rxp->rxi_nSendFrags;
3796 if (rxp->rxi_nRecvFrags)
3797 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3798 if (rxp->rxi_OrphanFragSize)
3799 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3800 if (rxp->rx_maxReceiveSize) {
3801 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3802 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3804 if (rxp->rx_MyMaxSendSize)
3805 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3811 * VIOC_GETINITPARAMS (49) - Get initial cache manager parameters
3815 * \param[in] ain not in use
3816 * \param[out] aout initial cache manager params
3818 * \retval E2BIG Error if the initial parameters are bigger than some PIGGYSIZE
3820 * \post return the initial cache manager parameters
3822 DECL_PIOCTL(PGetInitParams)
3824 if (sizeof(struct cm_initparams) > PIGGYSIZE)
3827 memcpy(aout, (char *)&cm_initParams, sizeof(struct cm_initparams));
3828 *aoutSize = sizeof(struct cm_initparams);
3832 #ifdef AFS_SGI65_ENV
3833 /* They took crget() from us, so fake it. */
3838 cr = crdup(get_current_cred());
3839 memset(cr, 0, sizeof(cred_t));
3840 #if CELL || CELL_PREPARE
3848 * VIOC_GETRXKCRYPT (55) - Get rxkad encryption flag
3852 * \param[in] ain not in use
3853 * \param[out] aout value of cryptall
3855 * \post get the value of cryptall (presumably whether or not things should be encrypted)
3857 DECL_PIOCTL(PGetRxkcrypt)
3859 memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3860 *aoutSize = sizeof(afs_int32);
3865 * VIOC_SETRXKCRYPT (56) - Set rxkad encryption flag
3869 * \param[in] ain the argument whether or not things should be encrypted
3870 * \param[out] aout not in use
3872 * \retval EPERM Error if the user doesn't have super-user credentials
3873 * \retval EINVAL Error if the input is too big, or if the input is outside the bounds of what it can be set to
3875 * \post set whether or not things should be encrypted
3877 * \notes may need to be modified at a later date to take into account other values for cryptall (beyond true or false)
3879 DECL_PIOCTL(PSetRxkcrypt)
3883 if (!afs_osi_suser(*acred))
3885 if (ainSize != sizeof(afs_int32) || ain == NULL)
3887 memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3888 /* if new mappings added later this will need to be changed */
3889 if (tmpval != 0 && tmpval != 1)
3895 #ifdef AFS_NEED_CLIENTCONTEXT
3897 * Create new credentials to correspond to a remote user with given
3898 * <hostaddr, uid, g0, g1>. This allows a server running as root to
3899 * provide pioctl (and other) services to foreign clients (i.e. nfs
3900 * clients) by using this call to `become' the client.
3903 #define PIOCTL_HEADER 6
3905 HandleClientContext(struct afs_ioctl *ablob, int *com,
3906 afs_ucred_t **acred, afs_ucred_t *credp)
3909 afs_uint32 hostaddr;
3910 afs_int32 uid, g0, g1, i, code, pag, exporter_type, isroot = 0;
3911 struct afs_exporter *exporter, *outexporter;
3912 afs_ucred_t *newcred;
3913 struct unixuser *au;
3914 afs_uint32 comp = *com & 0xff00;
3916 #if defined(AFS_SUN510_ENV)
3920 #if defined(AFS_SGIMP_ENV)
3921 osi_Assert(ISAFS_GLOCK());
3923 AFS_STATCNT(HandleClientContext);
3924 if (ablob->in_size < PIOCTL_HEADER * sizeof(afs_int32)) {
3925 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3926 return EINVAL; /* Too small to be good */
3928 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3929 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER * sizeof(afs_int32), code);
3931 osi_FreeLargeSpace(inData);
3935 /* Extract information for remote user */
3936 hostaddr = *((afs_uint32 *) ain);
3937 ain += sizeof(hostaddr);
3938 uid = *((afs_uint32 *) ain);
3940 g0 = *((afs_uint32 *) ain);
3942 g1 = *((afs_uint32 *) ain);
3944 *com = *((afs_uint32 *) ain);
3945 ain += sizeof(afs_int32);
3946 exporter_type = *((afs_uint32 *) ain); /* In case we support more than NFS */
3949 * Of course, one must be root for most of these functions, but
3950 * we'll allow (for knfs) you to set things if the pag is 0 and
3951 * you're setting tokens or unlogging.
3954 if (!afs_osi_suser(credp)) {
3955 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI64_ENV)
3956 /* Since SGI's suser() returns explicit failure after the call.. */
3959 /* check for acceptable opcodes for normal folks, which are, so far,
3960 * get/set tokens, sysname, and unlog.
3962 if (i != 9 && i != 3 && i != 38 && i != 8) {
3963 osi_FreeLargeSpace(inData);
3968 ablob->in_size -= PIOCTL_HEADER * sizeof(afs_int32);
3969 ablob->in += PIOCTL_HEADER * sizeof(afs_int32);
3970 osi_FreeLargeSpace(inData);
3973 * We map uid 0 to nobody to match the mapping that the nfs
3974 * server does and to ensure that the suser() calls in the afs
3975 * code fails for remote client roots.
3977 uid = afs_nobody; /* NFS_NOBODY == -2 */
3981 #ifdef AFS_AIX41_ENV
3984 afs_set_cr_gid(newcred, isroot ? RMTUSER_REQ_PRIV : RMTUSER_REQ);
3985 #ifdef AFS_AIX51_ENV
3986 newcred->cr_groupset.gs_union.un_groups[0] = g0;
3987 newcred->cr_groupset.gs_union.un_groups[1] = g1;
3988 #elif defined(AFS_LINUX26_ENV)
3989 # ifdef AFS_LINUX26_ONEGROUP_ENV
3990 set_cr_group_info(newcred, groups_alloc(1)); /* not that anything sets this */
3991 l = (((g0-0x3f00) & 0x3fff) << 14) | ((g1-0x3f00) & 0x3fff);
3992 h = ((g0-0x3f00) >> 14);
3993 h = ((g1-0x3f00) >> 14) + h + h + h;
3994 GROUP_AT(cr_group_info(newcred), 0) = ((h << 28) | l);
3996 set_cr_group_info(newcred, groups_alloc(2));
3997 GROUP_AT(cr_group_info(newcred), 0) = g0;
3998 GROUP_AT(cr_group_info(newcred), 1) = g1;
4000 #elif defined(AFS_SUN510_ENV)
4003 crsetgroups(newcred, 2, gids);
4005 newcred->cr_groups[0] = g0;
4006 newcred->cr_groups[1] = g1;
4009 newcred->cr_ngrps = 2;
4010 #elif !defined(AFS_LINUX26_ENV) && !defined(AFS_SUN510_ENV)
4011 # if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
4012 newcred->cr_ngroups = 2;
4014 for (i = 2; i < NGROUPS; i++)
4015 newcred->cr_groups[i] = NOGROUP;
4018 if (!(exporter = exporter_find(exporter_type))) {
4019 /* Exporter wasn't initialized or an invalid exporter type */
4023 if (exporter->exp_states & EXP_PWSYNC) {
4024 if (uid != afs_cr_uid(credp)) {
4026 return ENOEXEC; /* XXX Find a better errno XXX */
4029 afs_set_cr_uid(newcred, uid); /* Only temporary */
4030 code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
4031 /* The client's pag is the only unique identifier for it */
4032 afs_set_cr_uid(newcred, pag);
4034 if (!code && *com == PSETPAG) {
4035 /* Special case for 'setpag' */
4036 afs_uint32 pagvalue = genpag();
4038 au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
4040 * Note that we leave the 'outexporter' struct held so it won't
4043 au->exporter = outexporter;
4044 if (ablob->out_size >= 4) {
4045 AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32),
4048 afs_PutUser(au, WRITE_LOCK);
4051 return PSETPAG; /* Special return for setpag */
4053 EXP_RELE(outexporter);
4056 *com = (*com) | comp;
4059 #endif /* AFS_NEED_CLIENTCONTEXT */
4063 * VIOC_GETCPREFS (50) - Get client interface
4067 * \param[in] ain sprefrequest input
4068 * \param[out] aout spref information
4070 * \retval EIO Error if the afs daemon hasn't started yet
4071 * \retval EINVAL Error if some of the standard args aren't set
4073 * \post get all interface addresses and other information of the client interface
4075 DECL_PIOCTL(PGetCPrefs)
4077 struct sprefrequest *spin; /* input */
4078 struct sprefinfo *spout; /* output */
4079 struct spref *srvout; /* one output component */
4083 AFS_STATCNT(PGetCPrefs);
4084 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4085 return EIO; /* Inappropriate ioctl for device */
4087 if (ainSize < sizeof(struct sprefrequest))
4090 spin = (struct sprefrequest *)ain;
4091 spout = (struct sprefinfo *)aout;
4093 maxNumber = spin->num_servers; /* max addrs this time */
4094 srvout = spout->servers;
4096 ObtainReadLock(&afs_xinterface);
4098 /* copy out the client interface information from the
4099 ** kernel data structure "interface" to the output buffer
4101 for (i = spin->offset, j = 0; (i < afs_cb_interface.numberOfInterfaces)
4102 && (j < maxNumber); i++, j++, srvout++)
4103 srvout->host.s_addr = afs_cb_interface.addr_in[i];
4105 spout->num_servers = j;
4106 *aoutSize = sizeof(struct sprefinfo) + (j - 1) * sizeof(struct spref);
4108 if (i >= afs_cb_interface.numberOfInterfaces)
4109 spout->next_offset = 0; /* start from beginning again */
4111 spout->next_offset = spin->offset + j;
4113 ReleaseReadLock(&afs_xinterface);
4118 * VIOC_SETCPREFS (51) - Set client interface
4122 * \param[in] ain the interfaces you want set
4123 * \param[out] aout not in use
4125 * \retval EIO Error if the afs daemon hasn't started yet
4126 * \retval EINVAL Error if the input is too large for the struct
4127 * \retval ENOMEM Error if there are too many servers
4129 * \post set the callbak interfaces addresses to those of the hosts
4131 DECL_PIOCTL(PSetCPrefs)
4133 struct setspref *sin;
4136 AFS_STATCNT(PSetCPrefs);
4137 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4138 return EIO; /* Inappropriate ioctl for device */
4140 sin = (struct setspref *)ain;
4142 if (ainSize < sizeof(struct setspref))
4144 #if 0 /* num_servers is unsigned */
4145 if (sin->num_servers < 0)
4148 if (sin->num_servers > AFS_MAX_INTERFACE_ADDR)
4151 ObtainWriteLock(&afs_xinterface, 412);
4152 afs_cb_interface.numberOfInterfaces = sin->num_servers;
4153 for (i = 0; (unsigned short)i < sin->num_servers; i++)
4154 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
4156 ReleaseWriteLock(&afs_xinterface);
4161 * VIOC_AFS_FLUSHMOUNT (52) - Flush mount symlink data
4165 * \param[in] ain the last part of a path to a mount point, which tells us what to flush
4166 * \param[out] aout not in use
4168 * \retval EINVAL Error if some of the initial arguments aren't set
4169 * \retval ENOTDIR Error if the initial argument for the mount point isn't a directory
4170 * \retval ENOENT Error if the dcache entry isn't set
4172 * \post remove all of the mount data from the dcache regarding a certain mount point
4174 DECL_PIOCTL(PFlushMount)
4176 register afs_int32 code;
4177 register struct vcache *tvc;
4178 register struct dcache *tdc;
4179 struct VenusFid tfid;
4181 struct sysname_info sysState;
4182 afs_size_t offset, len;
4184 AFS_STATCNT(PFlushMount);
4187 code = afs_VerifyVCache(avc, areq);
4190 if (vType(avc) != VDIR) {
4193 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
4196 Check_AtSys(avc, ain, &sysState, areq);
4197 ObtainReadLock(&tdc->lock);
4199 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
4200 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
4201 ReleaseReadLock(&tdc->lock);
4202 afs_PutDCache(tdc); /* we're done with the data */
4203 bufp = sysState.name;
4207 tfid.Cell = avc->f.fid.Cell;
4208 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
4209 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
4210 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
4212 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4218 if (tvc->mvstat != 1) {
4223 #ifdef AFS_BOZONLOCK_ENV
4224 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
4226 ObtainWriteLock(&tvc->lock, 649);
4227 ObtainWriteLock(&afs_xcbhash, 650);
4228 afs_DequeueCallback(tvc);
4229 tvc->f.states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
4230 ReleaseWriteLock(&afs_xcbhash);
4231 /* now find the disk cache entries */
4232 afs_TryToSmush(tvc, *acred, 1);
4233 osi_dnlc_purgedp(tvc);
4234 if (tvc->linkData && !(tvc->f.states & CCore)) {
4235 afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
4236 tvc->linkData = NULL;
4238 ReleaseWriteLock(&tvc->lock);
4239 #ifdef AFS_BOZONLOCK_ENV
4240 afs_BozonUnlock(&tvc->pvnLock, tvc);
4244 if (sysState.allocked)
4245 osi_FreeLargeSpace(bufp);
4250 * VIOC_RXSTAT_PROC (53) - Control process RX statistics
4254 * \param[in] ain the flags that control which stats to use
4255 * \param[out] aout not in use
4257 * \retval EACCES Error if the user doesn't have super-user credentials
4258 * \retval EINVAL Error if the flag input is too long
4260 * \post either enable process RPCStats, disable process RPCStats, or clear the process RPCStats
4262 DECL_PIOCTL(PRxStatProc)
4267 if (!afs_osi_suser(*acred)) {
4271 if (ainSize != sizeof(afs_int32)) {
4275 memcpy((char *)&flags, ain, sizeof(afs_int32));
4276 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4280 if (flags & AFSCALL_RXSTATS_ENABLE) {
4281 rx_enableProcessRPCStats();
4283 if (flags & AFSCALL_RXSTATS_DISABLE) {
4284 rx_disableProcessRPCStats();
4286 if (flags & AFSCALL_RXSTATS_CLEAR) {
4287 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
4296 * VIOC_RXSTAT_PEER (54) - Control peer RX statistics
4300 * \param[in] ain the flags that control which statistics to use
4301 * \param[out] aout not in use
4303 * \retval EACCES Error if the user doesn't have super-user credentials
4304 * \retval EINVAL Error if the flag input is too long
4306 * \post either enable peer RPCStatws, disable peer RPCStats, or clear the peer RPCStats
4308 DECL_PIOCTL(PRxStatPeer)
4313 if (!afs_osi_suser(*acred)) {
4317 if (ainSize != sizeof(afs_int32)) {
4321 memcpy((char *)&flags, ain, sizeof(afs_int32));
4322 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4326 if (flags & AFSCALL_RXSTATS_ENABLE) {
4327 rx_enablePeerRPCStats();
4329 if (flags & AFSCALL_RXSTATS_DISABLE) {
4330 rx_disablePeerRPCStats();
4332 if (flags & AFSCALL_RXSTATS_CLEAR) {
4333 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
4340 DECL_PIOCTL(PPrefetchFromTape)
4342 register afs_int32 code, code1;
4344 struct afs_conn *tc;
4345 struct rx_call *tcall;
4346 struct AFSVolSync tsync;
4347 struct AFSFetchStatus OutStatus;
4348 struct AFSCallBack CallBack;
4349 struct VenusFid tfid;
4353 AFS_STATCNT(PSetAcl);
4357 if (ain && (ainSize == 3 * sizeof(afs_int32)))
4358 Fid = (struct AFSFid *)ain;
4360 Fid = &avc->f.fid.Fid;
4361 tfid.Cell = avc->f.fid.Cell;
4362 tfid.Fid.Volume = Fid->Volume;
4363 tfid.Fid.Vnode = Fid->Vnode;
4364 tfid.Fid.Unique = Fid->Unique;
4366 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4368 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4369 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &avc->f.fid);
4372 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4373 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &tvc->f.fid);
4376 tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
4380 tcall = rx_NewCall(tc->id);
4382 StartRXAFS_FetchData(tcall, (struct AFSFid *)&tvc->f.fid.Fid, 0,
4385 bytes = rx_Read(tcall, (char *)aout, sizeof(afs_int32));
4387 EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
4389 code1 = rx_EndCall(tcall, code);
4393 } while (afs_Analyze
4394 (tc, code, &tvc->f.fid, areq, AFS_STATS_FS_RPCIDX_RESIDENCYRPCS,
4395 SHARED_LOCK, NULL));
4396 /* This call is done only to have the callback things handled correctly */
4397 afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
4401 *aoutSize = sizeof(afs_int32);
4408 register afs_int32 code;
4409 struct afs_conn *tc;
4411 struct FsCmdInputs *Inputs;
4412 struct FsCmdOutputs *Outputs;
4413 struct VenusFid tfid;
4416 Inputs = (struct FsCmdInputs *)ain;
4417 Outputs = (struct FsCmdOutputs *)aout;
4420 if (!ain || ainSize != sizeof(struct FsCmdInputs))
4425 Fid = &avc->f.fid.Fid;
4427 tfid.Cell = avc->f.fid.Cell;
4428 tfid.Fid.Volume = Fid->Volume;
4429 tfid.Fid.Vnode = Fid->Vnode;
4430 tfid.Fid.Unique = Fid->Unique;
4432 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4433 afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD, ICL_TYPE_POINTER, tvc,
4434 ICL_TYPE_INT32, Inputs->command, ICL_TYPE_FID, &tfid);
4438 if (Inputs->command) {
4440 tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
4444 RXAFS_FsCmd(tc->id, Fid, Inputs,
4445 (struct FsCmdOutputs *)aout);
4449 } while (afs_Analyze
4450 (tc, code, &tvc->f.fid, areq,
4451 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK, NULL));
4452 /* This call is done to have the callback things handled correctly */
4453 afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4454 } else { /* just a status request, return also link data */
4456 Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4457 Outputs->chars[0] = 0;
4458 if (vType(tvc) == VLNK) {
4459 ObtainWriteLock(&tvc->lock, 555);
4460 if (afs_HandleLink(tvc, areq) == 0)
4461 strncpy((char *)&Outputs->chars, tvc->linkData, MAXCMDCHARS);
4462 ReleaseWriteLock(&tvc->lock);
4469 *aoutSize = sizeof(struct FsCmdOutputs);
4474 DECL_PIOCTL(PNewUuid)
4476 /*AFS_STATCNT(PNewUuid); */
4477 if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4478 return EIO; /* Inappropriate ioctl for device */
4480 if (!afs_osi_suser(*acred))
4483 ObtainWriteLock(&afs_xinterface, 555);
4484 afs_uuid_create(&afs_cb_interface.uuid);
4485 ReleaseWriteLock(&afs_xinterface);
4486 ForceAllNewConnections();
4490 #if defined(AFS_CACHE_BYPASS)
4492 DECL_PIOCTL(PSetCachingThreshold)
4497 setting = getting = 1;
4499 if (ain == NULL || ainSize < sizeof(afs_int32))
4505 if (setting == 0 && getting == 0)
4509 * If setting, set first, and return the value now in effect
4512 afs_int32 threshold;
4514 if (!afs_osi_suser(*acred))
4516 memcpy((char *)&threshold, ain, sizeof(afs_int32));
4517 cache_bypass_threshold = threshold;
4518 afs_warn("Cache Bypass Threshold set to: %d\n", threshold);
4519 /* TODO: move to separate pioctl, or enhance pioctl */
4520 cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
4524 /* Return the current size threshold */
4525 afs_int32 oldThreshold = cache_bypass_threshold;
4526 memcpy(aout, (char *)&oldThreshold, sizeof(afs_int32));
4527 *aoutSize = sizeof(afs_int32);
4533 #endif /* defined(AFS_CACHE_BYPASS) */
4535 DECL_PIOCTL(PCallBackAddr)
4538 afs_uint32 addr, code;
4542 struct afs_conn *tc;
4544 struct unixuser *tu;
4545 struct srvAddr **addrs;
4547 /*AFS_STATCNT(PCallBackAddr); */
4548 if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4549 return EIO; /* Inappropriate ioctl for device */
4551 if (!afs_osi_suser(acred))
4554 if (ainSize < sizeof(afs_int32))
4557 memcpy(&addr, ain, sizeof(afs_int32));
4559 ObtainReadLock(&afs_xinterface);
4560 for (i = 0; (unsigned short)i < afs_cb_interface.numberOfInterfaces; i++) {
4561 if (afs_cb_interface.addr_in[i] == addr)
4565 ReleaseWriteLock(&afs_xinterface);
4567 if (afs_cb_interface.addr_in[i] != addr)
4570 ObtainReadLock(&afs_xserver); /* Necessary? */
4571 ObtainReadLock(&afs_xsrvAddr);
4574 for (i = 0; i < NSERVERS; i++) {
4575 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4580 addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
4582 for (i = 0; i < NSERVERS; i++) {
4583 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4584 if (j >= srvAddrCount)
4590 ReleaseReadLock(&afs_xsrvAddr);
4591 ReleaseReadLock(&afs_xserver);
4593 for (i = 0; i < j; i++) {
4599 /* vlserver has no callback conn */
4600 if (sa->sa_portal == AFS_VLPORT) {
4604 if (!ts->cell) /* not really an active server, anyway, it must */
4605 continue; /* have just been added by setsprefs */
4607 /* get a connection, even if host is down; bumps conn ref count */
4608 tu = afs_GetUser(areq->uid, ts->cell->cellNum, SHARED_LOCK);
4609 tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
4610 1 /*force */ , 1 /*create */ , SHARED_LOCK);
4611 afs_PutUser(tu, SHARED_LOCK);
4615 if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(ts)) {
4616 if (sa->sa_flags & SRVADDR_ISDOWN) {
4617 rx_SetConnDeadTime(tc->id, 3);
4619 #ifdef RX_ENABLE_LOCKS
4621 #endif /* RX_ENABLE_LOCKS */
4622 code = RXAFS_CallBackRxConnAddr(tc->id, &addr);
4623 #ifdef RX_ENABLE_LOCKS
4625 #endif /* RX_ENABLE_LOCKS */
4627 afs_PutConn(tc, SHARED_LOCK); /* done with it now */
4628 } /* Outer loop over addrs */
4629 #endif /* UKERNEL */
4633 DECL_PIOCTL(PDiscon)
4635 #ifdef AFS_DISCON_ENV
4636 static afs_int32 mode = 1; /* Start up in 'off' */
4637 afs_int32 force = 0;
4642 if (!afs_osi_suser(*acred))
4648 afs_ConflictPolicy = ain[1] - 1;
4653 * All of these numbers are hard coded in fs.c. If they
4654 * change here, they should change there and vice versa
4657 case 0: /* Disconnect ("offline" mode), breaking all callbacks */
4658 if (!AFS_IS_DISCONNECTED) {
4659 ObtainWriteLock(&afs_discon_lock, 999);
4660 afs_DisconGiveUpCallbacks();
4661 afs_RemoveAllConns();
4662 afs_is_disconnected = 1;
4663 afs_is_discon_rw = 1;
4664 ReleaseWriteLock(&afs_discon_lock);
4667 case 1: /* Fully connected, ("online" mode). */
4668 ObtainWriteLock(&afs_discon_lock, 998);
4671 afs_MarkAllServersUp();
4672 code = afs_ResyncDisconFiles(areq, *acred);
4675 if (code && !force) {
4676 printf("Files not synchronized properly, still in discon state. \n"
4677 "Please retry or use \"force\".\n");
4681 afs_DisconDiscardAll(*acred);
4683 afs_ClearAllStatdFlag();
4684 afs_is_disconnected = 0;
4685 afs_is_discon_rw = 0;
4686 printf("\nSync succeeded. You are back online.\n");
4689 ReleaseWriteLock(&afs_discon_lock);
4698 memcpy(aout, &mode, sizeof(afs_int32));
4699 *aoutSize = sizeof(afs_int32);
4706 DECL_PIOCTL(PNFSNukeCreds)
4709 register afs_int32 i;
4710 register struct unixuser *tu;
4712 AFS_STATCNT(PUnlog);
4713 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4714 return EIO; /* Inappropriate ioctl for device */
4716 if (ainSize < sizeof(afs_int32))
4718 memcpy(&addr, ain, sizeof(afs_int32));
4720 if (afs_cr_gid(*acred) == RMTUSER_REQ_PRIV && !addr) {
4721 tu = afs_GetUser(areq->uid, -1, SHARED_LOCK);
4722 if (!tu->exporter || !(addr = EXP_GETHOST(tu->exporter))) {
4723 afs_PutUser(tu, SHARED_LOCK);
4726 afs_PutUser(tu, SHARED_LOCK);
4727 } else if (!afs_osi_suser(acred)) {
4731 ObtainWriteLock(&afs_xuser, 227);
4732 for (i = 0; i < NUSERS; i++) {
4733 for (tu = afs_users[i]; tu; tu = tu->next) {
4734 if (tu->exporter && EXP_CHECKHOST(tu->exporter, addr)) {
4736 tu->states &= ~UHasTokens;
4737 /* security is not having to say you're sorry */
4738 memset(&tu->ct, 0, sizeof(struct ClearToken));
4740 ReleaseWriteLock(&afs_xuser);
4741 afs_ResetUserConns(tu);
4743 ObtainWriteLock(&afs_xuser, 228);
4745 /* set the expire times to 0, causes
4746 * afs_GCUserData to remove this entry
4748 tu->ct.EndTimestamp = 0;
4750 #endif /* UKERNEL */
4754 ReleaseWriteLock(&afs_xuser);