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"
15 #include "../afs/sysincludes.h" /* Standard vendor system headers */
16 #include "../afs/afsincludes.h" /* Afs-based standard headers */
17 #include "../afs/afs_stats.h" /* afs statistics */
18 #include "../afs/vice.h"
19 #include "../rx/rx_globals.h"
21 extern void afs_ComputePAGStats();
22 extern struct vcache *afs_LookupVCache();
23 struct VenusFid afs_rootFid;
24 afs_int32 afs_waitForever=0;
25 short afs_waitForeverCount = 0;
26 afs_int32 afs_showflags = GAGUSER | GAGCONSOLE; /* show all messages */
27 extern afs_int32 PROBE_INTERVAL;
29 extern int cacheDiskType;
30 extern afs_int32 afs_cacheBlocks;
31 extern struct afs_q CellLRU;
32 extern char *afs_indexFlags; /* only one: is there data there? */
33 extern afs_int32 afs_blocksUsed;
34 extern struct unixuser *afs_users[NUSERS];
35 extern struct server *afs_servers[NSERVERS];
36 extern struct interfaceAddr afs_cb_interface; /* client interface addresses */
37 extern afs_rwlock_t afs_xserver;
38 extern afs_rwlock_t afs_xinterface;
39 extern afs_rwlock_t afs_xcell;
40 extern afs_rwlock_t afs_xuser;
41 #ifndef AFS_FINEG_SUNLOCK
42 extern afs_rwlock_t afs_xconn;
44 extern afs_rwlock_t afs_xvolume;
45 extern afs_lock_t afs_xdcache; /* lock: alloc new disk cache entries */
46 extern afs_rwlock_t afs_xvcache;
47 extern afs_rwlock_t afs_xcbhash;
48 extern afs_int32 afs_mariner, afs_marinerHost;
49 extern struct srvAddr *afs_srvAddrs[NSERVERS];
50 extern int afs_resourceinit_flag;
51 extern afs_int32 cryptall;
53 static int PBogus(), PSetAcl(), PGetAcl(), PSetTokens(), PGetVolumeStatus();
54 static int PSetVolumeStatus(), PFlush(), PNewStatMount(), PGetTokens(), PUnlog();
55 static int PCheckServers(), PCheckVolNames(), PCheckAuth(), PFindVolume();
56 static int PViceAccess(), PSetCacheSize(), Prefetch();
57 static int PRemoveCallBack(), PNewCell(), PListCells(), PRemoveMount();
58 static int PMariner(), PGetUserCell(), PGetWSCell(), PGetFileCell();
59 static int PVenusLogging(), PNoop(), PSetCellStatus(), PGetCellStatus();
60 static int PFlushVolumeData(), PGetCacheSize();
61 static int PSetSysName(),PGetFID();
62 static int PGetVnodeXStatus();
63 static int PSetSPrefs(), PGetSPrefs(), PGag(), PTwiddleRx();
64 static int PSetSPrefs33(), PStoreBehind(), PGCPAGs();
65 static int PGetCPrefs(), PSetCPrefs(); /* client network addresses */
66 static int PGetInitParams(), PFlushMount(), PRxStatProc(), PRxStatPeer();
67 static int PGetRxkcrypt(), PSetRxkcrypt();
68 static int PPrefetchFromTape(), PResidencyCmd();
69 static int PNewAlias(), PListAliases();
72 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp);
74 extern struct cm_initparams cm_initParams;
76 static int (*(VpioctlSw[]))() = {
81 PGetVolumeStatus, /* 4 */
82 PSetVolumeStatus, /* 5 */
87 PCheckServers, /* 10 */
88 PCheckVolNames, /* 11 */
90 PBogus, /* 13 -- used to be quick check time */
92 PBogus, /* 15 -- prefetch is now special-cased; see pioctl code! */
93 PBogus, /* 16 -- used to be testing code */
94 PNoop, /* 17 -- used to be enable group */
95 PNoop, /* 18 -- used to be disable group */
96 PBogus, /* 19 -- used to be list group */
98 PUnlog, /* 21 -- unlog *is* unpag in this system */
99 PGetFID, /* 22 -- get file ID */
100 PBogus, /* 23 -- used to be waitforever */
101 PSetCacheSize, /* 24 */
102 PRemoveCallBack, /* 25 -- flush only the callback */
105 PRemoveMount, /* 28 -- delete mount point */
106 PNewStatMount, /* 29 -- new style mount point stat */
107 PGetFileCell, /* 30 -- get cell name for input file */
108 PGetWSCell, /* 31 -- get cell name for workstation */
109 PMariner, /* 32 - set/get mariner host */
110 PGetUserCell, /* 33 -- get cell name for user */
111 PVenusLogging, /* 34 -- Enable/Disable logging */
112 PGetCellStatus, /* 35 */
113 PSetCellStatus, /* 36 */
114 PFlushVolumeData, /* 37 -- flush all data from a volume */
115 PSetSysName, /* 38 - Set system name */
116 PExportAfs, /* 39 - Export Afs to remote nfs clients */
117 PGetCacheSize, /* 40 - get cache size and usage */
118 PGetVnodeXStatus, /* 41 - get vcache's special status */
119 PSetSPrefs33, /* 42 - Set CM Server preferences... */
120 PGetSPrefs, /* 43 - Get CM Server preferences... */
121 PGag, /* 44 - turn off/on all CM messages */
122 PTwiddleRx, /* 45 - adjust some RX params */
123 PSetSPrefs, /* 46 - Set CM Server preferences... */
124 PStoreBehind, /* 47 - set degree of store behind to be done */
125 PGCPAGs, /* 48 - disable automatic pag gc-ing */
126 PGetInitParams, /* 49 - get initial cm params */
127 PGetCPrefs, /* 50 - get client interface addresses */
128 PSetCPrefs, /* 51 - set client interface addresses */
129 PFlushMount, /* 52 - flush mount symlink data */
130 PRxStatProc, /* 53 - control process RX statistics */
131 PRxStatPeer, /* 54 - control peer RX statistics */
132 PGetRxkcrypt, /* 55 -- Get rxkad encryption flag */
133 PSetRxkcrypt, /* 56 -- Set rxkad encryption flag */
134 PBogus, /* 57 -- arla: set file prio */
135 PBogus, /* 58 -- arla: fallback getfh */
136 PBogus, /* 59 -- arla: fallback fhopen */
137 PBogus, /* 60 -- arla: controls xfsdebug */
138 PBogus, /* 61 -- arla: controls arla debug */
139 PBogus, /* 62 -- arla: debug interface */
140 PBogus, /* 63 -- arla: print xfs status */
141 PBogus, /* 64 -- arla: force cache check */
142 PBogus, /* 65 -- arla: break callback */
143 PPrefetchFromTape, /* 66 -- MR-AFS: prefetch file from tape */
144 PResidencyCmd, /* 67 -- MR-AFS: generic commnd interface */
145 PBogus, /* 68 -- arla: fetch stats */
148 static int (*(CpioctlSw[]))() = {
150 PNewAlias, /* 1 -- create new cell alias */
151 PListAliases, /* 2 -- list cell aliases */
154 #define PSetClientContext 99 /* Special pioctl to setup caller's creds */
155 int afs_nobody = NFS_NOBODY;
158 afs_ioctl32_to_afs_ioctl(const struct afs_ioctl32 *src, struct afs_ioctl *dst)
160 dst->in = (char *)(unsigned long)src->in;
161 dst->out = (char *)(unsigned long)src->out;
162 dst->in_size = src->in_size;
163 dst->out_size = src->out_size;
167 * If you need to change copyin_afs_ioctl(), you may also need to change
172 copyin_afs_ioctl(caddr_t cmarg, struct afs_ioctl *dst)
176 #if defined(AFS_HPUX_64BIT_ENV)
177 struct afs_ioctl32 dst32;
179 if (is_32bit(u.u_procp)) /* is_32bit() in proc_iface.h */
181 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
183 afs_ioctl32_to_afs_ioctl(&dst32, dst);
186 #endif /* defined(AFS_HPUX_64BIT_ENV) */
188 #if defined(AFS_SUN57_64BIT_ENV)
189 struct afs_ioctl32 dst32;
191 if (get_udatamodel() == DATAMODEL_ILP32) {
192 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
194 afs_ioctl32_to_afs_ioctl(&dst32, dst);
197 #endif /* defined(AFS_SUN57_64BIT_ENV) */
199 #if defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64)
200 struct afs_ioctl32 dst32;
202 if (!ABI_IS_64BIT(get_current_abi()))
204 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
206 afs_ioctl32_to_afs_ioctl(&dst32, dst);
209 #endif /* defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64) */
211 #if defined(AFS_LINUX_64BIT_KERNEL) && !defined(AFS_ALPHA_LINUX20_ENV) && !defined(AFS_IA64_LINUX20_ENV)
212 struct afs_ioctl32 dst32;
214 #ifdef AFS_SPARC64_LINUX24_ENV
215 if (current->thread.flags & SPARC_FLAG_32BIT)
216 #elif AFS_SPARC64_LINUX20_ENV
217 if (current->tss.flags & SPARC_FLAG_32BIT)
219 #error Not done for this linux type
220 #endif /* AFS_SPARC64_LINUX20_ENV */
222 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
224 afs_ioctl32_to_afs_ioctl(&dst32, dst);
227 #endif /* defined(AFS_LINUX_64BIT_KERNEL) */
229 AFS_COPYIN(cmarg, (caddr_t) dst, sizeof *dst, code);
233 HandleIoctl(avc, acom, adata)
234 register struct vcache *avc;
235 register afs_int32 acom;
236 struct afs_ioctl *adata; {
237 register afs_int32 code;
240 AFS_STATCNT(HandleIoctl);
242 switch(acom & 0xff) {
244 avc->states |= CSafeStore;
248 /* case 2 used to be abort store, but this is no longer provided,
249 since it is impossible to implement under normal Unix.
253 /* return the name of the cell this file is open on */
254 register struct cell *tcell;
255 register afs_int32 i;
257 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
259 i = strlen(tcell->cellName) + 1; /* bytes to copy out */
261 if (i > adata->out_size) {
262 /* 0 means we're not interested in the output */
263 if (adata->out_size != 0) code = EFAULT;
267 AFS_COPYOUT(tcell->cellName, adata->out, i, code);
269 afs_PutCell(tcell, READ_LOCK);
275 case 49: /* VIOC_GETINITPARAMS */
276 if (adata->out_size < sizeof(struct cm_initparams)) {
280 AFS_COPYOUT(&cm_initParams, adata->out,
281 sizeof(struct cm_initparams), code);
290 return code; /* so far, none implemented */
295 /* For aix we don't temporarily bypass ioctl(2) but rather do our
296 * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
297 * is now called from afs_gn_ioctl.
299 afs_ioctl(tvc, cmd, arg)
304 struct afs_ioctl data;
307 AFS_STATCNT(afs_ioctl);
308 if (((cmd >> 8) & 0xff) == 'V') {
309 /* This is a VICEIOCTL call */
310 AFS_COPYIN(arg, (caddr_t) &data, sizeof(data), error);
313 error = HandleIoctl(tvc, cmd, &data);
316 /* No-op call; just return. */
320 #endif /* AFS_AIX_ENV */
322 #if defined(AFS_SGI_ENV)
323 afs_ioctl(OSI_VN_DECL(tvc), int cmd, void * arg, int flag, cred_t *cr, rval_t *rvalp
329 struct afs_ioctl data;
335 AFS_STATCNT(afs_ioctl);
336 if (((cmd >> 8) & 0xff) == 'V') {
337 /* This is a VICEIOCTL call */
338 error = copyin_afs_ioctl(arg, &data);
341 locked = ISAFS_GLOCK();
344 error = HandleIoctl(tvc, cmd, &data);
349 /* No-op call; just return. */
353 #endif /* AFS_SGI_ENV */
356 /* unlike most calls here, this one uses u.u_error to return error conditions,
357 since this is really an intercepted chapter 2 call, rather than a vnode
360 /* AFS_HPUX102 and up uses VNODE ioctl instead */
361 #ifndef AFS_HPUX102_ENV
362 #if !defined(AFS_SGI_ENV)
364 kioctl(fdes, com, arg, ext)
371 } u_uap, *uap = &u_uap;
375 struct afs_ioctl_sys {
381 afs_xioctl (uap, rvp)
382 struct afs_ioctl_sys *uap;
387 afs_xioctl (p, args, retval)
396 } *uap = (struct a *)args;
397 #else /* AFS_OSF_ENV */
398 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
404 afs_xioctl(p, uap, retval)
406 register struct ioctl_args *uap;
410 #ifdef AFS_LINUX22_ENV
411 struct afs_ioctl_sys {
415 asmlinkage int afs_xioctl(struct inode *ip, struct file *fp,
416 unsigned int com, unsigned long arg)
418 struct afs_ioctl_sys ua, *uap = &ua;
426 } *uap = (struct a *)u.u_ap;
427 #endif /* AFS_LINUX22_ENV */
428 #endif /* AFS_DARWIN_ENV || AFS_FBSD_ENV */
429 #endif /* AFS_OSF_ENV */
430 #endif /* AFS_SUN5_ENV */
432 #ifndef AFS_LINUX22_ENV
433 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
436 register struct file *fd;
439 #if defined(AFS_FBSD_ENV)
440 register struct filedesc *fdp;
442 register struct vcache *tvc;
443 register int ioctlDone = 0, code = 0;
445 AFS_STATCNT(afs_xioctl);
446 #if defined(AFS_FBSD_ENV)
448 if ((u_int)uap->fd >= fdp->fd_nfiles ||
449 (fd = fdp->fd_ofiles[uap->fd]) == NULL)
451 if ((fd->f_flag & (FREAD | FWRITE)) == 0)
454 #if defined(AFS_DARWIN_ENV)
455 if ((code=fdgetf(p, uap->fd, &fd)))
458 #ifdef AFS_LINUX22_ENV
466 if (setuerror(getf(uap->fd, &fd))) {
472 if (code = getf(&fd, uap->fd, FILE_FLAGS_NULL, &u.u_file_state))
474 #else /* AFS_OSF_ENV */
476 #if defined(AFS_SUN57_ENV)
478 if (!fd) return(EBADF);
479 #elif defined(AFS_SUN54_ENV)
481 if (!fd) return(EBADF);
483 if (code = getf(uap->fd, &fd)) {
496 /* first determine whether this is any sort of vnode */
497 #ifdef AFS_LINUX22_ENV
502 if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
504 if (fd->f_type == DTYPE_VNODE) {
506 /* good, this is a vnode; next see if it is an AFS vnode */
507 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
508 tvc = VTOAFS(fd->f_vnode); /* valid, given a vnode */
510 tvc = VTOAFS((struct vnode*)fd->f_data); /* valid, given a vnode */
512 #endif /* AFS_LINUX22_ENV */
513 if (tvc && IsAfsVnode(AFSTOV(tvc))) {
515 tvc = VTOAFS(afs_gntovn((struct gnode *) tvc));
516 if (!tvc) { /* shouldn't happen with held gnodes */
521 /* This is an AFS vnode */
522 if (((uap->com >> 8) & 0xff) == 'V') {
523 register struct afs_ioctl *datap;
525 datap = (struct afs_ioctl *) osi_AllocSmallSpace(AFS_SMALLOCSIZ);
526 AFS_COPYIN((char *)uap->arg, (caddr_t) datap, sizeof (struct afs_ioctl), code);
528 osi_FreeSmallSpace(datap);
530 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
533 #if defined(AFS_SUN5_ENV)
548 #else /* AFS_OSF_ENV */
552 #ifdef AFS_LINUX22_ENV
562 code = HandleIoctl(tvc, uap->com, datap);
563 osi_FreeSmallSpace(datap);
577 #if defined(AFS_LINUX22_ENV)
587 code = okioctl(fdes, com, arg, ext);
591 okioctl(fdes, com, arg, ext);
593 #if defined(AFS_SUN5_ENV)
594 #if defined(AFS_SUN57_ENV)
596 #elif defined(AFS_SUN54_ENV)
601 code = ioctl(uap, rvp);
603 #if defined(AFS_FBSD_ENV)
604 return ioctl(p, uap);
606 #if defined(AFS_DARWIN_ENV)
607 return ioctl(p, uap, retval);
610 code = ioctl(p, args, retval);
617 #else /* AFS_OSF_ENV */
618 #ifndef AFS_LINUX22_ENV
637 #ifdef AFS_LINUX22_ENV
640 #if !defined(AFS_OSF_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
643 #if defined(AFS_AIX32_ENV) && !defined(AFS_AIX41_ENV)
644 return (getuerror() ? -1 : u.u_ioctlrv);
646 return getuerror() ? -1 : 0;
649 #endif /* AFS_LINUX22_ENV */
650 #endif /* AFS_SUN5_ENV */
651 #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
655 #endif /* AFS_SGI_ENV */
656 #endif /* AFS_HPUX102_ENV */
658 #if defined(AFS_SGI_ENV)
659 /* "pioctl" system call entry point; just pass argument to the parameterized
668 afs_pioctl(struct pioctlargs *uap, rval_t *rvp)
672 AFS_STATCNT(afs_pioctl);
674 code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
682 #endif /* AFS_SGI_ENV */
685 afs_pioctl(p, args, retval)
695 } *uap = (struct a *) args;
697 AFS_STATCNT(afs_pioctl);
698 return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow));
701 extern struct mount *afs_globalVFS;
702 #else /* AFS_OSF_ENV */
703 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
704 afs_pioctl(p, args, retval)
714 } *uap = (struct a *) args;
716 AFS_STATCNT(afs_pioctl);
717 return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow, p->p_cred->pc_ucred));
720 extern struct mount *afs_globalVFS;
721 #else /* AFS_OSF_ENV */
722 extern struct vfs *afs_globalVFS;
726 /* macro to avoid adding any more #ifdef's to pioctl code. */
727 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
728 #define PIOCTL_FREE_CRED() crfree(credp)
730 #define PIOCTL_FREE_CRED()
734 afs_syscall_pioctl(path, com, cmarg, follow, rvp, credp)
736 struct AFS_UCRED *credp;
738 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
739 afs_syscall_pioctl(path, com, cmarg, follow, credp)
740 struct AFS_UCRED *credp;
742 afs_syscall_pioctl(path, com, cmarg, follow)
750 struct afs_ioctl data;
751 struct AFS_UCRED *tmpcred, *foreigncreds = 0;
752 register afs_int32 code = 0;
758 struct ucred *credp = crref(); /* don't free until done! */
760 #ifdef AFS_LINUX22_ENV
761 cred_t *credp = crref(); /* don't free until done! */
765 AFS_STATCNT(afs_syscall_pioctl);
766 if (follow) follow = 1; /* compat. with old venus */
767 code = copyin_afs_ioctl(cmarg, &data);
770 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
777 if ((com & 0xff) == PSetClientContext) {
778 #if defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
779 return EINVAL; /* Not handling these yet. */
781 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
782 code = HandleClientContext(&data, &com, &foreigncreds, credp);
784 #if defined(AFS_HPUX101_ENV)
785 code=HandleClientContext(&data, &com, &foreigncreds, p_cred(u.u_procp));
788 code = HandleClientContext(&data, &com, &foreigncreds, OSI_GET_CURRENT_CRED());
790 code = HandleClientContext(&data, &com, &foreigncreds, u.u_cred);
791 #endif /* AFS_SGI_ENV */
797 crfree(foreigncreds);
800 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
803 return (setuerror(code), code);
807 #if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
810 * We could have done without temporary setting the u.u_cred below
811 * (foreigncreds could be passed as param the pioctl modules)
812 * but calls such as afs_osi_suser() doesn't allow that since it
813 * references u.u_cred directly. We could, of course, do something
814 * like afs_osi_suser(cred) which, I think, is better since it
815 * generalizes and supports multi cred environments...
819 credp = foreigncreds;
822 tmpcred = crref(); /* XXX */
825 #if defined(AFS_HPUX101_ENV)
826 tmpcred = p_cred(u.u_procp);
827 set_p_cred(u.u_procp, foreigncreds);
830 tmpcred = OSI_GET_CURRENT_CRED();
831 OSI_SET_CURRENT_CRED(foreigncreds);
834 u.u_cred = foreigncreds;
835 #endif /* AFS_SGI64_ENV */
836 #endif /* AFS_HPUX101_ENV */
841 if ((com & 0xff) == 15) {
842 /* special case prefetch so entire pathname eval occurs in helper process.
843 otherwise, the pioctl call is essentially useless */
844 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
845 code = Prefetch(path, &data, follow,
846 foreigncreds ? foreigncreds : credp);
848 #if defined(AFS_HPUX101_ENV)
849 code = Prefetch(path, &data, follow, p_cred(u.u_procp));
852 code = Prefetch(path, &data, follow, OSI_GET_CURRENT_CRED());
854 code = Prefetch(path, &data, follow, u.u_cred);
855 #endif /* AFS_SGI64_ENV */
856 #endif /* AFS_HPUX101_ENV */
858 #if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
861 crset(tmpcred); /* restore original credentials */
863 #if defined(AFS_HPUX101_ENV)
864 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
868 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
870 u.u_cred = tmpcred; /* restore original credentials */
873 #endif /* AFS_HPUX101_ENV */
874 crfree(foreigncreds);
877 #endif /* AFS_LINUX22_ENV */
879 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
882 return (setuerror(code), code);
888 code = lookupname(path, USR, follow, NULL, &vp,
889 foreigncreds ? foreigncreds : credp);
891 #ifdef AFS_LINUX22_ENV
892 code = gop_lookupname(path, AFS_UIOUSER, follow, (struct vnode **) 0, &dp);
894 vp = (struct vnode *)dp->d_inode;
896 code = gop_lookupname(path, AFS_UIOUSER, follow, (struct vnode **) 0, &vp);
897 #endif /* AFS_LINUX22_ENV */
898 #endif /* AFS_AIX41_ENV */
901 #if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
904 crset(tmpcred); /* restore original credentials */
906 #if defined(AFS_HPUX101_ENV)
907 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
909 #if !defined(AFS_SUN5_ENV)
911 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
913 u.u_cred = tmpcred; /* restore original credentials */
914 #endif /* AFS_SGI64_ENV */
916 #endif /* AFS_HPUX101_ENV */
917 crfree(foreigncreds);
920 #endif /* AFS_LINUX22_ENV */
922 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
925 return(setuerror(code), code);
929 else vp = (struct vnode *) 0;
931 /* now make the call if we were passed no file, or were passed an AFS file */
932 if (!vp || IsAfsVnode(vp)) {
934 /* Ultrix 4.0: can't get vcache entry unless we've got an AFS gnode.
935 * So, we must test in this part of the code. Also, must arrange to
936 * GRELE the original gnode pointer when we're done, since in Ultrix 4.0,
937 * we hold gnodes, whose references hold our vcache entries.
940 gp = vp; /* remember for "put" */
941 vp = (struct vnode *) afs_gntovn(vp); /* get vcache from gp */
943 else gp = (struct vnode *) 0;
946 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
950 struct ucred *cred1, *cred2;
953 cred1 = cred2 = foreigncreds;
955 cred1 = cred2 = credp;
957 code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
958 if (cred1 != cred2) {
959 /* something changed the creds */
964 #if defined(AFS_HPUX101_ENV)
966 struct ucred *cred = p_cred(u.u_procp);
967 code = afs_HandlePioctl(vp, com, &data, follow, &cred);
973 credp = OSI_GET_CURRENT_CRED();
974 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
977 #if defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
978 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
980 code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
982 #endif /* AFS_SGI_ENV */
983 #endif /* AFS_HPUX101_ENV */
984 #endif /* AFS_AIX41_ENV */
985 #endif /* AFS_SUN5_ENV */
987 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
988 code = EINVAL; /* not in /afs */
995 vp = (struct vnode *) 0;
1000 #if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
1002 #ifdef AFS_AIX41_ENV
1005 #if defined(AFS_HPUX101_ENV)
1006 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
1008 #ifndef AFS_SUN5_ENV
1010 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
1012 u.u_cred = tmpcred; /* restore original credentials */
1013 #endif /* ASF_SGI64_ENV */
1015 #endif /* AFS_HPUX101_ENV */
1016 crfree(foreigncreds);
1019 #endif /* AFS_LINUX22_ENV */
1021 #ifdef AFS_LINUX22_ENV
1024 AFS_RELE(vp); /* put vnode back */
1028 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1033 return (getuerror());
1038 afs_HandlePioctl(avc, acom, ablob, afollow, acred)
1041 struct AFS_UCRED **acred;
1042 register struct afs_ioctl *ablob;
1045 struct vrequest treq;
1046 register afs_int32 code;
1047 register afs_int32 function, device;
1048 afs_int32 inSize, outSize;
1049 char *inData, *outData;
1050 int (*(*pioctlSw))();
1052 struct afs_fakestat_state fakestate;
1054 afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
1055 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
1056 AFS_STATCNT(HandlePioctl);
1057 if (code = afs_InitReq(&treq, *acred)) return code;
1058 afs_InitFakeStat(&fakestate);
1060 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
1062 afs_PutFakeStat(&fakestate);
1066 device = (acom & 0xff00) >> 8;
1068 case 'V': /* Original pioctl's */
1069 pioctlSw = VpioctlSw;
1070 pioctlSwSize = sizeof(VpioctlSw);
1072 case 'C': /* Coordinated/common pioctl's */
1073 pioctlSw = CpioctlSw;
1074 pioctlSwSize = sizeof(CpioctlSw);
1077 afs_PutFakeStat(&fakestate);
1080 function = acom & 0xff;
1081 if (function >= (pioctlSwSize / sizeof(char *))) {
1082 afs_PutFakeStat(&fakestate);
1083 return EINVAL; /* out of range */
1085 inSize = ablob->in_size;
1086 if (inSize >= PIGGYSIZE) return E2BIG;
1087 inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1089 AFS_COPYIN(ablob->in, inData, inSize, code);
1093 osi_FreeLargeSpace(inData);
1094 afs_PutFakeStat(&fakestate);
1097 outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1099 if (function == 3 && device == 'V') /* PSetTokens */
1100 code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, acred);
1102 code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, *acred);
1103 osi_FreeLargeSpace(inData);
1104 if (code == 0 && ablob->out_size > 0) {
1105 if (outSize > ablob->out_size) outSize = ablob->out_size;
1106 if (outSize >= PIGGYSIZE) code = E2BIG;
1108 AFS_COPYOUT(outData, ablob->out, outSize, code);
1110 osi_FreeLargeSpace(outData);
1111 afs_PutFakeStat(&fakestate);
1112 return afs_CheckCode(code, &treq, 41);
1115 static PGetFID(avc, afun, areq, ain, aout, ainSize, aoutSize)
1118 struct vrequest *areq;
1121 afs_int32 *aoutSize; /* set this */ {
1122 register afs_int32 code;
1124 AFS_STATCNT(PGetFID);
1125 if (!avc) return EINVAL;
1126 memcpy(aout, (char *)&avc->fid, sizeof(struct VenusFid));
1127 *aoutSize = sizeof(struct VenusFid);
1131 static PSetAcl(avc, afun, areq, ain, aout, ainSize, aoutSize)
1134 struct vrequest *areq;
1137 afs_int32 *aoutSize; /* set this */ {
1138 register afs_int32 code;
1140 struct AFSOpaque acl;
1141 struct AFSVolSync tsync;
1142 struct AFSFetchStatus OutStatus;
1145 AFS_STATCNT(PSetAcl);
1148 if ((acl.AFSOpaque_len = strlen(ain)+1) > 1000)
1151 acl.AFSOpaque_val = ain;
1153 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1155 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1157 code = RXAFS_StoreACL(tconn->id, (struct AFSFid *) &avc->fid.Fid,
1158 &acl, &OutStatus, &tsync);
1164 (afs_Analyze(tconn, code, &avc->fid, areq,
1165 AFS_STATS_FS_RPCIDX_STOREACL, SHARED_LOCK, (struct cell *)0));
1167 /* now we've forgotten all of the access info */
1168 ObtainWriteLock(&afs_xcbhash, 455);
1170 afs_DequeueCallback(avc);
1171 avc->states &= ~(CStatd | CUnique);
1172 ReleaseWriteLock(&afs_xcbhash);
1173 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1174 osi_dnlc_purgedp(avc);
1178 int afs_defaultAsynchrony = 0;
1180 static PStoreBehind(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1183 struct vrequest *areq;
1186 afs_int32 *aoutSize; /* set this */
1187 struct AFS_UCRED *acred;
1190 struct sbstruct *sbr;
1192 sbr = (struct sbstruct *)ain;
1193 if (sbr->sb_default != -1) {
1194 if (afs_osi_suser(acred))
1195 afs_defaultAsynchrony = sbr->sb_default;
1199 if (avc && (sbr->sb_thisfile != -1)) {
1200 if (afs_AccessOK(avc, PRSFS_WRITE | PRSFS_ADMINISTER,
1201 areq, DONT_CHECK_MODE_BITS))
1202 avc->asynchrony = sbr->sb_thisfile;
1206 *aoutSize = sizeof(struct sbstruct);
1207 sbr = (struct sbstruct *)aout;
1208 sbr->sb_default = afs_defaultAsynchrony;
1210 sbr->sb_thisfile = avc->asynchrony;
1216 static PGCPAGs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1219 struct vrequest *areq;
1222 afs_int32 *aoutSize; /* set this */
1223 struct AFS_UCRED *acred;
1225 if (!afs_osi_suser(acred)) {
1228 afs_gcpags = AFS_GCPAGS_USERDISABLED;
1232 static PGetAcl(avc, afun, areq, ain, aout, ainSize, aoutSize)
1235 struct vrequest *areq;
1238 afs_int32 *aoutSize; /* set this */ {
1239 struct AFSOpaque acl;
1240 struct AFSVolSync tsync;
1241 struct AFSFetchStatus OutStatus;
1247 AFS_STATCNT(PGetAcl);
1248 if (!avc) return EINVAL;
1249 Fid.Volume = avc->fid.Fid.Volume;
1250 Fid.Vnode = avc->fid.Fid.Vnode;
1251 Fid.Unique = avc->fid.Fid.Unique;
1252 if (avc->states & CForeign) {
1254 * For a dfs xlator acl we have a special hack so that the
1255 * xlator will distinguish which type of acl will return. So
1256 * we currently use the top 2-bytes (vals 0-4) to tell which
1257 * type of acl to bring back. Horrible hack but this will
1258 * cause the least number of changes to code size and interfaces.
1260 if (Fid.Vnode & 0xc0000000)
1262 Fid.Vnode |= (ainSize << 30);
1264 acl.AFSOpaque_val = aout;
1266 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1269 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1271 code = RXAFS_FetchACL(tconn->id, &Fid,
1272 &acl, &OutStatus, &tsync);
1278 (afs_Analyze(tconn, code, &avc->fid, areq,
1279 AFS_STATS_FS_RPCIDX_FETCHACL,
1280 SHARED_LOCK, (struct cell *)0));
1283 *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1294 AFS_STATCNT(PBogus);
1298 static PGetFileCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1301 struct vrequest *areq;
1305 afs_int32 *aoutSize; /* set this */ {
1306 register struct cell *tcell;
1308 AFS_STATCNT(PGetFileCell);
1309 if (!avc) return EINVAL;
1310 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
1311 if (!tcell) return ESRCH;
1312 strcpy(aout, tcell->cellName);
1313 afs_PutCell(tcell, READ_LOCK);
1314 *aoutSize = strlen(aout) + 1;
1318 static PGetWSCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1321 struct vrequest *areq;
1325 afs_int32 *aoutSize; /* set this */ {
1326 register struct cell *tcell=0, *cellOne=0;
1327 register struct afs_q *cq, *tq;
1329 AFS_STATCNT(PGetWSCell);
1330 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1331 return EIO; /* Inappropriate ioctl for device */
1333 ObtainReadLock(&afs_xcell);
1334 cellOne = (struct cell *) 0;
1336 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
1337 tcell = QTOC(cq); tq = QNext(cq);
1338 if (tcell->states & CPrimary) break;
1339 if (tcell->cell == 1) cellOne = tcell;
1342 ReleaseReadLock(&afs_xcell);
1343 if (!tcell) { /* no primary cell, use cell #1 */
1344 if (!cellOne) return ESRCH;
1347 strcpy(aout, tcell->cellName);
1348 *aoutSize = strlen(aout) + 1;
1352 static PGetUserCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1355 struct vrequest *areq;
1359 afs_int32 *aoutSize; /* set this */ {
1360 register afs_int32 i;
1361 register struct unixuser *tu;
1362 register struct cell *tcell;
1364 AFS_STATCNT(PGetUserCell);
1365 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1366 return EIO; /* Inappropriate ioctl for device */
1368 /* return the cell name of the primary cell for this user */
1369 i = UHash(areq->uid);
1370 ObtainWriteLock(&afs_xuser,224);
1371 for(tu = afs_users[i]; tu; tu = tu->next) {
1372 if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1374 ReleaseWriteLock(&afs_xuser);
1379 tcell = afs_GetCell(tu->cell, READ_LOCK);
1380 afs_PutUser(tu, WRITE_LOCK);
1381 if (!tcell) return ESRCH;
1383 strcpy(aout, tcell->cellName);
1384 afs_PutCell(tcell, READ_LOCK);
1385 *aoutSize = strlen(aout)+1; /* 1 for the null */
1389 ReleaseWriteLock(&afs_xuser);
1396 static PSetTokens(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1399 struct vrequest *areq;
1403 afs_int32 *aoutSize; /* set this */
1404 struct AFS_UCRED **acred;
1407 register struct unixuser *tu;
1408 struct ClearToken clear;
1409 register struct cell *tcell;
1412 struct vrequest treq;
1413 afs_int32 flag, set_parent_pag = 0;
1415 AFS_STATCNT(PSetTokens);
1416 if (!afs_resourceinit_flag) {
1419 memcpy((char *)&i, ain, sizeof(afs_int32));
1420 ain += sizeof(afs_int32);
1421 stp = ain; /* remember where the ticket is */
1422 if (i < 0 || i > 2000) return EINVAL; /* malloc may fail */
1424 ain += i; /* skip over ticket */
1425 memcpy((char *)&i, ain, sizeof(afs_int32));
1426 ain += sizeof(afs_int32);
1427 if (i != sizeof(struct ClearToken)) {
1430 memcpy((char *)&clear, ain, sizeof(struct ClearToken));
1431 if (clear.AuthHandle == -1) clear.AuthHandle = 999; /* more rxvab compat stuff */
1432 ain += sizeof(struct ClearToken);
1433 if (ainSize != 2*sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1434 /* still stuff left? we've got primary flag and cell name. Set these */
1435 memcpy((char *)&flag, ain, sizeof(afs_int32)); /* primary id flag */
1436 ain += sizeof(afs_int32); /* skip id field */
1437 /* rest is cell name, look it up */
1438 /* some versions of gcc appear to need != 0 in order to get this right */
1439 if (flag & 0x8000 != 0) { /* XXX Use Constant XXX */
1443 tcell = afs_GetCellByName(ain, READ_LOCK);
1452 /* default to cell 1, primary id */
1453 flag = 1; /* primary id */
1454 i = 1; /* cell number */
1455 tcell = afs_GetCell(1, READ_LOCK);
1456 if (!tcell) goto nocell;
1458 afs_PutCell(tcell, READ_LOCK);
1459 if (set_parent_pag) {
1461 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1462 #if defined(AFS_DARWIN_ENV)
1463 struct proc *p=current_proc(); /* XXX */
1465 struct proc *p=curproc; /* XXX */
1467 uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1468 p->p_pid, p->p_comm);
1469 if (!setpag(p, acred, -1, &pag, 1)) {
1472 if (!setpag(u.u_procp, acred, -1, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
1474 if (!setpag(acred, -1, &pag, 1)) {
1477 afs_InitReq(&treq, *acred);
1481 /* now we just set the tokens */
1482 tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1483 tu->vid = clear.ViceId;
1484 if (tu->stp != (char *) 0) {
1485 afs_osi_Free(tu->stp, tu->stLen);
1487 tu->stp = (char *) afs_osi_Alloc(stLen);
1489 memcpy(tu->stp, stp, stLen);
1492 afs_stats_cmfullperf.authent.TicketUpdates++;
1493 afs_ComputePAGStats();
1494 #endif /* AFS_NOSTATS */
1495 tu->states |= UHasTokens;
1496 tu->states &= ~UTokensBad;
1497 afs_SetPrimary(tu, flag);
1498 tu->tokenTime =osi_Time();
1499 afs_ResetUserConns(tu);
1500 afs_PutUser(tu, WRITE_LOCK);
1515 static PGetVolumeStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
1518 struct vrequest *areq;
1521 afs_int32 *aoutSize; /* set this */ {
1523 char offLineMsg[256];
1525 register struct conn *tc;
1526 register afs_int32 code;
1527 struct VolumeStatus volstat;
1529 char *Name, *OfflineMsg, *MOTD;
1532 AFS_STATCNT(PGetVolumeStatus);
1533 if (!avc) return EINVAL;
1535 OfflineMsg = offLineMsg;
1538 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1540 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1542 code = RXAFS_GetVolumeStatus(tc->id, avc->fid.Fid.Volume, &volstat,
1543 &Name, &OfflineMsg, &MOTD);
1549 (afs_Analyze(tc, code, &avc->fid, areq,
1550 AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1551 SHARED_LOCK, (struct cell *)0));
1553 if (code) return code;
1554 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1556 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1557 cp += sizeof(VolumeStatus);
1558 strcpy(cp, volName);
1559 cp += strlen(volName)+1;
1560 strcpy(cp, offLineMsg);
1561 cp += strlen(offLineMsg)+1;
1563 cp += strlen(motd)+1;
1564 *aoutSize = (cp - aout);
1568 static PSetVolumeStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
1571 struct vrequest *areq;
1574 afs_int32 *aoutSize; /* set this */ {
1576 char offLineMsg[256];
1578 register struct conn *tc;
1579 register afs_int32 code;
1580 struct AFSFetchVolumeStatus volstat;
1581 struct AFSStoreVolumeStatus storeStat;
1582 register struct volume *tvp;
1586 AFS_STATCNT(PSetVolumeStatus);
1587 if (!avc) return EINVAL;
1589 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
1591 if (tvp->states & (VRO | VBackup)) {
1592 afs_PutVolume(tvp, READ_LOCK);
1595 afs_PutVolume(tvp, READ_LOCK);
1598 /* Copy the junk out, using cp as a roving pointer. */
1600 memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
1601 cp += sizeof(AFSFetchVolumeStatus);
1602 if (strlen(cp) >= sizeof(volName))
1604 strcpy(volName, cp);
1605 cp += strlen(volName)+1;
1606 if (strlen(cp) >= sizeof(offLineMsg))
1608 strcpy(offLineMsg, cp);
1609 cp += strlen(offLineMsg)+1;
1610 if (strlen(cp) >= sizeof(motd))
1614 if (volstat.MinQuota != -1) {
1615 storeStat.MinQuota = volstat.MinQuota;
1616 storeStat.Mask |= AFS_SETMINQUOTA;
1618 if (volstat.MaxQuota != -1) {
1619 storeStat.MaxQuota = volstat.MaxQuota;
1620 storeStat.Mask |= AFS_SETMAXQUOTA;
1623 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1625 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1627 code = RXAFS_SetVolumeStatus(tc->id, avc->fid.Fid.Volume,
1628 &storeStat, volName, offLineMsg, motd);
1634 (afs_Analyze(tc, code, &avc->fid, areq,
1635 AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1636 SHARED_LOCK, (struct cell *)0));
1638 if (code) return code;
1639 /* we are sending parms back to make compat. with prev system. should
1640 change interface later to not ask for current status, just set new status */
1642 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1643 cp += sizeof(VolumeStatus);
1644 strcpy(cp, volName);
1645 cp += strlen(volName)+1;
1646 strcpy(cp, offLineMsg);
1647 cp += strlen(offLineMsg)+1;
1649 cp += strlen(motd)+1;
1650 *aoutSize = cp - aout;
1654 static PFlush(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1655 register struct vcache *avc;
1657 struct vrequest *areq;
1660 afs_int32 *aoutSize; /* set this */
1661 struct AFS_UCRED *acred;
1664 AFS_STATCNT(PFlush);
1665 if (!avc) return EINVAL;
1666 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1667 afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
1669 ObtainWriteLock(&avc->lock,225);
1670 ObtainWriteLock(&afs_xcbhash, 456);
1671 afs_DequeueCallback(avc);
1672 avc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
1673 ReleaseWriteLock(&afs_xcbhash);
1674 /* now find the disk cache entries */
1675 afs_TryToSmush(avc, acred, 1);
1676 osi_dnlc_purgedp(avc);
1677 afs_symhint_inval(avc);
1678 if (avc->linkData && !(avc->states & CCore)) {
1679 afs_osi_Free(avc->linkData, strlen(avc->linkData)+1);
1680 avc->linkData = (char *) 0;
1682 ReleaseWriteLock(&avc->lock);
1683 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1684 afs_BozonUnlock(&avc->pvnLock, avc);
1689 static PNewStatMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
1692 struct vrequest *areq;
1695 afs_int32 *aoutSize; /* set this */ {
1696 register afs_int32 code;
1697 register struct vcache *tvc;
1698 register struct dcache *tdc;
1699 struct VenusFid tfid;
1701 struct sysname_info sysState;
1702 afs_size_t offset, len;
1704 AFS_STATCNT(PNewStatMount);
1705 if (!avc) return EINVAL;
1706 code = afs_VerifyVCache(avc, areq);
1707 if (code) return code;
1708 if (vType(avc) != VDIR) {
1711 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
1712 if (!tdc) return ENOENT;
1713 Check_AtSys(avc, ain, &sysState, areq);
1714 ObtainReadLock(&tdc->lock);
1716 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
1717 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1718 ReleaseReadLock(&tdc->lock);
1719 afs_PutDCache(tdc); /* we're done with the data */
1720 bufp = sysState.name;
1724 tfid.Cell = avc->fid.Cell;
1725 tfid.Fid.Volume = avc->fid.Fid.Volume;
1726 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
1727 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
1729 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
1736 if (tvc->mvstat != 1) {
1737 afs_PutVCache(tvc, WRITE_LOCK);
1741 ObtainWriteLock(&tvc->lock,226);
1742 code = afs_HandleLink(tvc, areq);
1744 if (tvc->linkData) {
1745 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1748 /* we have the data */
1749 strcpy(aout, tvc->linkData);
1750 *aoutSize = strlen(tvc->linkData)+1;
1755 ReleaseWriteLock(&tvc->lock);
1756 afs_PutVCache(tvc, WRITE_LOCK);
1758 if (sysState.allocked) osi_FreeLargeSpace(bufp);
1762 static PGetTokens(avc, afun, areq, ain, aout, ainSize, aoutSize)
1765 struct vrequest *areq;
1768 afs_int32 *aoutSize; /* set this */ {
1769 register struct cell *tcell;
1770 register afs_int32 i;
1771 register struct unixuser *tu;
1776 AFS_STATCNT(PGetTokens);
1777 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1778 return EIO; /* Inappropriate ioctl for device */
1780 /* weird interface. If input parameter is present, it is an integer and
1781 we're supposed to return the parm'th tokens for this unix uid.
1782 If not present, we just return tokens for cell 1.
1783 If counter out of bounds, return EDOM.
1784 If no tokens for the particular cell, return ENOTCONN.
1785 Also, if this mysterious parm is present, we return, along with the
1786 tokens, the primary cell indicator (an afs_int32 0) and the cell name
1787 at the end, in that order.
1789 if (newStyle = (ainSize > 0)) {
1790 memcpy((char *)&iterator, ain, sizeof(afs_int32));
1792 i = UHash(areq->uid);
1793 ObtainReadLock(&afs_xuser);
1794 for(tu = afs_users[i]; tu; tu=tu->next) {
1796 if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1797 if (iterator-- == 0) break; /* are we done yet? */
1801 if (tu->uid == areq->uid && tu->cell == 1) break;
1806 * No need to hold a read lock on each user entry
1810 ReleaseReadLock(&afs_xuser);
1815 if (((tu->states & UHasTokens) == 0) || (tu->ct.EndTimestamp < osi_Time())) {
1816 tu->states |= (UTokensBad | UNeedsReset);
1817 afs_PutUser(tu, READ_LOCK);
1820 /* use iterator for temp */
1822 iterator = tu->stLen; /* for compat, we try to return 56 byte tix if they fit */
1823 if (iterator < 56) iterator = 56; /* # of bytes we're returning */
1824 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1825 cp += sizeof(afs_int32);
1826 memcpy(cp, tu->stp, tu->stLen); /* copy out st */
1828 iterator = sizeof(struct ClearToken);
1829 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1830 cp += sizeof(afs_int32);
1831 memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
1832 cp += sizeof(struct ClearToken);
1834 /* put out primary id and cell name, too */
1835 iterator = (tu->states & UPrimary ? 1 : 0);
1836 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1837 cp += sizeof(afs_int32);
1838 tcell = afs_GetCell(tu->cell, READ_LOCK);
1840 strcpy(cp, tcell->cellName);
1841 cp += strlen(tcell->cellName)+1;
1842 afs_PutCell(tcell, READ_LOCK);
1846 *aoutSize = cp - aout;
1847 afs_PutUser(tu, READ_LOCK);
1851 static PUnlog(avc, afun, areq, ain, aout, ainSize, aoutSize)
1854 struct vrequest *areq;
1857 afs_int32 *aoutSize; /* set this */ {
1858 register afs_int32 i;
1859 register struct unixuser *tu;
1861 AFS_STATCNT(PUnlog);
1862 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1863 return EIO; /* Inappropriate ioctl for device */
1865 i = UHash(areq->uid);
1866 ObtainWriteLock(&afs_xuser,227);
1867 for(tu=afs_users[i]; tu; tu=tu->next) {
1868 if (tu->uid == areq->uid) {
1870 tu->states &= ~UHasTokens;
1871 /* security is not having to say you're sorry */
1872 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
1874 ReleaseWriteLock(&afs_xuser);
1875 /* We have to drop the lock over the call to afs_ResetUserConns, since
1876 * it obtains the afs_xvcache lock. We could also keep the lock, and
1877 * modify ResetUserConns to take parm saying we obtained the lock
1878 * already, but that is overkill. By keeping the "tu" pointer
1879 * held over the released lock, we guarantee that we won't lose our
1880 * place, and that we'll pass over every user conn that existed when
1881 * we began this call.
1883 afs_ResetUserConns(tu);
1885 ObtainWriteLock(&afs_xuser,228);
1887 /* set the expire times to 0, causes
1888 * afs_GCUserData to remove this entry
1890 tu->ct.EndTimestamp = 0;
1892 #endif /* UKERNEL */
1895 ReleaseWriteLock(&afs_xuser);
1899 static PMariner(avc, afun, areq, ain, aout, ainSize, aoutSize)
1902 struct vrequest *areq;
1905 afs_int32 *aoutSize; /* set this */ {
1906 afs_int32 newHostAddr;
1907 afs_int32 oldHostAddr;
1909 AFS_STATCNT(PMariner);
1911 memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost, sizeof(afs_int32));
1913 oldHostAddr = 0xffffffff; /* disabled */
1915 memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
1916 if (newHostAddr == 0xffffffff) {
1917 /* disable mariner operations */
1920 else if (newHostAddr) {
1922 afs_marinerHost = newHostAddr;
1924 memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
1925 *aoutSize = sizeof(afs_int32);
1929 static PCheckServers(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1932 struct vrequest *areq;
1935 afs_int32 *aoutSize; /* set this */
1936 struct AFS_UCRED *acred;
1938 register char *cp = 0;
1940 register struct server *ts;
1941 afs_int32 temp, *lp = (afs_int32 *)ain, havecell=0;
1943 struct chservinfo *pcheck;
1945 AFS_STATCNT(PCheckServers);
1947 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1948 return EIO; /* Inappropriate ioctl for device */
1950 if (*lp == 0x12345678) { /* For afs3.3 version */
1951 pcheck=(struct chservinfo *)ain;
1952 if (pcheck->tinterval >= 0) {
1954 memcpy(cp, (char *)&PROBE_INTERVAL, sizeof(afs_int32));
1955 *aoutSize = sizeof(afs_int32);
1956 if (pcheck->tinterval > 0) {
1957 if (!afs_osi_suser(acred))
1959 PROBE_INTERVAL=pcheck->tinterval;
1965 temp=pcheck->tflags;
1966 cp = pcheck->tbuffer;
1967 } else { /* For pre afs3.3 versions */
1968 memcpy((char *)&temp, ain, sizeof(afs_int32));
1969 cp = ain+sizeof(afs_int32);
1970 if (ainSize > sizeof(afs_int32))
1975 * 1: fast check, don't contact servers.
1976 * 2: local cell only.
1979 /* have cell name, too */
1980 cellp = afs_GetCellByName(cp, READ_LOCK);
1981 if (!cellp) return ENOENT;
1983 else cellp = (struct cell *) 0;
1984 if (!cellp && (temp & 2)) {
1985 /* use local cell */
1986 cellp = afs_GetCell(1, READ_LOCK);
1988 if (!(temp & 1)) { /* if not fast, call server checker routine */
1989 afs_CheckServers(1, cellp); /* check down servers */
1990 afs_CheckServers(0, cellp); /* check up servers */
1992 /* now return the current down server list */
1994 ObtainReadLock(&afs_xserver);
1995 for(i=0;i<NSERVERS;i++) {
1996 for(ts = afs_servers[i]; ts; ts=ts->next) {
1997 if (cellp && ts->cell != cellp) continue; /* cell spec'd and wrong */
1998 if ((ts->flags & SRVR_ISDOWN) && ts->addr->sa_portal != ts->cell->vlport) {
1999 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2000 cp += sizeof(afs_int32);
2004 ReleaseReadLock(&afs_xserver);
2005 if (cellp) afs_PutCell(cellp, READ_LOCK);
2006 *aoutSize = cp - aout;
2010 static PCheckVolNames(avc, afun, areq, ain, aout, ainSize, aoutSize)
2013 struct vrequest *areq;
2016 afs_int32 *aoutSize; /* set this */ {
2017 AFS_STATCNT(PCheckVolNames);
2018 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2019 return EIO; /* Inappropriate ioctl for device */
2021 afs_CheckRootVolume();
2022 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE |
2023 AFS_VOLCHECK_EXPIRED |
2025 AFS_VOLCHECK_MTPTS);
2029 static PCheckAuth(avc, afun, areq, ain, aout, ainSize, aoutSize)
2032 struct vrequest *areq;
2035 afs_int32 *aoutSize; /* set this */ {
2039 struct unixuser *tu;
2041 extern afs_rwlock_t afs_xsrvAddr;
2043 AFS_STATCNT(PCheckAuth);
2044 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2045 return EIO; /* Inappropriate ioctl for device */
2048 tu = afs_GetUser(areq->uid, 1, READ_LOCK); /* check local cell authentication */
2049 if (!tu) retValue = EACCES;
2051 /* we have a user */
2052 ObtainReadLock(&afs_xsrvAddr);
2053 ObtainReadLock(&afs_xconn);
2055 /* any tokens set? */
2056 if ((tu->states & UHasTokens) == 0) retValue = EACCES;
2057 /* all connections in cell 1 working? */
2058 for(i=0;i<NSERVERS;i++) {
2059 for(sa = afs_srvAddrs[i]; sa; sa=sa->next_bkt) {
2060 for (tc = sa->conns; tc; tc=tc->next) {
2061 if (tc->user == tu && (tu->states & UTokensBad))
2066 ReleaseReadLock(&afs_xsrvAddr);
2067 ReleaseReadLock(&afs_xconn);
2068 afs_PutUser(tu, READ_LOCK);
2070 memcpy(aout, (char *)&retValue, sizeof(afs_int32));
2071 *aoutSize = sizeof(afs_int32);
2075 static Prefetch(apath, adata, afollow, acred)
2077 struct afs_ioctl *adata;
2079 struct AFS_UCRED *acred;
2082 register afs_int32 code;
2083 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2089 AFS_STATCNT(Prefetch);
2090 if (!apath) return EINVAL;
2091 tp = osi_AllocLargeSpace(1024);
2092 AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2094 osi_FreeLargeSpace(tp);
2097 if (afs_BBusy()) { /* do this as late as possible */
2098 osi_FreeLargeSpace(tp);
2099 return EWOULDBLOCK; /* pretty close */
2101 afs_BQueue(BOP_PATH, (struct vcache*)0, 0, 0, acred,
2102 (afs_size_t) 0, (afs_size_t) 0, tp);
2106 static PFindVolume(avc, afun, areq, ain, aout, ainSize, aoutSize)
2109 struct vrequest *areq;
2112 afs_int32 *aoutSize; /* set this */ {
2113 register struct volume *tvp;
2114 register struct server *ts;
2115 register afs_int32 i;
2118 AFS_STATCNT(PFindVolume);
2119 if (!avc) return EINVAL;
2120 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
2123 for(i=0;i<MAXHOSTS;i++) {
2124 ts = tvp->serverHost[i];
2126 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2127 cp += sizeof(afs_int32);
2130 /* still room for terminating NULL, add it on */
2131 ainSize = 0; /* reuse vbl */
2132 memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
2133 cp += sizeof(afs_int32);
2135 *aoutSize = cp - aout;
2136 afs_PutVolume(tvp, READ_LOCK);
2142 static PViceAccess(avc, afun, areq, ain, aout, ainSize, aoutSize)
2145 struct vrequest *areq;
2148 afs_int32 *aoutSize; /* set this */ {
2149 register afs_int32 code;
2152 AFS_STATCNT(PViceAccess);
2153 if (!avc) return EINVAL;
2154 code = afs_VerifyVCache(avc, areq);
2155 if (code) return code;
2156 memcpy((char *)&temp, ain, sizeof(afs_int32));
2157 code = afs_AccessOK(avc,temp, areq, CHECK_MODE_BITS);
2162 static PSetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2165 struct vrequest *areq;
2168 afs_int32 *aoutSize; /* set this */
2169 struct AFS_UCRED *acred;
2174 AFS_STATCNT(PSetCacheSize);
2175 if (!afs_osi_suser(acred))
2177 /* too many things are setup initially in mem cache version */
2178 if (cacheDiskType == AFS_FCACHE_TYPE_MEM) return EROFS;
2179 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2180 if (newValue == 0) afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2182 extern u_int afs_min_cache;
2183 if (newValue < afs_min_cache)
2184 afs_cacheBlocks = afs_min_cache;
2186 afs_cacheBlocks = newValue;
2188 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2189 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2190 afs_MaybeWakeupTruncateDaemon();
2191 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2192 afs_osi_Wait(1000, 0, 0);
2193 afs_MaybeWakeupTruncateDaemon();
2198 #define MAXGCSTATS 16
2199 static PGetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize)
2202 struct vrequest *areq;
2205 afs_int32 *aoutSize; /* set this */ {
2206 afs_int32 results[MAXGCSTATS];
2208 AFS_STATCNT(PGetCacheSize);
2209 memset((char *)results, 0, sizeof(results));
2210 results[0] = afs_cacheBlocks;
2211 results[1] = afs_blocksUsed;
2212 memcpy(aout, (char *)results, sizeof(results));
2213 *aoutSize = sizeof(results);
2217 static PRemoveCallBack(avc, afun, areq, ain, aout, ainSize, aoutSize)
2220 struct vrequest *areq;
2223 afs_int32 *aoutSize; /* set this */ {
2224 register struct conn *tc;
2225 register afs_int32 code;
2226 struct AFSCallBack CallBacks_Array[1];
2227 struct AFSCBFids theFids;
2228 struct AFSCBs theCBs;
2231 AFS_STATCNT(PRemoveCallBack);
2232 if (!avc) return EINVAL;
2233 if (avc->states & CRO) return 0; /* read-only-ness can't change */
2234 ObtainWriteLock(&avc->lock,229);
2235 theFids.AFSCBFids_len = 1;
2236 theCBs.AFSCBs_len = 1;
2237 theFids.AFSCBFids_val = (struct AFSFid *) &avc->fid.Fid;
2238 theCBs.AFSCBs_val = CallBacks_Array;
2239 CallBacks_Array[0].CallBackType = CB_DROPPED;
2240 if (avc->callback) {
2242 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2244 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2246 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2250 /* don't set code on failure since we wouldn't use it */
2252 (afs_Analyze(tc, code, &avc->fid, areq,
2253 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS,
2254 SHARED_LOCK, (struct cell *)0));
2256 ObtainWriteLock(&afs_xcbhash, 457);
2257 afs_DequeueCallback(avc);
2259 avc->states &= ~(CStatd | CUnique);
2260 ReleaseWriteLock(&afs_xcbhash);
2261 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2262 osi_dnlc_purgedp(avc);
2264 ReleaseWriteLock(&avc->lock);
2268 static PNewCell(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2271 struct vrequest *areq;
2275 struct AFS_UCRED *acred;
2276 afs_int32 *aoutSize; /* set this */ {
2277 /* create a new cell */
2278 afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic=0;
2279 register struct cell *tcell;
2280 char *newcell=0, *linkedcell=0, *tp= ain;
2281 register afs_int32 code, linkedstate=0, ls;
2282 u_short fsport = 0, vlport = 0;
2285 AFS_STATCNT(PNewCell);
2286 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2287 return EIO; /* Inappropriate ioctl for device */
2289 if (!afs_osi_suser(acred))
2292 memcpy((char *)&magic, tp, sizeof(afs_int32));
2293 tp += sizeof(afs_int32);
2294 if (magic != 0x12345678)
2297 /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2298 * server addresses while the 3.5 fs newcell command passes
2299 * MAXHOSTS. To figure out which is which, check if the cellname
2302 newcell = tp + (MAXCELLHOSTS+3)*sizeof(afs_int32);
2303 scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2305 /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2306 memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
2307 tp += (scount * sizeof(afs_int32));
2309 lp = (afs_int32 *)tp;
2312 if (fsport < 1024) fsport = 0; /* Privileged ports not allowed */
2313 if (vlport < 1024) vlport = 0; /* Privileged ports not allowed */
2314 tp += (3 * sizeof(afs_int32));
2316 if ((ls = *lp) & 1) {
2317 linkedcell = tp + strlen(newcell)+1;
2318 linkedstate |= CLinkedCell;
2321 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2322 code = afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport, vlport, (int)0, (char *) 0);
2326 static PNewAlias(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2329 struct vrequest *areq;
2333 struct AFS_UCRED *acred;
2334 afs_int32 *aoutSize; /* set this */
2336 /* create a new cell alias */
2337 register struct cell *tcell;
2339 register afs_int32 code;
2340 char *realName, *aliasName;
2341 register struct afs_q *cq, *tq;
2343 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2344 return EIO; /* Inappropriate ioctl for device */
2346 if (!afs_osi_suser(acred))
2350 tp += strlen(aliasName) + 1;
2354 * Prevent user from shooting themselves in the foot -- don't allow
2355 * creation of aliases when a real cell already exists with that name.
2357 ObtainReadLock(&afs_xcell);
2358 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2359 tcell = QTOC(cq); tq = QNext(cq);
2360 if ((afs_strcasecmp(tcell->cellName, aliasName) == 0) &&
2361 !(tcell->states & CAlias)) {
2362 ReleaseReadLock(&afs_xcell);
2366 ReleaseReadLock(&afs_xcell);
2368 code = afs_NewCell(aliasName, 0, CAlias, 0, 0, 0, 0, realName);
2373 static PListCells(avc, afun, areq, ain, aout, ainSize, aoutSize)
2376 struct vrequest *areq;
2379 afs_int32 *aoutSize; /* set this */ {
2380 afs_int32 whichCell;
2381 register struct cell *tcell=0;
2382 register afs_int32 i;
2383 register char *cp, *tp = ain;
2384 register struct afs_q *cq, *tq;
2386 AFS_STATCNT(PListCells);
2387 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2388 return EIO; /* Inappropriate ioctl for device */
2390 memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2391 tp += sizeof(afs_int32);
2392 ObtainReadLock(&afs_xcell);
2393 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2394 tcell = QTOC(cq); tq = QNext(cq);
2395 if (tcell->states & CAlias) {
2399 if (whichCell == 0) break;
2405 memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
2406 for(i=0;i<MAXCELLHOSTS;i++) {
2407 if (tcell->cellHosts[i] == 0) break;
2408 memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip, sizeof(afs_int32));
2409 cp += sizeof(afs_int32);
2411 cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2412 strcpy(cp, tcell->cellName);
2413 cp += strlen(tcell->cellName)+1;
2414 *aoutSize = cp - aout;
2416 ReleaseReadLock(&afs_xcell);
2417 if (tcell) return 0;
2421 static PListAliases(avc, afun, areq, ain, aout, ainSize, aoutSize)
2424 struct vrequest *areq;
2427 afs_int32 *aoutSize; /* set this */
2429 afs_int32 whichAlias;
2430 register struct cell *tcell=0;
2431 register char *cp, *tp = ain;
2432 register struct afs_q *cq, *tq;
2434 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2435 return EIO; /* Inappropriate ioctl for device */
2436 if (ainSize < sizeof(afs_int32))
2439 memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2440 tp += sizeof(afs_int32);
2442 ObtainReadLock(&afs_xcell);
2443 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2444 tcell = QTOC(cq); tq = QNext(cq);
2445 if (!(tcell->states & CAlias)) {
2449 if (whichAlias == 0) break;
2455 strcpy(cp, tcell->cellName);
2456 cp += strlen(tcell->cellName)+1;
2457 strcpy(cp, tcell->realName);
2458 cp += strlen(tcell->realName)+1;
2459 *aoutSize = cp - aout;
2461 ReleaseReadLock(&afs_xcell);
2462 if (tcell) return 0;
2466 static PRemoveMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
2469 struct vrequest *areq;
2473 afs_int32 *aoutSize; /* set this */ {
2474 register afs_int32 code;
2476 struct sysname_info sysState;
2477 afs_size_t offset, len;
2478 register struct conn *tc;
2479 register struct dcache *tdc;
2480 register struct vcache *tvc;
2481 struct AFSFetchStatus OutDirStatus;
2482 struct VenusFid tfid;
2483 struct AFSVolSync tsync;
2487 /* "ain" is the name of the file in this dir to remove */
2489 AFS_STATCNT(PRemoveMount);
2490 if (!avc) return EINVAL;
2491 code = afs_VerifyVCache(avc, areq);
2492 if (code) return code;
2493 if (vType(avc) != VDIR) return ENOTDIR;
2495 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1); /* test for error below */
2496 if (!tdc) return ENOENT;
2497 Check_AtSys(avc, ain, &sysState, areq);
2498 ObtainReadLock(&tdc->lock);
2500 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
2501 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2502 ReleaseReadLock(&tdc->lock);
2503 bufp = sysState.name;
2508 tfid.Cell = avc->fid.Cell;
2509 tfid.Fid.Volume = avc->fid.Fid.Volume;
2510 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
2511 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
2513 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0,
2514 (struct vcache*)0/*xxx avc?*/, WRITE_LOCK);
2521 if (tvc->mvstat != 1) {
2523 afs_PutVCache(tvc, WRITE_LOCK);
2527 ObtainWriteLock(&tvc->lock,230);
2528 code = afs_HandleLink(tvc, areq);
2530 if (tvc->linkData) {
2531 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2536 ReleaseWriteLock(&tvc->lock);
2537 osi_dnlc_purgedp(tvc);
2538 afs_PutVCache(tvc, WRITE_LOCK);
2543 ObtainWriteLock(&avc->lock,231);
2544 osi_dnlc_remove(avc, bufp, tvc);
2546 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2548 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2550 code = RXAFS_RemoveFile(tc->id, (struct AFSFid *) &avc->fid.Fid,
2551 bufp, &OutDirStatus, &tsync);
2557 (afs_Analyze(tc, code, &avc->fid, areq,
2558 AFS_STATS_FS_RPCIDX_REMOVEFILE,
2559 SHARED_LOCK, (struct cell *)0));
2562 if (tdc) afs_PutDCache(tdc);
2563 ReleaseWriteLock(&avc->lock);
2567 /* we have the thing in the cache */
2568 ObtainWriteLock(&tdc->lock, 661);
2569 if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2570 /* we can do it locally */
2571 code = afs_dir_Delete(&tdc->f.inode, bufp);
2573 ZapDCE(tdc); /* surprise error -- invalid value */
2574 DZap(&tdc->f.inode);
2577 ReleaseWriteLock(&tdc->lock);
2578 afs_PutDCache(tdc); /* drop ref count */
2580 avc->states &= ~CUnique; /* For the dfs xlator */
2581 ReleaseWriteLock(&avc->lock);
2584 if (sysState.allocked) osi_FreeLargeSpace(bufp);
2588 static PVenusLogging(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2591 struct vrequest *areq;
2595 struct AFS_UCRED *acred;
2596 afs_int32 *aoutSize; /* set this */ {
2597 return EINVAL; /* OBSOLETE */
2600 static PGetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2603 struct vrequest *areq;
2606 afs_int32 *aoutSize; /* set this */ {
2607 register struct cell *tcell;
2610 AFS_STATCNT(PGetCellStatus);
2611 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2612 return EIO; /* Inappropriate ioctl for device */
2614 tcell = afs_GetCellByName(ain, READ_LOCK);
2615 if (!tcell) return ENOENT;
2616 temp = tcell->states;
2617 afs_PutCell(tcell, READ_LOCK);
2618 memcpy(aout, (char *)&temp, sizeof(afs_int32));
2619 *aoutSize = sizeof(afs_int32);
2623 static PSetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2626 struct vrequest *areq;
2629 struct AFS_UCRED *acred;
2630 afs_int32 *aoutSize; /* set this */ {
2631 register struct cell *tcell;
2634 if (!afs_osi_suser(acred))
2636 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2637 return EIO; /* Inappropriate ioctl for device */
2639 tcell = afs_GetCellByName(ain+2*sizeof(afs_int32), WRITE_LOCK);
2640 if (!tcell) return ENOENT;
2641 memcpy((char *)&temp, ain, sizeof(afs_int32));
2643 tcell->states |= CNoSUID;
2645 tcell->states &= ~CNoSUID;
2646 afs_PutCell(tcell, WRITE_LOCK);
2650 static PFlushVolumeData(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2653 struct vrequest *areq;
2656 afs_int32 *aoutSize; /* set this */
2657 struct AFS_UCRED *acred;
2659 extern struct volume *afs_volumes[NVOLS];
2660 register afs_int32 i;
2661 register struct dcache *tdc;
2662 register struct vcache *tvc;
2663 register struct volume *tv;
2664 afs_int32 cell, volume;
2666 AFS_STATCNT(PFlushVolumeData);
2669 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2670 return EIO; /* Inappropriate ioctl for device */
2672 volume = avc->fid.Fid.Volume; /* who to zap */
2673 cell = avc->fid.Cell;
2676 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
2677 * the vcaches associated with the volume.
2679 ObtainReadLock(&afs_xvcache);
2680 for(i = 0; i < VCSIZE; i++) {
2681 for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
2682 if (tvc->fid.Fid.Volume == volume && tvc->fid.Cell == cell) {
2683 #if defined(AFS_SGI_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
2684 VN_HOLD(AFSTOV(tvc));
2686 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2692 ReleaseReadLock(&afs_xvcache);
2693 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2694 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
2696 ObtainWriteLock(&tvc->lock,232);
2698 ObtainWriteLock(&afs_xcbhash, 458);
2699 afs_DequeueCallback(tvc);
2700 tvc->states &= ~(CStatd | CDirty);
2701 ReleaseWriteLock(&afs_xcbhash);
2702 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
2703 osi_dnlc_purgedp(tvc);
2704 afs_TryToSmush(tvc, acred, 1);
2705 ReleaseWriteLock(&tvc->lock);
2706 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2707 afs_BozonUnlock(&tvc->pvnLock, tvc);
2709 ObtainReadLock(&afs_xvcache);
2710 /* our tvc ptr is still good until now */
2715 ReleaseReadLock(&afs_xvcache);
2718 MObtainWriteLock(&afs_xdcache,328); /* needed if you're going to flush any stuff */
2719 for(i=0;i<afs_cacheFiles;i++) {
2720 if (!(afs_indexFlags[i] & IFEverUsed)) continue; /* never had any data */
2721 tdc = afs_GetDSlot(i, (struct dcache *) 0);
2722 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
2723 ReleaseReadLock(&tdc->tlock);
2724 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
2725 if (! (afs_indexFlags[i] & IFDataMod)) {
2726 /* if the file is modified, but has a ref cnt of only 1, then
2727 someone probably has the file open and is writing into it.
2728 Better to skip flushing such a file, it will be brought back
2729 immediately on the next write anyway.
2731 If we *must* flush, then this code has to be rearranged to call
2732 afs_storeAllSegments() first */
2733 afs_FlushDCache(tdc);
2737 ReleaseReadLock(&tdc->tlock);
2739 afs_PutDCache(tdc); /* bumped by getdslot */
2741 MReleaseWriteLock(&afs_xdcache);
2743 ObtainReadLock(&afs_xvolume);
2744 for (i=0;i<NVOLS;i++) {
2745 for (tv = afs_volumes[i]; tv; tv=tv->next) {
2746 if (tv->volume == volume) {
2747 afs_ResetVolumeInfo(tv);
2752 ReleaseReadLock(&afs_xvolume);
2754 /* probably, a user is doing this, probably, because things are screwed up.
2755 * maybe it's the dnlc's fault? */
2762 static PGetVnodeXStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2765 struct vrequest *areq;
2768 afs_int32 *aoutSize; /* set this */ {
2769 register afs_int32 code;
2770 struct vcxstat stat;
2773 /* AFS_STATCNT(PGetVnodeXStatus); */
2774 if (!avc) return EINVAL;
2775 code = afs_VerifyVCache(avc, areq);
2776 if (code) return code;
2777 if (vType(avc) == VDIR)
2778 mode = PRSFS_LOOKUP;
2781 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
2783 stat.fid = avc->fid;
2784 hset32(stat.DataVersion, hgetlo(avc->m.DataVersion));
2785 stat.lock = avc->lock;
2786 stat.parentVnode = avc->parentVnode;
2787 stat.parentUnique = avc->parentUnique;
2788 hset(stat.flushDV, avc->flushDV);
2789 hset(stat.mapDV, avc->mapDV);
2790 stat.truncPos = avc->truncPos;
2791 { /* just grab the first two - won't break anything... */
2792 struct axscache *ac;
2794 for (i=0, ac=avc->Access; ac && i < CPSIZE; i++, ac=ac->next) {
2795 stat.randomUid[i] = ac->uid;
2796 stat.randomAccess[i] = ac->axess;
2799 stat.callback = afs_data_pointer_to_int32(avc->callback);
2800 stat.cbExpires = avc->cbExpires;
2801 stat.anyAccess = avc->anyAccess;
2802 stat.opens = avc->opens;
2803 stat.execsOrWriters = avc->execsOrWriters;
2804 stat.flockCount = avc->flockCount;
2805 stat.mvstat = avc->mvstat;
2806 stat.states = avc->states;
2807 memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
2808 *aoutSize = sizeof(struct vcxstat);
2813 /* We require root for local sysname changes, but not for remote */
2814 /* (since we don't really believe remote uids anyway) */
2815 /* outname[] shouldn't really be needed- this is left as an excercise */
2816 /* for the reader. */
2817 static PSetSysName(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2820 struct vrequest *areq;
2823 afs_int32 *aoutSize; /* set this */
2824 register struct AFS_UCRED *acred;
2826 char *cp, inname[MAXSYSNAME], outname[MAXSYSNAME];
2827 int setsysname, foundname=0;
2828 register struct afs_exporter *exporter;
2829 extern struct unixuser *afs_FindUser();
2830 extern char *afs_sysname;
2831 extern char *afs_sysnamelist[];
2832 extern int afs_sysnamecount;
2833 register struct unixuser *au;
2834 register afs_int32 pag, error;
2838 AFS_STATCNT(PSetSysName);
2839 if (!afs_globalVFS) {
2840 /* Afsd is NOT running; disable it */
2841 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2844 return (setuerror(EINVAL), EINVAL);
2847 memset(inname, 0, MAXSYSNAME);
2848 memcpy((char *)&setsysname, ain, sizeof(afs_int32));
2849 ain += sizeof(afs_int32);
2853 if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
2855 for(cp = ain,count = 0;count < setsysname;count++) {
2856 /* won't go past end of ain since maxsysname*num < ain length */
2858 if (t >= MAXSYSNAME || t <= 0)
2860 /* check for names that can shoot us in the foot */
2861 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
2867 /* inname gets first entry in case we're being a translater */
2869 memcpy(inname, ain, t+1); /* include terminating null */
2872 if (acred->cr_gid == RMTUSER_REQ) { /* Handles all exporters */
2873 pag = PagInCred(acred);
2875 return EINVAL; /* Better than panicing */
2877 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
2878 return EINVAL; /* Better than panicing */
2880 if (!(exporter = au->exporter)) {
2881 afs_PutUser(au, READ_LOCK);
2882 return EINVAL; /* Better than panicing */
2884 error = EXP_SYSNAME(exporter, (setsysname? inname : (char *)0), outname);
2886 if (error == ENODEV) foundname = 0; /* sysname not set yet! */
2888 afs_PutUser(au, READ_LOCK);
2893 afs_PutUser(au, READ_LOCK);
2896 /* Not xlating, so local case */
2897 if (!afs_sysname) osi_Panic("PSetSysName: !afs_sysname\n");
2898 if (!setsysname) { /* user just wants the info */
2899 strcpy(outname, afs_sysname);
2900 foundname = afs_sysnamecount;
2901 } else { /* Local guy; only root can change sysname */
2902 if (!afs_osi_suser(acred))
2905 /* clear @sys entries from the dnlc, once afs_lookup can
2906 do lookups of @sys entries and thinks it can trust them */
2907 /* privs ok, store the entry, ... */
2908 strcpy(afs_sysname, inname);
2909 if (setsysname > 1) { /* ... or list */
2911 for(count=1; count < setsysname;++count) {
2912 if (!afs_sysnamelist[count])
2913 osi_Panic("PSetSysName: no afs_sysnamelist entry to write\n");
2915 memcpy(afs_sysnamelist[count], cp, t+1); /* include null */
2919 afs_sysnamecount = setsysname;
2923 cp = aout; /* not changing so report back the count and ... */
2924 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
2925 cp += sizeof(afs_int32);
2927 strcpy(cp, outname); /* ... the entry, ... */
2928 cp += strlen(outname)+1;
2929 for(count=1; count < foundname; ++count) { /* ... or list. */
2930 /* Note: we don't support @sys lists for exporters */
2931 if (!afs_sysnamelist[count])
2932 osi_Panic("PSetSysName: no afs_sysnamelist entry to read\n");
2933 t = strlen(afs_sysnamelist[count]);
2934 if (t >= MAXSYSNAME)
2935 osi_Panic("PSetSysName: sysname entry garbled\n");
2936 strcpy(cp, afs_sysnamelist[count]);
2940 *aoutSize = cp - aout;
2945 /* sequential search through the list of touched cells is not a good
2946 * long-term solution here. For small n, though, it should be just
2947 * fine. Should consider special-casing the local cell for large n.
2948 * Likewise for PSetSPrefs.
2950 static void ReSortCells(s,l, vlonly)
2951 int s; /* number of ids in array l[] -- NOT index of last id */
2952 afs_int32 l[]; /* array of cell ids which have volumes that need to be sorted */
2953 int vlonly; /* sort vl servers or file servers?*/
2955 extern struct volume *afs_volumes[NVOLS]; /* volume hash table */
2963 ObtainWriteLock(&afs_xcell,300);
2965 tcell = afs_GetCellNoLock(l[k], WRITE_LOCK);
2966 if (!tcell) continue;
2967 afs_SortServers(tcell->cellHosts, MAXCELLHOSTS);
2968 afs_PutCell(tcell, WRITE_LOCK);
2970 ReleaseWriteLock(&afs_xcell);
2974 ObtainReadLock(&afs_xvolume);
2975 for (i= 0; i< NVOLS; i++) {
2976 for (j=afs_volumes[i];j;j=j->next) {
2978 if (j->cell == l[k]) {
2979 ObtainWriteLock(&j->lock,233);
2980 afs_SortServers(j->serverHost, MAXHOSTS);
2981 ReleaseWriteLock(&j->lock);
2986 ReleaseReadLock(&afs_xvolume);
2991 static int afs_setsprefs(sp, num, vlonly)
2994 unsigned int vlonly;
2997 int i,j,k,matches,touchedSize;
2998 struct server *srvr = NULL;
2999 afs_int32 touched[34];
3003 for (k=0; k < num; sp++, k++) {
3005 printf ("sp host=%x, rank=%d\n",sp->host.s_addr, sp->rank);
3008 ObtainReadLock(&afs_xserver);
3010 i = SHash(sp->host.s_addr);
3011 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
3012 if (sa->sa_ip == sp->host.s_addr) {
3014 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3015 || (sa->sa_portal == AFS_FSPORT);
3016 if ((!vlonly && isfs) || (vlonly && !isfs)) {
3023 if (sa && matches) { /* found one! */
3025 printf ("sa ip=%x, ip_rank=%d\n",sa->sa_ip, sa->sa_iprank);
3027 sa->sa_iprank = sp->rank + afs_randomMod15();
3028 afs_SortOneServer(sa->server);
3031 /* if we don't know yet what cell it's in, this is moot */
3032 for (j=touchedSize-1; j>=0 && touched[j] != srvr->cell->cell; j--)
3033 /* is it in our list of touched cells ? */ ;
3034 if (j < 0) { /* no, it's not */
3035 touched[touchedSize++] = srvr->cell->cell;
3036 if (touchedSize >= 32) { /* watch for ovrflow */
3037 ReleaseReadLock(&afs_xserver);
3038 ReSortCells(touchedSize, touched, vlonly);
3040 ObtainReadLock(&afs_xserver);
3046 ReleaseReadLock(&afs_xserver);
3047 /* if we didn't find one, start to create one. */
3048 /* Note that it doesn't have a cell yet... */
3050 afs_uint32 temp = sp->host.s_addr;
3051 srvr = afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
3052 WRITE_LOCK, (afsUUID *)0,0);
3053 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3054 afs_PutServer(srvr, WRITE_LOCK);
3056 } /* for all cited preferences */
3058 ReSortCells(touchedSize, touched, vlonly);
3062 /* Note that this may only be performed by the local root user.
3065 PSetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3068 struct vrequest *areq;
3071 struct AFS_UCRED *acred;
3072 afs_int32 *aoutSize;
3074 struct setspref *ssp;
3075 AFS_STATCNT(PSetSPrefs);
3077 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3078 return EIO; /* Inappropriate ioctl for device */
3080 if (!afs_osi_suser(acred))
3083 if (ainSize < sizeof(struct setspref))
3086 ssp = (struct setspref *)ain;
3087 if (ainSize < sizeof(struct spref)*ssp->num_servers)
3090 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
3091 (ssp->flags & DBservers));
3096 PSetSPrefs33(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3099 struct vrequest *areq;
3102 struct AFS_UCRED *acred;
3103 afs_int32 *aoutSize;
3106 AFS_STATCNT(PSetSPrefs);
3107 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3108 return EIO; /* Inappropriate ioctl for device */
3111 if (!afs_osi_suser(acred))
3114 sp = (struct spref *)ain;
3115 afs_setsprefs(sp, ainSize/(sizeof(struct spref)), 0 /*!vlonly*/);
3119 /* some notes on the following code...
3120 * in the hash table of server structs, all servers with the same IP address
3121 * will be on the same overflow chain.
3122 * This could be sped slightly in some circumstances by having it cache the
3123 * immediately previous slot in the hash table and some supporting information
3124 * Only reports file servers now.
3127 PGetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3130 struct vrequest *areq;
3133 afs_int32 *aoutSize;
3135 struct sprefrequest *spin; /* input */
3136 struct sprefinfo *spout; /* output */
3137 struct spref *srvout; /* one output component */
3138 int i,j; /* counters for hash table traversal */
3139 struct server *srvr; /* one of CM's server structs */
3142 int vlonly; /* just return vlservers ? */
3145 AFS_STATCNT(PGetSPrefs);
3146 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3147 return EIO; /* Inappropriate ioctl for device */
3150 if (ainSize < sizeof (struct sprefrequest_33)) {
3154 spin = ((struct sprefrequest *) ain);
3157 if (ainSize > sizeof (struct sprefrequest_33)) {
3158 vlonly = (spin->flags & DBservers);
3162 /* struct sprefinfo includes 1 server struct... that size gets added
3163 * in during the loop that follows.
3165 *aoutSize = sizeof(struct sprefinfo) - sizeof (struct spref);
3166 spout = (struct sprefinfo *) aout;
3167 spout->next_offset = spin->offset;
3168 spout->num_servers = 0;
3169 srvout = spout->servers;
3171 ObtainReadLock(&afs_xserver);
3172 for (i=0, j=0; j < NSERVERS; j++) { /* sift through hash table */
3173 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3174 if (spin->offset > (unsigned short)i) {
3175 continue; /* catch up to where we left off */
3177 spout->next_offset++;
3180 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3181 || (sa->sa_portal == AFS_FSPORT);
3183 if ((vlonly && isfs) || (!vlonly && !isfs)) {
3184 /* only report ranks for vl servers */
3188 srvout->host.s_addr = sa->sa_ip;
3189 srvout->rank = sa->sa_iprank;
3190 *aoutSize += sizeof(struct spref);
3191 spout->num_servers++;
3194 if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3195 ReleaseReadLock(&afs_xserver); /* no more room! */
3200 ReleaseReadLock(&afs_xserver);
3202 spout->next_offset = 0; /* start over from the beginning next time */
3206 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3207 int afs_NFSRootOnly = 1;
3208 /*static*/ PExportAfs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3211 struct vrequest *areq;
3214 afs_int32 *aoutSize; /* set this */
3215 struct AFS_UCRED *acred;
3217 afs_int32 export, newint=0, type, changestate, handleValue, convmode, pwsync, smounts;
3218 extern struct afs_exporter *exporter_find();
3219 register struct afs_exporter *exporter;
3221 AFS_STATCNT(PExportAfs);
3222 memcpy((char *)&handleValue, ain, sizeof(afs_int32));
3223 type = handleValue >> 24;
3228 exporter = exporter_find(type);
3230 export = handleValue & 3;
3231 changestate = handleValue & 0xff;
3232 smounts = (handleValue >> 2) & 3;
3233 pwsync = (handleValue >> 4) & 3;
3234 convmode = (handleValue >> 6) & 3;
3236 changestate = (handleValue >> 16) & 0x1;
3237 convmode = (handleValue >> 16) & 0x2;
3238 pwsync = (handleValue >> 16) & 0x4;
3239 smounts = (handleValue >> 16) & 0x8;
3240 export = handleValue & 0xff;
3243 /* Failed finding desired exporter; */
3247 handleValue = exporter->exp_states;
3248 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3249 *aoutSize = sizeof(afs_int32);
3251 if (!afs_osi_suser(acred))
3252 return EACCES; /* Only superuser can do this */
3256 exporter->exp_states |= EXP_EXPORTED;
3258 exporter->exp_states &= ~EXP_EXPORTED;
3262 exporter->exp_states |= EXP_UNIXMODE;
3264 exporter->exp_states &= ~EXP_UNIXMODE;
3268 exporter->exp_states |= EXP_PWSYNC;
3270 exporter->exp_states &= ~EXP_PWSYNC;
3274 afs_NFSRootOnly = 0;
3275 exporter->exp_states |= EXP_SUBMOUNTS;
3277 afs_NFSRootOnly = 1;
3278 exporter->exp_states &= ~EXP_SUBMOUNTS;
3281 handleValue = exporter->exp_states;
3282 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3283 *aoutSize = sizeof(afs_int32);
3286 exporter->exp_states |= EXP_EXPORTED;
3288 exporter->exp_states &= ~EXP_EXPORTED;
3290 exporter->exp_states |= EXP_UNIXMODE;
3292 exporter->exp_states &= ~EXP_UNIXMODE;
3294 exporter->exp_states |= EXP_PWSYNC;
3296 exporter->exp_states &= ~EXP_PWSYNC;
3298 afs_NFSRootOnly = 0;
3299 exporter->exp_states |= EXP_SUBMOUNTS;
3301 afs_NFSRootOnly = 1;
3302 exporter->exp_states &= ~EXP_SUBMOUNTS;
3311 PGag(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3314 struct vrequest *areq;
3317 struct AFS_UCRED *acred;
3318 afs_int32 *aoutSize; /* set this */
3320 struct gaginfo *gagflags;
3322 if (!afs_osi_suser(acred))
3325 gagflags = (struct gaginfo *) ain;
3326 afs_showflags = gagflags->showflags;
3333 PTwiddleRx(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3336 struct vrequest *areq;
3339 struct AFS_UCRED *acred;
3340 afs_int32 *aoutSize;
3342 struct rxparams *rxp;
3344 if (!afs_osi_suser(acred))
3347 rxp = (struct rxparams *) ain;
3349 if (rxp->rx_initReceiveWindow)
3350 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3351 if (rxp->rx_maxReceiveWindow)
3352 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3353 if (rxp->rx_initSendWindow)
3354 rx_initSendWindow = rxp->rx_initSendWindow;
3355 if (rxp->rx_maxSendWindow)
3356 rx_maxSendWindow = rxp->rx_maxSendWindow;
3357 if (rxp->rxi_nSendFrags)
3358 rxi_nSendFrags = rxp->rxi_nSendFrags;
3359 if (rxp->rxi_nRecvFrags)
3360 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3361 if (rxp->rxi_OrphanFragSize)
3362 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3363 if (rxp->rx_maxReceiveSize)
3365 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3366 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3368 if (rxp->rx_MyMaxSendSize)
3369 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3374 static int PGetInitParams(avc, afun, areq, ain, aout, ainSize, aoutSize)
3377 struct vrequest *areq;
3381 afs_int32 *aoutSize; /* set this */
3383 if (sizeof(struct cm_initparams) > PIGGYSIZE)
3386 memcpy(aout, (char*)&cm_initParams, sizeof(struct cm_initparams));
3387 *aoutSize = sizeof(struct cm_initparams);
3391 #ifdef AFS_SGI65_ENV
3392 /* They took crget() from us, so fake it. */
3393 static cred_t *crget(void)
3396 cr = crdup(get_current_cred());
3397 memset((char*)cr, 0, sizeof(cred_t));
3398 #if CELL || CELL_PREPARE
3406 PGetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3409 struct vrequest *areq;
3412 afs_int32 *aoutSize;
3413 struct AFS_UCRED *acred;
3415 memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3416 *aoutSize=sizeof(afs_int32);
3421 PSetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3424 struct vrequest *areq;
3427 afs_int32 *aoutSize;
3428 struct AFS_UCRED *acred;
3432 if (!afs_osi_suser(acred))
3434 if (ainSize != sizeof(afs_int32) || ain == NULL)
3436 memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3437 /* if new mappings added later this will need to be changed */
3438 if (tmpval != 0 && tmpval != 1)
3445 * Create new credentials to correspond to a remote user with given
3446 * <hostaddr, uid, g0, g1>. This allows a server running as root to
3447 * provide pioctl (and other) services to foreign clients (i.e. nfs
3448 * clients) by using this call to `become' the client.
3451 #define PIOCTL_HEADER 6
3452 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3455 afs_uint32 hostaddr;
3456 afs_int32 uid, g0, g1, i, code, pag, exporter_type;
3457 extern struct afs_exporter *exporter_find();
3458 struct afs_exporter *exporter, *outexporter;
3459 struct AFS_UCRED *newcred;
3460 struct unixuser *au;
3462 #if defined(AFS_DEC_ENV) || (defined(AFS_NONFSTRANS) && !defined(AFS_AIX_IAUTH_ENV))
3463 return EINVAL; /* NFS trans not supported for Ultrix */
3465 #if defined(AFS_SGIMP_ENV)
3466 osi_Assert(ISAFS_GLOCK());
3468 AFS_STATCNT(HandleClientContext);
3469 if (ablob->in_size < PIOCTL_HEADER*sizeof(afs_int32)) {
3470 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3471 return EINVAL; /* Too small to be good */
3473 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3474 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER*sizeof(afs_int32), code);
3476 osi_FreeLargeSpace(inData);
3480 /* Extract information for remote user */
3481 hostaddr = *((afs_uint32 *)ain);
3482 ain += sizeof(hostaddr);
3483 uid = *((afs_uint32 *)ain);
3485 g0 = *((afs_uint32 *)ain);
3487 g1 = *((afs_uint32 *)ain);
3489 *com = *((afs_uint32 *)ain);
3490 ain += sizeof(afs_int32);
3491 exporter_type = *((afs_uint32 *)ain); /* In case we support more than NFS */
3494 * Of course, one must be root for most of these functions, but
3495 * we'll allow (for knfs) you to set things if the pag is 0 and
3496 * you're setting tokens or unlogging.
3499 if (!afs_osi_suser(credp)) {
3501 #ifndef AFS_SGI64_ENV
3502 /* Since SGI's suser() returns explicit failure after the call.. */
3506 /* check for acceptable opcodes for normal folks, which are, so far,
3507 * set tokens and unlog.
3509 if (i != 9 && i != 3 && i != 38 && i != 8) {
3510 osi_FreeLargeSpace(inData);
3515 ablob->in_size -= PIOCTL_HEADER*sizeof(afs_int32);
3516 ablob->in += PIOCTL_HEADER*sizeof(afs_int32);
3517 osi_FreeLargeSpace(inData);
3520 * We map uid 0 to nobody to match the mapping that the nfs
3521 * server does and to ensure that the suser() calls in the afs
3522 * code fails for remote client roots.
3524 uid = afs_nobody; /* NFS_NOBODY == -2 */
3527 #ifdef AFS_AIX41_ENV
3530 newcred->cr_gid = RMTUSER_REQ;
3531 newcred->cr_groups[0] = g0;
3532 newcred->cr_groups[1] = g1;
3534 newcred->cr_ngrps = 2;
3536 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)
3537 newcred->cr_ngroups = 2;
3539 for (i=2; i<NGROUPS; i++)
3540 newcred->cr_groups[i] = NOGROUP;
3543 #if !defined(AFS_OSF_ENV) && !defined(AFS_DEC_ENV)
3544 afs_nfsclient_init(); /* before looking for exporter, ensure one exists */
3546 if (!(exporter = exporter_find(exporter_type))) {
3547 /* Exporter wasn't initialized or an invalid exporter type */
3551 if (exporter->exp_states & EXP_PWSYNC) {
3552 if (uid != credp->cr_uid) {
3554 return ENOEXEC; /* XXX Find a better errno XXX */
3557 newcred->cr_uid = uid; /* Only temporary */
3558 code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
3559 /* The client's pag is the only unique identifier for it */
3560 newcred->cr_uid = pag;
3562 if (!code && *com == PSETPAG) {
3563 /* Special case for 'setpag' */
3564 afs_uint32 pagvalue = genpag();
3566 au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
3568 * Note that we leave the 'outexporter' struct held so it won't
3571 au->exporter = outexporter;
3572 if (ablob->out_size >= 4) {
3573 AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32), code);
3575 afs_PutUser(au, WRITE_LOCK);
3576 if (code) return code;
3577 return PSETPAG; /* Special return for setpag */
3579 EXP_RELE(outexporter);
3582 #endif /*defined(AFS_DEC_ENV) || defined(AFS_NONFSTRANS)*/
3585 /* get all interface addresses of this client */
3588 PGetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3591 struct vrequest *areq;
3594 afs_int32 *aoutSize;
3596 struct sprefrequest *spin; /* input */
3597 struct sprefinfo *spout; /* output */
3598 struct spref *srvout; /* one output component */
3602 AFS_STATCNT(PGetCPrefs);
3603 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3604 return EIO; /* Inappropriate ioctl for device */
3606 if ( ainSize < sizeof (struct sprefrequest ))
3609 spin = (struct sprefrequest *) ain;
3610 spout = (struct sprefinfo *) aout;
3612 maxNumber = spin->num_servers; /* max addrs this time */
3613 srvout = spout->servers;
3615 ObtainReadLock(&afs_xinterface);
3617 /* copy out the client interface information from the
3618 ** kernel data structure "interface" to the output buffer
3620 for ( i=spin->offset, j=0; (i < afs_cb_interface.numberOfInterfaces)
3621 && ( j< maxNumber) ; i++, j++, srvout++)
3622 srvout->host.s_addr = afs_cb_interface.addr_in[i];
3624 spout->num_servers = j;
3625 *aoutSize = sizeof(struct sprefinfo) +(j-1)* sizeof (struct spref);
3627 if ( i >= afs_cb_interface.numberOfInterfaces )
3628 spout->next_offset = 0; /* start from beginning again */
3630 spout->next_offset = spin->offset + j;
3632 ReleaseReadLock(&afs_xinterface);
3637 PSetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3640 struct vrequest *areq;
3643 afs_int32 *aoutSize;
3645 struct setspref *sin;
3648 AFS_STATCNT(PSetCPrefs);
3649 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3650 return EIO; /* Inappropriate ioctl for device */
3652 sin = (struct setspref *)ain;
3654 if ( ainSize < sizeof(struct setspref) )
3656 #if 0 /* num_servers is unsigned */
3657 if ( sin->num_servers < 0 )
3660 if ( sin->num_servers > AFS_MAX_INTERFACE_ADDR)
3663 ObtainWriteLock(&afs_xinterface, 412);
3664 afs_cb_interface.numberOfInterfaces = sin->num_servers;
3665 for ( i=0; (unsigned short)i < sin->num_servers; i++)
3666 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
3668 ReleaseWriteLock(&afs_xinterface);
3672 static PFlushMount(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3675 struct vrequest *areq;
3678 afs_int32 *aoutSize;
3679 struct AFS_UCRED *acred; {
3680 register afs_int32 code;
3681 register struct vcache *tvc;
3682 register struct dcache *tdc;
3683 struct VenusFid tfid;
3685 struct sysname_info sysState;
3686 afs_size_t offset, len;
3688 AFS_STATCNT(PFlushMount);
3689 if (!avc) return EINVAL;
3690 code = afs_VerifyVCache(avc, areq);
3691 if (code) return code;
3692 if (vType(avc) != VDIR) {
3695 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
3696 if (!tdc) return ENOENT;
3697 Check_AtSys(avc, ain, &sysState, areq);
3698 ObtainReadLock(&tdc->lock);
3700 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
3701 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
3702 ReleaseReadLock(&tdc->lock);
3703 afs_PutDCache(tdc); /* we're done with the data */
3704 bufp = sysState.name;
3708 tfid.Cell = avc->fid.Cell;
3709 tfid.Fid.Volume = avc->fid.Fid.Volume;
3710 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
3711 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
3713 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
3720 if (tvc->mvstat != 1) {
3721 afs_PutVCache(tvc, WRITE_LOCK);
3725 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3726 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3728 ObtainWriteLock(&tvc->lock,649);
3729 ObtainWriteLock(&afs_xcbhash, 650);
3730 afs_DequeueCallback(tvc);
3731 tvc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
3732 ReleaseWriteLock(&afs_xcbhash);
3733 /* now find the disk cache entries */
3734 afs_TryToSmush(tvc, acred, 1);
3735 osi_dnlc_purgedp(tvc);
3736 afs_symhint_inval(tvc);
3737 if (tvc->linkData && !(tvc->states & CCore)) {
3738 afs_osi_Free(tvc->linkData, strlen(tvc->linkData)+1);
3739 tvc->linkData = (char *) 0;
3741 ReleaseWriteLock(&tvc->lock);
3742 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3743 afs_BozonUnlock(&tvc->pvnLock, tvc);
3745 afs_PutVCache(tvc, WRITE_LOCK);
3747 if (sysState.allocked) osi_FreeLargeSpace(bufp);
3751 static PRxStatProc(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3754 struct vrequest *areq;
3757 afs_int32 *aoutSize;
3758 struct AFS_UCRED *acred;
3763 if (!afs_osi_suser(acred)) {
3767 if (ainSize != sizeof(afs_int32)) {
3771 memcpy((char *)&flags, ain, sizeof(afs_int32));
3772 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3776 if (flags & AFSCALL_RXSTATS_ENABLE) {
3777 rx_enableProcessRPCStats();
3779 if (flags & AFSCALL_RXSTATS_DISABLE) {
3780 rx_disableProcessRPCStats();
3782 if (flags & AFSCALL_RXSTATS_CLEAR) {
3783 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
3791 static PRxStatPeer(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3794 struct vrequest *areq;
3797 afs_int32 *aoutSize;
3798 struct AFS_UCRED *acred;
3803 if (!afs_osi_suser(acred)) {
3807 if (ainSize != sizeof(afs_int32)) {
3811 memcpy((char *)&flags, ain, sizeof(afs_int32));
3812 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3816 if (flags & AFSCALL_RXSTATS_ENABLE) {
3817 rx_enablePeerRPCStats();
3819 if (flags & AFSCALL_RXSTATS_DISABLE) {
3820 rx_disablePeerRPCStats();
3822 if (flags & AFSCALL_RXSTATS_CLEAR) {
3823 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
3830 static PPrefetchFromTape(avc, afun, areq, ain, aout, ainSize, aoutSize)
3833 struct vrequest *areq;
3836 afs_int32 *aoutSize; /* set this */
3838 register afs_int32 code, code1;
3841 struct rx_call *tcall;
3842 struct AFSVolSync tsync;
3843 struct AFSFetchStatus OutStatus;
3844 struct AFSCallBack CallBack;
3845 struct VenusFid tfid;
3850 AFS_STATCNT(PSetAcl);
3854 if (ain && (ainSize == 3 * sizeof(afs_int32)))
3855 Fid = (struct AFSFid *) ain;
3857 Fid = &avc->fid.Fid;
3858 tfid.Cell = avc->fid.Cell;
3859 tfid.Fid.Volume = Fid->Volume;
3860 tfid.Fid.Vnode = Fid->Vnode;
3861 tfid.Fid.Unique = Fid->Unique;
3863 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
3866 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3867 ICL_TYPE_POINTER, tvc,
3868 ICL_TYPE_FID, &tfid,
3869 ICL_TYPE_FID, &avc->fid);
3872 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3873 ICL_TYPE_POINTER, tvc,
3874 ICL_TYPE_FID, &tfid,
3875 ICL_TYPE_FID, &tvc->fid);
3878 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3882 tcall = rx_NewCall(tc->id);
3883 code = StartRXAFS_FetchData(tcall,
3884 (struct AFSFid *) &tvc->fid.Fid, 0, 0);
3886 bytes = rx_Read(tcall, (char *) aout, sizeof(afs_int32));
3887 code = EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
3889 code1 = rx_EndCall(tcall, code);
3894 (afs_Analyze(tc, code, &tvc->fid, areq,
3895 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
3897 /* This call is done only to have the callback things handled correctly */
3898 afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
3899 afs_PutVCache(tvc, WRITE_LOCK);
3902 *aoutSize = sizeof(afs_int32);
3907 static PResidencyCmd(avc, afun, areq, ain, aout, ainSize, aoutSize)
3910 struct vrequest *areq;
3913 afs_int32 *aoutSize; /* set this */
3915 register afs_int32 code;
3918 struct ResidencyCmdInputs *Inputs;
3919 struct ResidencyCmdOutputs *Outputs;
3920 struct VenusFid tfid;
3923 Inputs = (struct ResidencyCmdInputs *) ain;
3924 Outputs = (struct ResidencyCmdOutputs *) aout;
3925 if (!avc) return EINVAL;
3926 if (!ain || ainSize != sizeof(struct ResidencyCmdInputs)) return EINVAL;
3930 Fid = &avc->fid.Fid;
3932 tfid.Cell = avc->fid.Cell;
3933 tfid.Fid.Volume = Fid->Volume;
3934 tfid.Fid.Vnode = Fid->Vnode;
3935 tfid.Fid.Unique = Fid->Unique;
3937 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
3939 afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD,
3940 ICL_TYPE_POINTER, tvc,
3941 ICL_TYPE_INT32, Inputs->command,
3942 ICL_TYPE_FID, &tfid);
3946 if (Inputs->command) {
3948 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3951 code = RXAFS_ResidencyCmd(tc->id, Fid,
3953 (struct ResidencyCmdOutputs *) aout);
3958 (afs_Analyze(tc, code, &tvc->fid, areq,
3959 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
3961 /* This call is done to have the callback things handled correctly */
3962 afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3963 } else { /* just a status request, return also link data */
3965 Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3966 Outputs->chars[0] = 0;
3967 if (vType(tvc) == VLNK) {
3968 ObtainWriteLock(&tvc->lock,555);
3969 if (afs_HandleLink(tvc, areq) == 0)
3970 strncpy((char *) &Outputs->chars, tvc->linkData, MAXCMDCHARS);
3971 ReleaseWriteLock(&tvc->lock);
3975 afs_PutVCache(tvc, WRITE_LOCK);
3978 *aoutSize = sizeof(struct ResidencyCmdOutputs);