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);
1090 inData[inSize]='\0';
1094 osi_FreeLargeSpace(inData);
1095 afs_PutFakeStat(&fakestate);
1098 outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1100 if (function == 3 && device == 'V') /* PSetTokens */
1101 code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, acred);
1103 code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, *acred);
1104 osi_FreeLargeSpace(inData);
1105 if (code == 0 && ablob->out_size > 0) {
1106 if (outSize > ablob->out_size) outSize = ablob->out_size;
1107 if (outSize >= PIGGYSIZE) code = E2BIG;
1109 outData[outSize]='\0';
1110 AFS_COPYOUT(outData, ablob->out, outSize, code);
1113 osi_FreeLargeSpace(outData);
1114 afs_PutFakeStat(&fakestate);
1115 return afs_CheckCode(code, &treq, 41);
1118 static PGetFID(avc, afun, areq, ain, aout, ainSize, aoutSize)
1121 struct vrequest *areq;
1124 afs_int32 *aoutSize; /* set this */ {
1125 register afs_int32 code;
1127 AFS_STATCNT(PGetFID);
1128 if (!avc) return EINVAL;
1129 memcpy(aout, (char *)&avc->fid, sizeof(struct VenusFid));
1130 *aoutSize = sizeof(struct VenusFid);
1134 static PSetAcl(avc, afun, areq, ain, aout, ainSize, aoutSize)
1137 struct vrequest *areq;
1140 afs_int32 *aoutSize; /* set this */ {
1141 register afs_int32 code;
1143 struct AFSOpaque acl;
1144 struct AFSVolSync tsync;
1145 struct AFSFetchStatus OutStatus;
1148 AFS_STATCNT(PSetAcl);
1151 if ((acl.AFSOpaque_len = strlen(ain)+1) > 1000)
1154 acl.AFSOpaque_val = ain;
1156 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1158 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1160 code = RXAFS_StoreACL(tconn->id, (struct AFSFid *) &avc->fid.Fid,
1161 &acl, &OutStatus, &tsync);
1167 (afs_Analyze(tconn, code, &avc->fid, areq,
1168 AFS_STATS_FS_RPCIDX_STOREACL, SHARED_LOCK, (struct cell *)0));
1170 /* now we've forgotten all of the access info */
1171 ObtainWriteLock(&afs_xcbhash, 455);
1173 afs_DequeueCallback(avc);
1174 avc->states &= ~(CStatd | CUnique);
1175 ReleaseWriteLock(&afs_xcbhash);
1176 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1177 osi_dnlc_purgedp(avc);
1181 int afs_defaultAsynchrony = 0;
1183 static PStoreBehind(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1186 struct vrequest *areq;
1189 afs_int32 *aoutSize; /* set this */
1190 struct AFS_UCRED *acred;
1193 struct sbstruct *sbr;
1195 sbr = (struct sbstruct *)ain;
1196 if (sbr->sb_default != -1) {
1197 if (afs_osi_suser(acred))
1198 afs_defaultAsynchrony = sbr->sb_default;
1202 if (avc && (sbr->sb_thisfile != -1)) {
1203 if (afs_AccessOK(avc, PRSFS_WRITE | PRSFS_ADMINISTER,
1204 areq, DONT_CHECK_MODE_BITS))
1205 avc->asynchrony = sbr->sb_thisfile;
1209 *aoutSize = sizeof(struct sbstruct);
1210 sbr = (struct sbstruct *)aout;
1211 sbr->sb_default = afs_defaultAsynchrony;
1213 sbr->sb_thisfile = avc->asynchrony;
1219 static PGCPAGs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1222 struct vrequest *areq;
1225 afs_int32 *aoutSize; /* set this */
1226 struct AFS_UCRED *acred;
1228 if (!afs_osi_suser(acred)) {
1231 afs_gcpags = AFS_GCPAGS_USERDISABLED;
1235 static PGetAcl(avc, afun, areq, ain, aout, ainSize, aoutSize)
1238 struct vrequest *areq;
1241 afs_int32 *aoutSize; /* set this */ {
1242 struct AFSOpaque acl;
1243 struct AFSVolSync tsync;
1244 struct AFSFetchStatus OutStatus;
1250 AFS_STATCNT(PGetAcl);
1251 if (!avc) return EINVAL;
1252 Fid.Volume = avc->fid.Fid.Volume;
1253 Fid.Vnode = avc->fid.Fid.Vnode;
1254 Fid.Unique = avc->fid.Fid.Unique;
1255 if (avc->states & CForeign) {
1257 * For a dfs xlator acl we have a special hack so that the
1258 * xlator will distinguish which type of acl will return. So
1259 * we currently use the top 2-bytes (vals 0-4) to tell which
1260 * type of acl to bring back. Horrible hack but this will
1261 * cause the least number of changes to code size and interfaces.
1263 if (Fid.Vnode & 0xc0000000)
1265 Fid.Vnode |= (ainSize << 30);
1267 acl.AFSOpaque_val = aout;
1269 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1272 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1274 code = RXAFS_FetchACL(tconn->id, &Fid,
1275 &acl, &OutStatus, &tsync);
1281 (afs_Analyze(tconn, code, &avc->fid, areq,
1282 AFS_STATS_FS_RPCIDX_FETCHACL,
1283 SHARED_LOCK, (struct cell *)0));
1286 *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1297 AFS_STATCNT(PBogus);
1301 static PGetFileCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1304 struct vrequest *areq;
1308 afs_int32 *aoutSize; /* set this */ {
1309 register struct cell *tcell;
1311 AFS_STATCNT(PGetFileCell);
1312 if (!avc) return EINVAL;
1313 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
1314 if (!tcell) return ESRCH;
1315 strcpy(aout, tcell->cellName);
1316 afs_PutCell(tcell, READ_LOCK);
1317 *aoutSize = strlen(aout) + 1;
1321 static PGetWSCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1324 struct vrequest *areq;
1328 afs_int32 *aoutSize; /* set this */ {
1329 register struct cell *tcell=0, *cellOne=0;
1330 register struct afs_q *cq, *tq;
1332 AFS_STATCNT(PGetWSCell);
1333 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1334 return EIO; /* Inappropriate ioctl for device */
1336 ObtainReadLock(&afs_xcell);
1337 cellOne = (struct cell *) 0;
1339 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
1340 tcell = QTOC(cq); tq = QNext(cq);
1341 if (tcell->states & CPrimary) break;
1342 if (tcell->cell == 1) cellOne = tcell;
1345 ReleaseReadLock(&afs_xcell);
1346 if (!tcell) { /* no primary cell, use cell #1 */
1347 if (!cellOne) return ESRCH;
1350 strcpy(aout, tcell->cellName);
1351 *aoutSize = strlen(aout) + 1;
1355 static PGetUserCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1358 struct vrequest *areq;
1362 afs_int32 *aoutSize; /* set this */ {
1363 register afs_int32 i;
1364 register struct unixuser *tu;
1365 register struct cell *tcell;
1367 AFS_STATCNT(PGetUserCell);
1368 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1369 return EIO; /* Inappropriate ioctl for device */
1371 /* return the cell name of the primary cell for this user */
1372 i = UHash(areq->uid);
1373 ObtainWriteLock(&afs_xuser,224);
1374 for(tu = afs_users[i]; tu; tu = tu->next) {
1375 if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1377 ReleaseWriteLock(&afs_xuser);
1382 tcell = afs_GetCell(tu->cell, READ_LOCK);
1383 afs_PutUser(tu, WRITE_LOCK);
1384 if (!tcell) return ESRCH;
1386 strcpy(aout, tcell->cellName);
1387 afs_PutCell(tcell, READ_LOCK);
1388 *aoutSize = strlen(aout)+1; /* 1 for the null */
1392 ReleaseWriteLock(&afs_xuser);
1399 static PSetTokens(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1402 struct vrequest *areq;
1406 afs_int32 *aoutSize; /* set this */
1407 struct AFS_UCRED **acred;
1410 register struct unixuser *tu;
1411 struct ClearToken clear;
1412 register struct cell *tcell;
1415 struct vrequest treq;
1416 afs_int32 flag, set_parent_pag = 0;
1418 AFS_STATCNT(PSetTokens);
1419 if (!afs_resourceinit_flag) {
1422 memcpy((char *)&i, ain, sizeof(afs_int32));
1423 ain += sizeof(afs_int32);
1424 stp = ain; /* remember where the ticket is */
1425 if (i < 0 || i > 2000) return EINVAL; /* malloc may fail */
1427 ain += i; /* skip over ticket */
1428 memcpy((char *)&i, ain, sizeof(afs_int32));
1429 ain += sizeof(afs_int32);
1430 if (i != sizeof(struct ClearToken)) {
1433 memcpy((char *)&clear, ain, sizeof(struct ClearToken));
1434 if (clear.AuthHandle == -1) clear.AuthHandle = 999; /* more rxvab compat stuff */
1435 ain += sizeof(struct ClearToken);
1436 if (ainSize != 2*sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1437 /* still stuff left? we've got primary flag and cell name. Set these */
1438 memcpy((char *)&flag, ain, sizeof(afs_int32)); /* primary id flag */
1439 ain += sizeof(afs_int32); /* skip id field */
1440 /* rest is cell name, look it up */
1441 /* some versions of gcc appear to need != 0 in order to get this right */
1442 if ((flag & 0x8000) != 0) { /* XXX Use Constant XXX */
1446 tcell = afs_GetCellByName(ain, READ_LOCK);
1455 /* default to cell 1, primary id */
1456 flag = 1; /* primary id */
1457 i = 1; /* cell number */
1458 tcell = afs_GetCell(1, READ_LOCK);
1459 if (!tcell) goto nocell;
1461 afs_PutCell(tcell, READ_LOCK);
1462 if (set_parent_pag) {
1464 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1465 #if defined(AFS_DARWIN_ENV)
1466 struct proc *p=current_proc(); /* XXX */
1468 struct proc *p=curproc; /* XXX */
1470 uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1471 p->p_pid, p->p_comm);
1472 if (!setpag(p, acred, -1, &pag, 1)) {
1475 if (!setpag(u.u_procp, acred, -1, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
1477 if (!setpag(acred, -1, &pag, 1)) {
1480 afs_InitReq(&treq, *acred);
1484 /* now we just set the tokens */
1485 tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1486 tu->vid = clear.ViceId;
1487 if (tu->stp != (char *) 0) {
1488 afs_osi_Free(tu->stp, tu->stLen);
1490 tu->stp = (char *) afs_osi_Alloc(stLen);
1492 memcpy(tu->stp, stp, stLen);
1495 afs_stats_cmfullperf.authent.TicketUpdates++;
1496 afs_ComputePAGStats();
1497 #endif /* AFS_NOSTATS */
1498 tu->states |= UHasTokens;
1499 tu->states &= ~UTokensBad;
1500 afs_SetPrimary(tu, flag);
1501 tu->tokenTime =osi_Time();
1502 afs_ResetUserConns(tu);
1503 afs_PutUser(tu, WRITE_LOCK);
1518 static PGetVolumeStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
1521 struct vrequest *areq;
1524 afs_int32 *aoutSize; /* set this */ {
1526 char offLineMsg[256];
1528 register struct conn *tc;
1529 register afs_int32 code;
1530 struct VolumeStatus volstat;
1532 char *Name, *OfflineMsg, *MOTD;
1535 AFS_STATCNT(PGetVolumeStatus);
1536 if (!avc) return EINVAL;
1538 OfflineMsg = offLineMsg;
1541 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1543 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1545 code = RXAFS_GetVolumeStatus(tc->id, avc->fid.Fid.Volume, &volstat,
1546 &Name, &OfflineMsg, &MOTD);
1552 (afs_Analyze(tc, code, &avc->fid, areq,
1553 AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1554 SHARED_LOCK, (struct cell *)0));
1556 if (code) return code;
1557 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1559 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1560 cp += sizeof(VolumeStatus);
1561 strcpy(cp, volName);
1562 cp += strlen(volName)+1;
1563 strcpy(cp, offLineMsg);
1564 cp += strlen(offLineMsg)+1;
1566 cp += strlen(motd)+1;
1567 *aoutSize = (cp - aout);
1571 static PSetVolumeStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
1574 struct vrequest *areq;
1577 afs_int32 *aoutSize; /* set this */ {
1579 char offLineMsg[256];
1581 register struct conn *tc;
1582 register afs_int32 code;
1583 struct AFSFetchVolumeStatus volstat;
1584 struct AFSStoreVolumeStatus storeStat;
1585 register struct volume *tvp;
1589 AFS_STATCNT(PSetVolumeStatus);
1590 if (!avc) return EINVAL;
1592 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
1594 if (tvp->states & (VRO | VBackup)) {
1595 afs_PutVolume(tvp, READ_LOCK);
1598 afs_PutVolume(tvp, READ_LOCK);
1601 /* Copy the junk out, using cp as a roving pointer. */
1603 memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
1604 cp += sizeof(AFSFetchVolumeStatus);
1605 if (strlen(cp) >= sizeof(volName))
1607 strcpy(volName, cp);
1608 cp += strlen(volName)+1;
1609 if (strlen(cp) >= sizeof(offLineMsg))
1611 strcpy(offLineMsg, cp);
1612 cp += strlen(offLineMsg)+1;
1613 if (strlen(cp) >= sizeof(motd))
1617 if (volstat.MinQuota != -1) {
1618 storeStat.MinQuota = volstat.MinQuota;
1619 storeStat.Mask |= AFS_SETMINQUOTA;
1621 if (volstat.MaxQuota != -1) {
1622 storeStat.MaxQuota = volstat.MaxQuota;
1623 storeStat.Mask |= AFS_SETMAXQUOTA;
1626 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1628 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1630 code = RXAFS_SetVolumeStatus(tc->id, avc->fid.Fid.Volume,
1631 &storeStat, volName, offLineMsg, motd);
1637 (afs_Analyze(tc, code, &avc->fid, areq,
1638 AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1639 SHARED_LOCK, (struct cell *)0));
1641 if (code) return code;
1642 /* we are sending parms back to make compat. with prev system. should
1643 change interface later to not ask for current status, just set new status */
1645 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1646 cp += sizeof(VolumeStatus);
1647 strcpy(cp, volName);
1648 cp += strlen(volName)+1;
1649 strcpy(cp, offLineMsg);
1650 cp += strlen(offLineMsg)+1;
1652 cp += strlen(motd)+1;
1653 *aoutSize = cp - aout;
1657 static PFlush(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1658 register struct vcache *avc;
1660 struct vrequest *areq;
1663 afs_int32 *aoutSize; /* set this */
1664 struct AFS_UCRED *acred;
1667 AFS_STATCNT(PFlush);
1668 if (!avc) return EINVAL;
1669 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1670 afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
1672 ObtainWriteLock(&avc->lock,225);
1673 ObtainWriteLock(&afs_xcbhash, 456);
1674 afs_DequeueCallback(avc);
1675 avc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
1676 ReleaseWriteLock(&afs_xcbhash);
1677 /* now find the disk cache entries */
1678 afs_TryToSmush(avc, acred, 1);
1679 osi_dnlc_purgedp(avc);
1680 afs_symhint_inval(avc);
1681 if (avc->linkData && !(avc->states & CCore)) {
1682 afs_osi_Free(avc->linkData, strlen(avc->linkData)+1);
1683 avc->linkData = (char *) 0;
1685 ReleaseWriteLock(&avc->lock);
1686 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1687 afs_BozonUnlock(&avc->pvnLock, avc);
1692 static PNewStatMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
1695 struct vrequest *areq;
1698 afs_int32 *aoutSize; /* set this */ {
1699 register afs_int32 code;
1700 register struct vcache *tvc;
1701 register struct dcache *tdc;
1702 struct VenusFid tfid;
1704 struct sysname_info sysState;
1705 afs_size_t offset, len;
1707 AFS_STATCNT(PNewStatMount);
1708 if (!avc) return EINVAL;
1709 code = afs_VerifyVCache(avc, areq);
1710 if (code) return code;
1711 if (vType(avc) != VDIR) {
1714 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
1715 if (!tdc) return ENOENT;
1716 Check_AtSys(avc, ain, &sysState, areq);
1717 ObtainReadLock(&tdc->lock);
1719 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
1720 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1721 ReleaseReadLock(&tdc->lock);
1722 afs_PutDCache(tdc); /* we're done with the data */
1723 bufp = sysState.name;
1727 tfid.Cell = avc->fid.Cell;
1728 tfid.Fid.Volume = avc->fid.Fid.Volume;
1729 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
1730 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
1732 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
1739 if (tvc->mvstat != 1) {
1740 afs_PutVCache(tvc, WRITE_LOCK);
1744 ObtainWriteLock(&tvc->lock,226);
1745 code = afs_HandleLink(tvc, areq);
1747 if (tvc->linkData) {
1748 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1751 /* we have the data */
1752 strcpy(aout, tvc->linkData);
1753 *aoutSize = strlen(tvc->linkData)+1;
1758 ReleaseWriteLock(&tvc->lock);
1759 afs_PutVCache(tvc, WRITE_LOCK);
1761 if (sysState.allocked) osi_FreeLargeSpace(bufp);
1765 static PGetTokens(avc, afun, areq, ain, aout, ainSize, aoutSize)
1768 struct vrequest *areq;
1771 afs_int32 *aoutSize; /* set this */ {
1772 register struct cell *tcell;
1773 register afs_int32 i;
1774 register struct unixuser *tu;
1779 AFS_STATCNT(PGetTokens);
1780 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1781 return EIO; /* Inappropriate ioctl for device */
1783 /* weird interface. If input parameter is present, it is an integer and
1784 we're supposed to return the parm'th tokens for this unix uid.
1785 If not present, we just return tokens for cell 1.
1786 If counter out of bounds, return EDOM.
1787 If no tokens for the particular cell, return ENOTCONN.
1788 Also, if this mysterious parm is present, we return, along with the
1789 tokens, the primary cell indicator (an afs_int32 0) and the cell name
1790 at the end, in that order.
1792 if (newStyle = (ainSize > 0)) {
1793 memcpy((char *)&iterator, ain, sizeof(afs_int32));
1795 i = UHash(areq->uid);
1796 ObtainReadLock(&afs_xuser);
1797 for(tu = afs_users[i]; tu; tu=tu->next) {
1799 if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1800 if (iterator-- == 0) break; /* are we done yet? */
1804 if (tu->uid == areq->uid && tu->cell == 1) break;
1809 * No need to hold a read lock on each user entry
1813 ReleaseReadLock(&afs_xuser);
1818 if (((tu->states & UHasTokens) == 0) || (tu->ct.EndTimestamp < osi_Time())) {
1819 tu->states |= (UTokensBad | UNeedsReset);
1820 afs_PutUser(tu, READ_LOCK);
1823 /* use iterator for temp */
1825 iterator = tu->stLen; /* for compat, we try to return 56 byte tix if they fit */
1826 if (iterator < 56) iterator = 56; /* # of bytes we're returning */
1827 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1828 cp += sizeof(afs_int32);
1829 memcpy(cp, tu->stp, tu->stLen); /* copy out st */
1831 iterator = sizeof(struct ClearToken);
1832 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1833 cp += sizeof(afs_int32);
1834 memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
1835 cp += sizeof(struct ClearToken);
1837 /* put out primary id and cell name, too */
1838 iterator = (tu->states & UPrimary ? 1 : 0);
1839 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1840 cp += sizeof(afs_int32);
1841 tcell = afs_GetCell(tu->cell, READ_LOCK);
1843 strcpy(cp, tcell->cellName);
1844 cp += strlen(tcell->cellName)+1;
1845 afs_PutCell(tcell, READ_LOCK);
1849 *aoutSize = cp - aout;
1850 afs_PutUser(tu, READ_LOCK);
1854 static PUnlog(avc, afun, areq, ain, aout, ainSize, aoutSize)
1857 struct vrequest *areq;
1860 afs_int32 *aoutSize; /* set this */ {
1861 register afs_int32 i;
1862 register struct unixuser *tu;
1864 AFS_STATCNT(PUnlog);
1865 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1866 return EIO; /* Inappropriate ioctl for device */
1868 i = UHash(areq->uid);
1869 ObtainWriteLock(&afs_xuser,227);
1870 for(tu=afs_users[i]; tu; tu=tu->next) {
1871 if (tu->uid == areq->uid) {
1873 tu->states &= ~UHasTokens;
1874 /* security is not having to say you're sorry */
1875 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
1877 ReleaseWriteLock(&afs_xuser);
1878 /* We have to drop the lock over the call to afs_ResetUserConns, since
1879 * it obtains the afs_xvcache lock. We could also keep the lock, and
1880 * modify ResetUserConns to take parm saying we obtained the lock
1881 * already, but that is overkill. By keeping the "tu" pointer
1882 * held over the released lock, we guarantee that we won't lose our
1883 * place, and that we'll pass over every user conn that existed when
1884 * we began this call.
1886 afs_ResetUserConns(tu);
1888 ObtainWriteLock(&afs_xuser,228);
1890 /* set the expire times to 0, causes
1891 * afs_GCUserData to remove this entry
1893 tu->ct.EndTimestamp = 0;
1895 #endif /* UKERNEL */
1898 ReleaseWriteLock(&afs_xuser);
1902 static PMariner(avc, afun, areq, ain, aout, ainSize, aoutSize)
1905 struct vrequest *areq;
1908 afs_int32 *aoutSize; /* set this */ {
1909 afs_int32 newHostAddr;
1910 afs_int32 oldHostAddr;
1912 AFS_STATCNT(PMariner);
1914 memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost, sizeof(afs_int32));
1916 oldHostAddr = 0xffffffff; /* disabled */
1918 memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
1919 if (newHostAddr == 0xffffffff) {
1920 /* disable mariner operations */
1923 else if (newHostAddr) {
1925 afs_marinerHost = newHostAddr;
1927 memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
1928 *aoutSize = sizeof(afs_int32);
1932 static PCheckServers(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1935 struct vrequest *areq;
1938 afs_int32 *aoutSize; /* set this */
1939 struct AFS_UCRED *acred;
1941 register char *cp = 0;
1943 register struct server *ts;
1944 afs_int32 temp, *lp = (afs_int32 *)ain, havecell=0;
1946 struct chservinfo *pcheck;
1948 AFS_STATCNT(PCheckServers);
1950 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1951 return EIO; /* Inappropriate ioctl for device */
1953 if (*lp == 0x12345678) { /* For afs3.3 version */
1954 pcheck=(struct chservinfo *)ain;
1955 if (pcheck->tinterval >= 0) {
1957 memcpy(cp, (char *)&PROBE_INTERVAL, sizeof(afs_int32));
1958 *aoutSize = sizeof(afs_int32);
1959 if (pcheck->tinterval > 0) {
1960 if (!afs_osi_suser(acred))
1962 PROBE_INTERVAL=pcheck->tinterval;
1968 temp=pcheck->tflags;
1969 cp = pcheck->tbuffer;
1970 } else { /* For pre afs3.3 versions */
1971 memcpy((char *)&temp, ain, sizeof(afs_int32));
1972 cp = ain+sizeof(afs_int32);
1973 if (ainSize > sizeof(afs_int32))
1978 * 1: fast check, don't contact servers.
1979 * 2: local cell only.
1982 /* have cell name, too */
1983 cellp = afs_GetCellByName(cp, READ_LOCK);
1984 if (!cellp) return ENOENT;
1986 else cellp = (struct cell *) 0;
1987 if (!cellp && (temp & 2)) {
1988 /* use local cell */
1989 cellp = afs_GetCell(1, READ_LOCK);
1991 if (!(temp & 1)) { /* if not fast, call server checker routine */
1992 afs_CheckServers(1, cellp); /* check down servers */
1993 afs_CheckServers(0, cellp); /* check up servers */
1995 /* now return the current down server list */
1997 ObtainReadLock(&afs_xserver);
1998 for(i=0;i<NSERVERS;i++) {
1999 for(ts = afs_servers[i]; ts; ts=ts->next) {
2000 if (cellp && ts->cell != cellp) continue; /* cell spec'd and wrong */
2001 if ((ts->flags & SRVR_ISDOWN) && ts->addr->sa_portal != ts->cell->vlport) {
2002 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2003 cp += sizeof(afs_int32);
2007 ReleaseReadLock(&afs_xserver);
2008 if (cellp) afs_PutCell(cellp, READ_LOCK);
2009 *aoutSize = cp - aout;
2013 static PCheckVolNames(avc, afun, areq, ain, aout, ainSize, aoutSize)
2016 struct vrequest *areq;
2019 afs_int32 *aoutSize; /* set this */ {
2020 AFS_STATCNT(PCheckVolNames);
2021 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2022 return EIO; /* Inappropriate ioctl for device */
2024 afs_CheckRootVolume();
2025 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE |
2026 AFS_VOLCHECK_EXPIRED |
2028 AFS_VOLCHECK_MTPTS);
2032 static PCheckAuth(avc, afun, areq, ain, aout, ainSize, aoutSize)
2035 struct vrequest *areq;
2038 afs_int32 *aoutSize; /* set this */ {
2042 struct unixuser *tu;
2044 extern afs_rwlock_t afs_xsrvAddr;
2046 AFS_STATCNT(PCheckAuth);
2047 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2048 return EIO; /* Inappropriate ioctl for device */
2051 tu = afs_GetUser(areq->uid, 1, READ_LOCK); /* check local cell authentication */
2052 if (!tu) retValue = EACCES;
2054 /* we have a user */
2055 ObtainReadLock(&afs_xsrvAddr);
2056 ObtainReadLock(&afs_xconn);
2058 /* any tokens set? */
2059 if ((tu->states & UHasTokens) == 0) retValue = EACCES;
2060 /* all connections in cell 1 working? */
2061 for(i=0;i<NSERVERS;i++) {
2062 for(sa = afs_srvAddrs[i]; sa; sa=sa->next_bkt) {
2063 for (tc = sa->conns; tc; tc=tc->next) {
2064 if (tc->user == tu && (tu->states & UTokensBad))
2069 ReleaseReadLock(&afs_xsrvAddr);
2070 ReleaseReadLock(&afs_xconn);
2071 afs_PutUser(tu, READ_LOCK);
2073 memcpy(aout, (char *)&retValue, sizeof(afs_int32));
2074 *aoutSize = sizeof(afs_int32);
2078 static Prefetch(apath, adata, afollow, acred)
2080 struct afs_ioctl *adata;
2082 struct AFS_UCRED *acred;
2085 register afs_int32 code;
2086 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2092 AFS_STATCNT(Prefetch);
2093 if (!apath) return EINVAL;
2094 tp = osi_AllocLargeSpace(1024);
2095 AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2097 osi_FreeLargeSpace(tp);
2100 if (afs_BBusy()) { /* do this as late as possible */
2101 osi_FreeLargeSpace(tp);
2102 return EWOULDBLOCK; /* pretty close */
2104 afs_BQueue(BOP_PATH, (struct vcache*)0, 0, 0, acred,
2105 (afs_size_t) 0, (afs_size_t) 0, tp);
2109 static PFindVolume(avc, afun, areq, ain, aout, ainSize, aoutSize)
2112 struct vrequest *areq;
2115 afs_int32 *aoutSize; /* set this */ {
2116 register struct volume *tvp;
2117 register struct server *ts;
2118 register afs_int32 i;
2121 AFS_STATCNT(PFindVolume);
2122 if (!avc) return EINVAL;
2123 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
2126 for(i=0;i<MAXHOSTS;i++) {
2127 ts = tvp->serverHost[i];
2129 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2130 cp += sizeof(afs_int32);
2133 /* still room for terminating NULL, add it on */
2134 ainSize = 0; /* reuse vbl */
2135 memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
2136 cp += sizeof(afs_int32);
2138 *aoutSize = cp - aout;
2139 afs_PutVolume(tvp, READ_LOCK);
2145 static PViceAccess(avc, afun, areq, ain, aout, ainSize, aoutSize)
2148 struct vrequest *areq;
2151 afs_int32 *aoutSize; /* set this */ {
2152 register afs_int32 code;
2155 AFS_STATCNT(PViceAccess);
2156 if (!avc) return EINVAL;
2157 code = afs_VerifyVCache(avc, areq);
2158 if (code) return code;
2159 memcpy((char *)&temp, ain, sizeof(afs_int32));
2160 code = afs_AccessOK(avc,temp, areq, CHECK_MODE_BITS);
2165 static PSetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2168 struct vrequest *areq;
2171 afs_int32 *aoutSize; /* set this */
2172 struct AFS_UCRED *acred;
2177 AFS_STATCNT(PSetCacheSize);
2178 if (!afs_osi_suser(acred))
2180 /* too many things are setup initially in mem cache version */
2181 if (cacheDiskType == AFS_FCACHE_TYPE_MEM) return EROFS;
2182 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2183 if (newValue == 0) afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2185 extern u_int afs_min_cache;
2186 if (newValue < afs_min_cache)
2187 afs_cacheBlocks = afs_min_cache;
2189 afs_cacheBlocks = newValue;
2191 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2192 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2193 afs_MaybeWakeupTruncateDaemon();
2194 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2195 afs_osi_Wait(1000, 0, 0);
2196 afs_MaybeWakeupTruncateDaemon();
2201 #define MAXGCSTATS 16
2202 static PGetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize)
2205 struct vrequest *areq;
2208 afs_int32 *aoutSize; /* set this */ {
2209 afs_int32 results[MAXGCSTATS];
2211 AFS_STATCNT(PGetCacheSize);
2212 memset((char *)results, 0, sizeof(results));
2213 results[0] = afs_cacheBlocks;
2214 results[1] = afs_blocksUsed;
2215 memcpy(aout, (char *)results, sizeof(results));
2216 *aoutSize = sizeof(results);
2220 static PRemoveCallBack(avc, afun, areq, ain, aout, ainSize, aoutSize)
2223 struct vrequest *areq;
2226 afs_int32 *aoutSize; /* set this */ {
2227 register struct conn *tc;
2228 register afs_int32 code;
2229 struct AFSCallBack CallBacks_Array[1];
2230 struct AFSCBFids theFids;
2231 struct AFSCBs theCBs;
2234 AFS_STATCNT(PRemoveCallBack);
2235 if (!avc) return EINVAL;
2236 if (avc->states & CRO) return 0; /* read-only-ness can't change */
2237 ObtainWriteLock(&avc->lock,229);
2238 theFids.AFSCBFids_len = 1;
2239 theCBs.AFSCBs_len = 1;
2240 theFids.AFSCBFids_val = (struct AFSFid *) &avc->fid.Fid;
2241 theCBs.AFSCBs_val = CallBacks_Array;
2242 CallBacks_Array[0].CallBackType = CB_DROPPED;
2243 if (avc->callback) {
2245 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2247 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2249 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2253 /* don't set code on failure since we wouldn't use it */
2255 (afs_Analyze(tc, code, &avc->fid, areq,
2256 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS,
2257 SHARED_LOCK, (struct cell *)0));
2259 ObtainWriteLock(&afs_xcbhash, 457);
2260 afs_DequeueCallback(avc);
2262 avc->states &= ~(CStatd | CUnique);
2263 ReleaseWriteLock(&afs_xcbhash);
2264 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2265 osi_dnlc_purgedp(avc);
2267 ReleaseWriteLock(&avc->lock);
2271 static PNewCell(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2274 struct vrequest *areq;
2278 struct AFS_UCRED *acred;
2279 afs_int32 *aoutSize; /* set this */ {
2280 /* create a new cell */
2281 afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic=0;
2282 register struct cell *tcell;
2283 char *newcell=0, *linkedcell=0, *tp= ain;
2284 register afs_int32 code, linkedstate=0, ls;
2285 u_short fsport = 0, vlport = 0;
2288 AFS_STATCNT(PNewCell);
2289 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2290 return EIO; /* Inappropriate ioctl for device */
2292 if (!afs_osi_suser(acred))
2295 memcpy((char *)&magic, tp, sizeof(afs_int32));
2296 tp += sizeof(afs_int32);
2297 if (magic != 0x12345678)
2300 /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2301 * server addresses while the 3.5 fs newcell command passes
2302 * MAXHOSTS. To figure out which is which, check if the cellname
2305 newcell = tp + (MAXCELLHOSTS+3)*sizeof(afs_int32);
2306 scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2308 /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2309 memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
2310 tp += (scount * sizeof(afs_int32));
2312 lp = (afs_int32 *)tp;
2315 if (fsport < 1024) fsport = 0; /* Privileged ports not allowed */
2316 if (vlport < 1024) vlport = 0; /* Privileged ports not allowed */
2317 tp += (3 * sizeof(afs_int32));
2319 if ((ls = *lp) & 1) {
2320 linkedcell = tp + strlen(newcell)+1;
2321 linkedstate |= CLinkedCell;
2324 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2325 code = afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport, vlport, (int)0, (char *) 0);
2329 static PNewAlias(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2332 struct vrequest *areq;
2336 struct AFS_UCRED *acred;
2337 afs_int32 *aoutSize; /* set this */
2339 /* create a new cell alias */
2340 register struct cell *tcell;
2342 register afs_int32 code;
2343 char *realName, *aliasName;
2344 register struct afs_q *cq, *tq;
2346 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2347 return EIO; /* Inappropriate ioctl for device */
2349 if (!afs_osi_suser(acred))
2353 tp += strlen(aliasName) + 1;
2357 * Prevent user from shooting themselves in the foot -- don't allow
2358 * creation of aliases when a real cell already exists with that name.
2360 ObtainReadLock(&afs_xcell);
2361 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2362 tcell = QTOC(cq); tq = QNext(cq);
2363 if ((afs_strcasecmp(tcell->cellName, aliasName) == 0) &&
2364 !(tcell->states & CAlias)) {
2365 ReleaseReadLock(&afs_xcell);
2369 ReleaseReadLock(&afs_xcell);
2371 code = afs_NewCell(aliasName, 0, CAlias, 0, 0, 0, 0, realName);
2376 static PListCells(avc, afun, areq, ain, aout, ainSize, aoutSize)
2379 struct vrequest *areq;
2382 afs_int32 *aoutSize; /* set this */ {
2383 afs_int32 whichCell;
2384 register struct cell *tcell=0;
2385 register afs_int32 i;
2386 register char *cp, *tp = ain;
2387 register struct afs_q *cq, *tq;
2389 AFS_STATCNT(PListCells);
2390 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2391 return EIO; /* Inappropriate ioctl for device */
2393 memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2394 tp += sizeof(afs_int32);
2395 tcell = afs_GetRealCellByIndex(whichCell, READ_LOCK, 0);
2398 memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
2399 for(i=0;i<MAXCELLHOSTS;i++) {
2400 if (tcell->cellHosts[i] == 0) break;
2401 memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip, sizeof(afs_int32));
2402 cp += sizeof(afs_int32);
2404 cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2405 strcpy(cp, tcell->cellName);
2406 cp += strlen(tcell->cellName)+1;
2407 *aoutSize = cp - aout;
2409 if (tcell) return 0;
2413 static PListAliases(avc, afun, areq, ain, aout, ainSize, aoutSize)
2416 struct vrequest *areq;
2419 afs_int32 *aoutSize; /* set this */
2421 afs_int32 whichAlias;
2422 register struct cell *tcell=0;
2423 register char *cp, *tp = ain;
2424 register struct afs_q *cq, *tq;
2426 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2427 return EIO; /* Inappropriate ioctl for device */
2428 if (ainSize < sizeof(afs_int32))
2431 memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2432 tp += sizeof(afs_int32);
2434 ObtainReadLock(&afs_xcell);
2435 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2436 tcell = QTOC(cq); tq = QNext(cq);
2437 if (!(tcell->states & CAlias)) {
2441 if (whichAlias == 0) break;
2447 strcpy(cp, tcell->cellName);
2448 cp += strlen(tcell->cellName)+1;
2449 strcpy(cp, tcell->realName);
2450 cp += strlen(tcell->realName)+1;
2451 *aoutSize = cp - aout;
2453 ReleaseReadLock(&afs_xcell);
2454 if (tcell) return 0;
2458 static PRemoveMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
2461 struct vrequest *areq;
2465 afs_int32 *aoutSize; /* set this */ {
2466 register afs_int32 code;
2468 struct sysname_info sysState;
2469 afs_size_t offset, len;
2470 register struct conn *tc;
2471 register struct dcache *tdc;
2472 register struct vcache *tvc;
2473 struct AFSFetchStatus OutDirStatus;
2474 struct VenusFid tfid;
2475 struct AFSVolSync tsync;
2479 /* "ain" is the name of the file in this dir to remove */
2481 AFS_STATCNT(PRemoveMount);
2482 if (!avc) return EINVAL;
2483 code = afs_VerifyVCache(avc, areq);
2484 if (code) return code;
2485 if (vType(avc) != VDIR) return ENOTDIR;
2487 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1); /* test for error below */
2488 if (!tdc) return ENOENT;
2489 Check_AtSys(avc, ain, &sysState, areq);
2490 ObtainReadLock(&tdc->lock);
2492 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
2493 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2494 ReleaseReadLock(&tdc->lock);
2495 bufp = sysState.name;
2500 tfid.Cell = avc->fid.Cell;
2501 tfid.Fid.Volume = avc->fid.Fid.Volume;
2502 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
2503 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
2505 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0,
2506 (struct vcache*)0/*xxx avc?*/, WRITE_LOCK);
2513 if (tvc->mvstat != 1) {
2515 afs_PutVCache(tvc, WRITE_LOCK);
2519 ObtainWriteLock(&tvc->lock,230);
2520 code = afs_HandleLink(tvc, areq);
2522 if (tvc->linkData) {
2523 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2528 ReleaseWriteLock(&tvc->lock);
2529 osi_dnlc_purgedp(tvc);
2530 afs_PutVCache(tvc, WRITE_LOCK);
2535 ObtainWriteLock(&avc->lock,231);
2536 osi_dnlc_remove(avc, bufp, tvc);
2538 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2540 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2542 code = RXAFS_RemoveFile(tc->id, (struct AFSFid *) &avc->fid.Fid,
2543 bufp, &OutDirStatus, &tsync);
2549 (afs_Analyze(tc, code, &avc->fid, areq,
2550 AFS_STATS_FS_RPCIDX_REMOVEFILE,
2551 SHARED_LOCK, (struct cell *)0));
2554 if (tdc) afs_PutDCache(tdc);
2555 ReleaseWriteLock(&avc->lock);
2559 /* we have the thing in the cache */
2560 ObtainWriteLock(&tdc->lock, 661);
2561 if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2562 /* we can do it locally */
2563 code = afs_dir_Delete(&tdc->f.inode, bufp);
2565 ZapDCE(tdc); /* surprise error -- invalid value */
2566 DZap(&tdc->f.inode);
2569 ReleaseWriteLock(&tdc->lock);
2570 afs_PutDCache(tdc); /* drop ref count */
2572 avc->states &= ~CUnique; /* For the dfs xlator */
2573 ReleaseWriteLock(&avc->lock);
2576 if (sysState.allocked) osi_FreeLargeSpace(bufp);
2580 static PVenusLogging(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2583 struct vrequest *areq;
2587 struct AFS_UCRED *acred;
2588 afs_int32 *aoutSize; /* set this */ {
2589 return EINVAL; /* OBSOLETE */
2592 static PGetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2595 struct vrequest *areq;
2598 afs_int32 *aoutSize; /* set this */ {
2599 register struct cell *tcell;
2602 AFS_STATCNT(PGetCellStatus);
2603 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2604 return EIO; /* Inappropriate ioctl for device */
2606 tcell = afs_GetCellByName(ain, READ_LOCK);
2607 if (!tcell) return ENOENT;
2608 temp = tcell->states;
2609 afs_PutCell(tcell, READ_LOCK);
2610 memcpy(aout, (char *)&temp, sizeof(afs_int32));
2611 *aoutSize = sizeof(afs_int32);
2615 static PSetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2618 struct vrequest *areq;
2621 struct AFS_UCRED *acred;
2622 afs_int32 *aoutSize; /* set this */ {
2623 register struct cell *tcell;
2626 if (!afs_osi_suser(acred))
2628 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2629 return EIO; /* Inappropriate ioctl for device */
2631 tcell = afs_GetCellByName(ain+2*sizeof(afs_int32), WRITE_LOCK);
2632 if (!tcell) return ENOENT;
2633 memcpy((char *)&temp, ain, sizeof(afs_int32));
2635 tcell->states |= CNoSUID;
2637 tcell->states &= ~CNoSUID;
2638 afs_PutCell(tcell, WRITE_LOCK);
2642 static PFlushVolumeData(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2645 struct vrequest *areq;
2648 afs_int32 *aoutSize; /* set this */
2649 struct AFS_UCRED *acred;
2651 extern struct volume *afs_volumes[NVOLS];
2652 register afs_int32 i;
2653 register struct dcache *tdc;
2654 register struct vcache *tvc;
2655 register struct volume *tv;
2656 afs_int32 cell, volume;
2658 AFS_STATCNT(PFlushVolumeData);
2661 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2662 return EIO; /* Inappropriate ioctl for device */
2664 volume = avc->fid.Fid.Volume; /* who to zap */
2665 cell = avc->fid.Cell;
2668 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
2669 * the vcaches associated with the volume.
2671 ObtainReadLock(&afs_xvcache);
2672 for(i = 0; i < VCSIZE; i++) {
2673 for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
2674 if (tvc->fid.Fid.Volume == volume && tvc->fid.Cell == cell) {
2675 #if defined(AFS_SGI_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
2676 VN_HOLD(AFSTOV(tvc));
2678 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2684 ReleaseReadLock(&afs_xvcache);
2685 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2686 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
2688 ObtainWriteLock(&tvc->lock,232);
2690 ObtainWriteLock(&afs_xcbhash, 458);
2691 afs_DequeueCallback(tvc);
2692 tvc->states &= ~(CStatd | CDirty);
2693 ReleaseWriteLock(&afs_xcbhash);
2694 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
2695 osi_dnlc_purgedp(tvc);
2696 afs_TryToSmush(tvc, acred, 1);
2697 ReleaseWriteLock(&tvc->lock);
2698 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2699 afs_BozonUnlock(&tvc->pvnLock, tvc);
2701 ObtainReadLock(&afs_xvcache);
2702 /* our tvc ptr is still good until now */
2707 ReleaseReadLock(&afs_xvcache);
2710 MObtainWriteLock(&afs_xdcache,328); /* needed if you're going to flush any stuff */
2711 for(i=0;i<afs_cacheFiles;i++) {
2712 if (!(afs_indexFlags[i] & IFEverUsed)) continue; /* never had any data */
2713 tdc = afs_GetDSlot(i, (struct dcache *) 0);
2714 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
2715 ReleaseReadLock(&tdc->tlock);
2716 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
2717 if (! (afs_indexFlags[i] & IFDataMod)) {
2718 /* if the file is modified, but has a ref cnt of only 1, then
2719 someone probably has the file open and is writing into it.
2720 Better to skip flushing such a file, it will be brought back
2721 immediately on the next write anyway.
2723 If we *must* flush, then this code has to be rearranged to call
2724 afs_storeAllSegments() first */
2725 afs_FlushDCache(tdc);
2729 ReleaseReadLock(&tdc->tlock);
2731 afs_PutDCache(tdc); /* bumped by getdslot */
2733 MReleaseWriteLock(&afs_xdcache);
2735 ObtainReadLock(&afs_xvolume);
2736 for (i=0;i<NVOLS;i++) {
2737 for (tv = afs_volumes[i]; tv; tv=tv->next) {
2738 if (tv->volume == volume) {
2739 afs_ResetVolumeInfo(tv);
2744 ReleaseReadLock(&afs_xvolume);
2746 /* probably, a user is doing this, probably, because things are screwed up.
2747 * maybe it's the dnlc's fault? */
2754 static PGetVnodeXStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2757 struct vrequest *areq;
2760 afs_int32 *aoutSize; /* set this */ {
2761 register afs_int32 code;
2762 struct vcxstat stat;
2765 /* AFS_STATCNT(PGetVnodeXStatus); */
2766 if (!avc) return EINVAL;
2767 code = afs_VerifyVCache(avc, areq);
2768 if (code) return code;
2769 if (vType(avc) == VDIR)
2770 mode = PRSFS_LOOKUP;
2773 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
2775 stat.fid = avc->fid;
2776 hset32(stat.DataVersion, hgetlo(avc->m.DataVersion));
2777 stat.lock = avc->lock;
2778 stat.parentVnode = avc->parentVnode;
2779 stat.parentUnique = avc->parentUnique;
2780 hset(stat.flushDV, avc->flushDV);
2781 hset(stat.mapDV, avc->mapDV);
2782 stat.truncPos = avc->truncPos;
2783 { /* just grab the first two - won't break anything... */
2784 struct axscache *ac;
2786 for (i=0, ac=avc->Access; ac && i < CPSIZE; i++, ac=ac->next) {
2787 stat.randomUid[i] = ac->uid;
2788 stat.randomAccess[i] = ac->axess;
2791 stat.callback = afs_data_pointer_to_int32(avc->callback);
2792 stat.cbExpires = avc->cbExpires;
2793 stat.anyAccess = avc->anyAccess;
2794 stat.opens = avc->opens;
2795 stat.execsOrWriters = avc->execsOrWriters;
2796 stat.flockCount = avc->flockCount;
2797 stat.mvstat = avc->mvstat;
2798 stat.states = avc->states;
2799 memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
2800 *aoutSize = sizeof(struct vcxstat);
2805 /* We require root for local sysname changes, but not for remote */
2806 /* (since we don't really believe remote uids anyway) */
2807 /* outname[] shouldn't really be needed- this is left as an excercise */
2808 /* for the reader. */
2809 static PSetSysName(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2812 struct vrequest *areq;
2815 afs_int32 *aoutSize; /* set this */
2816 register struct AFS_UCRED *acred;
2818 char *cp, inname[MAXSYSNAME], outname[MAXSYSNAME];
2819 int setsysname, foundname=0;
2820 register struct afs_exporter *exporter;
2821 extern struct unixuser *afs_FindUser();
2822 extern char *afs_sysname;
2823 extern char *afs_sysnamelist[];
2824 extern int afs_sysnamecount;
2825 register struct unixuser *au;
2826 register afs_int32 pag, error;
2830 AFS_STATCNT(PSetSysName);
2831 if (!afs_globalVFS) {
2832 /* Afsd is NOT running; disable it */
2833 #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)
2836 return (setuerror(EINVAL), EINVAL);
2839 memset(inname, 0, MAXSYSNAME);
2840 memcpy((char *)&setsysname, ain, sizeof(afs_int32));
2841 ain += sizeof(afs_int32);
2845 if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
2847 for(cp = ain,count = 0;count < setsysname;count++) {
2848 /* won't go past end of ain since maxsysname*num < ain length */
2850 if (t >= MAXSYSNAME || t <= 0)
2852 /* check for names that can shoot us in the foot */
2853 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
2859 /* inname gets first entry in case we're being a translater */
2861 memcpy(inname, ain, t+1); /* include terminating null */
2864 if (acred->cr_gid == RMTUSER_REQ) { /* Handles all exporters */
2865 pag = PagInCred(acred);
2867 return EINVAL; /* Better than panicing */
2869 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
2870 return EINVAL; /* Better than panicing */
2872 if (!(exporter = au->exporter)) {
2873 afs_PutUser(au, READ_LOCK);
2874 return EINVAL; /* Better than panicing */
2876 error = EXP_SYSNAME(exporter, (setsysname? inname : (char *)0), outname);
2878 if (error == ENODEV) foundname = 0; /* sysname not set yet! */
2880 afs_PutUser(au, READ_LOCK);
2885 afs_PutUser(au, READ_LOCK);
2888 /* Not xlating, so local case */
2889 if (!afs_sysname) osi_Panic("PSetSysName: !afs_sysname\n");
2890 if (!setsysname) { /* user just wants the info */
2891 strcpy(outname, afs_sysname);
2892 foundname = afs_sysnamecount;
2893 } else { /* Local guy; only root can change sysname */
2894 if (!afs_osi_suser(acred))
2897 /* clear @sys entries from the dnlc, once afs_lookup can
2898 do lookups of @sys entries and thinks it can trust them */
2899 /* privs ok, store the entry, ... */
2900 strcpy(afs_sysname, inname);
2901 if (setsysname > 1) { /* ... or list */
2903 for(count=1; count < setsysname;++count) {
2904 if (!afs_sysnamelist[count])
2905 osi_Panic("PSetSysName: no afs_sysnamelist entry to write\n");
2907 memcpy(afs_sysnamelist[count], cp, t+1); /* include null */
2911 afs_sysnamecount = setsysname;
2915 cp = aout; /* not changing so report back the count and ... */
2916 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
2917 cp += sizeof(afs_int32);
2919 strcpy(cp, outname); /* ... the entry, ... */
2920 cp += strlen(outname)+1;
2921 for(count=1; count < foundname; ++count) { /* ... or list. */
2922 /* Note: we don't support @sys lists for exporters */
2923 if (!afs_sysnamelist[count])
2924 osi_Panic("PSetSysName: no afs_sysnamelist entry to read\n");
2925 t = strlen(afs_sysnamelist[count]);
2926 if (t >= MAXSYSNAME)
2927 osi_Panic("PSetSysName: sysname entry garbled\n");
2928 strcpy(cp, afs_sysnamelist[count]);
2932 *aoutSize = cp - aout;
2937 /* sequential search through the list of touched cells is not a good
2938 * long-term solution here. For small n, though, it should be just
2939 * fine. Should consider special-casing the local cell for large n.
2940 * Likewise for PSetSPrefs.
2942 static void ReSortCells(s,l, vlonly)
2943 int s; /* number of ids in array l[] -- NOT index of last id */
2944 afs_int32 l[]; /* array of cell ids which have volumes that need to be sorted */
2945 int vlonly; /* sort vl servers or file servers?*/
2947 extern struct volume *afs_volumes[NVOLS]; /* volume hash table */
2955 ObtainWriteLock(&afs_xcell,300);
2957 tcell = afs_GetCellNoLock(l[k], WRITE_LOCK);
2958 if (!tcell) continue;
2959 afs_SortServers(tcell->cellHosts, MAXCELLHOSTS);
2960 afs_PutCell(tcell, WRITE_LOCK);
2962 ReleaseWriteLock(&afs_xcell);
2966 ObtainReadLock(&afs_xvolume);
2967 for (i= 0; i< NVOLS; i++) {
2968 for (j=afs_volumes[i];j;j=j->next) {
2970 if (j->cell == l[k]) {
2971 ObtainWriteLock(&j->lock,233);
2972 afs_SortServers(j->serverHost, MAXHOSTS);
2973 ReleaseWriteLock(&j->lock);
2978 ReleaseReadLock(&afs_xvolume);
2983 static int afs_setsprefs(sp, num, vlonly)
2986 unsigned int vlonly;
2989 int i,j,k,matches,touchedSize;
2990 struct server *srvr = NULL;
2991 afs_int32 touched[34];
2995 for (k=0; k < num; sp++, k++) {
2997 printf ("sp host=%x, rank=%d\n",sp->host.s_addr, sp->rank);
3000 ObtainReadLock(&afs_xserver);
3002 i = SHash(sp->host.s_addr);
3003 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
3004 if (sa->sa_ip == sp->host.s_addr) {
3006 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3007 || (sa->sa_portal == AFS_FSPORT);
3008 if ((!vlonly && isfs) || (vlonly && !isfs)) {
3015 if (sa && matches) { /* found one! */
3017 printf ("sa ip=%x, ip_rank=%d\n",sa->sa_ip, sa->sa_iprank);
3019 sa->sa_iprank = sp->rank + afs_randomMod15();
3020 afs_SortOneServer(sa->server);
3023 /* if we don't know yet what cell it's in, this is moot */
3024 for (j=touchedSize-1; j>=0 && touched[j] != srvr->cell->cell; j--)
3025 /* is it in our list of touched cells ? */ ;
3026 if (j < 0) { /* no, it's not */
3027 touched[touchedSize++] = srvr->cell->cell;
3028 if (touchedSize >= 32) { /* watch for ovrflow */
3029 ReleaseReadLock(&afs_xserver);
3030 ReSortCells(touchedSize, touched, vlonly);
3032 ObtainReadLock(&afs_xserver);
3038 ReleaseReadLock(&afs_xserver);
3039 /* if we didn't find one, start to create one. */
3040 /* Note that it doesn't have a cell yet... */
3042 afs_uint32 temp = sp->host.s_addr;
3043 srvr = afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
3044 WRITE_LOCK, (afsUUID *)0,0);
3045 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3046 afs_PutServer(srvr, WRITE_LOCK);
3048 } /* for all cited preferences */
3050 ReSortCells(touchedSize, touched, vlonly);
3054 /* Note that this may only be performed by the local root user.
3057 PSetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3060 struct vrequest *areq;
3063 struct AFS_UCRED *acred;
3064 afs_int32 *aoutSize;
3066 struct setspref *ssp;
3067 AFS_STATCNT(PSetSPrefs);
3069 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3070 return EIO; /* Inappropriate ioctl for device */
3072 if (!afs_osi_suser(acred))
3075 if (ainSize < sizeof(struct setspref))
3078 ssp = (struct setspref *)ain;
3079 if (ainSize < sizeof(struct spref)*ssp->num_servers)
3082 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
3083 (ssp->flags & DBservers));
3088 PSetSPrefs33(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3091 struct vrequest *areq;
3094 struct AFS_UCRED *acred;
3095 afs_int32 *aoutSize;
3098 AFS_STATCNT(PSetSPrefs);
3099 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3100 return EIO; /* Inappropriate ioctl for device */
3103 if (!afs_osi_suser(acred))
3106 sp = (struct spref *)ain;
3107 afs_setsprefs(sp, ainSize/(sizeof(struct spref)), 0 /*!vlonly*/);
3111 /* some notes on the following code...
3112 * in the hash table of server structs, all servers with the same IP address
3113 * will be on the same overflow chain.
3114 * This could be sped slightly in some circumstances by having it cache the
3115 * immediately previous slot in the hash table and some supporting information
3116 * Only reports file servers now.
3119 PGetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3122 struct vrequest *areq;
3125 afs_int32 *aoutSize;
3127 struct sprefrequest *spin; /* input */
3128 struct sprefinfo *spout; /* output */
3129 struct spref *srvout; /* one output component */
3130 int i,j; /* counters for hash table traversal */
3131 struct server *srvr; /* one of CM's server structs */
3134 int vlonly; /* just return vlservers ? */
3137 AFS_STATCNT(PGetSPrefs);
3138 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3139 return EIO; /* Inappropriate ioctl for device */
3142 if (ainSize < sizeof (struct sprefrequest_33)) {
3146 spin = ((struct sprefrequest *) ain);
3149 if (ainSize > sizeof (struct sprefrequest_33)) {
3150 vlonly = (spin->flags & DBservers);
3154 /* struct sprefinfo includes 1 server struct... that size gets added
3155 * in during the loop that follows.
3157 *aoutSize = sizeof(struct sprefinfo) - sizeof (struct spref);
3158 spout = (struct sprefinfo *) aout;
3159 spout->next_offset = spin->offset;
3160 spout->num_servers = 0;
3161 srvout = spout->servers;
3163 ObtainReadLock(&afs_xserver);
3164 for (i=0, j=0; j < NSERVERS; j++) { /* sift through hash table */
3165 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3166 if (spin->offset > (unsigned short)i) {
3167 continue; /* catch up to where we left off */
3169 spout->next_offset++;
3172 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3173 || (sa->sa_portal == AFS_FSPORT);
3175 if ((vlonly && isfs) || (!vlonly && !isfs)) {
3176 /* only report ranks for vl servers */
3180 srvout->host.s_addr = sa->sa_ip;
3181 srvout->rank = sa->sa_iprank;
3182 *aoutSize += sizeof(struct spref);
3183 spout->num_servers++;
3186 if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3187 ReleaseReadLock(&afs_xserver); /* no more room! */
3192 ReleaseReadLock(&afs_xserver);
3194 spout->next_offset = 0; /* start over from the beginning next time */
3198 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3199 int afs_NFSRootOnly = 1;
3200 /*static*/ PExportAfs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3203 struct vrequest *areq;
3206 afs_int32 *aoutSize; /* set this */
3207 struct AFS_UCRED *acred;
3209 afs_int32 export, newint=0, type, changestate, handleValue, convmode, pwsync, smounts;
3210 extern struct afs_exporter *exporter_find();
3211 register struct afs_exporter *exporter;
3213 AFS_STATCNT(PExportAfs);
3214 memcpy((char *)&handleValue, ain, sizeof(afs_int32));
3215 type = handleValue >> 24;
3220 exporter = exporter_find(type);
3222 export = handleValue & 3;
3223 changestate = handleValue & 0xff;
3224 smounts = (handleValue >> 2) & 3;
3225 pwsync = (handleValue >> 4) & 3;
3226 convmode = (handleValue >> 6) & 3;
3228 changestate = (handleValue >> 16) & 0x1;
3229 convmode = (handleValue >> 16) & 0x2;
3230 pwsync = (handleValue >> 16) & 0x4;
3231 smounts = (handleValue >> 16) & 0x8;
3232 export = handleValue & 0xff;
3235 /* Failed finding desired exporter; */
3239 handleValue = exporter->exp_states;
3240 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3241 *aoutSize = sizeof(afs_int32);
3243 if (!afs_osi_suser(acred))
3244 return EACCES; /* Only superuser can do this */
3248 exporter->exp_states |= EXP_EXPORTED;
3250 exporter->exp_states &= ~EXP_EXPORTED;
3254 exporter->exp_states |= EXP_UNIXMODE;
3256 exporter->exp_states &= ~EXP_UNIXMODE;
3260 exporter->exp_states |= EXP_PWSYNC;
3262 exporter->exp_states &= ~EXP_PWSYNC;
3266 afs_NFSRootOnly = 0;
3267 exporter->exp_states |= EXP_SUBMOUNTS;
3269 afs_NFSRootOnly = 1;
3270 exporter->exp_states &= ~EXP_SUBMOUNTS;
3273 handleValue = exporter->exp_states;
3274 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3275 *aoutSize = sizeof(afs_int32);
3278 exporter->exp_states |= EXP_EXPORTED;
3280 exporter->exp_states &= ~EXP_EXPORTED;
3282 exporter->exp_states |= EXP_UNIXMODE;
3284 exporter->exp_states &= ~EXP_UNIXMODE;
3286 exporter->exp_states |= EXP_PWSYNC;
3288 exporter->exp_states &= ~EXP_PWSYNC;
3290 afs_NFSRootOnly = 0;
3291 exporter->exp_states |= EXP_SUBMOUNTS;
3293 afs_NFSRootOnly = 1;
3294 exporter->exp_states &= ~EXP_SUBMOUNTS;
3303 PGag(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3306 struct vrequest *areq;
3309 struct AFS_UCRED *acred;
3310 afs_int32 *aoutSize; /* set this */
3312 struct gaginfo *gagflags;
3314 if (!afs_osi_suser(acred))
3317 gagflags = (struct gaginfo *) ain;
3318 afs_showflags = gagflags->showflags;
3325 PTwiddleRx(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3328 struct vrequest *areq;
3331 struct AFS_UCRED *acred;
3332 afs_int32 *aoutSize;
3334 struct rxparams *rxp;
3336 if (!afs_osi_suser(acred))
3339 rxp = (struct rxparams *) ain;
3341 if (rxp->rx_initReceiveWindow)
3342 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3343 if (rxp->rx_maxReceiveWindow)
3344 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3345 if (rxp->rx_initSendWindow)
3346 rx_initSendWindow = rxp->rx_initSendWindow;
3347 if (rxp->rx_maxSendWindow)
3348 rx_maxSendWindow = rxp->rx_maxSendWindow;
3349 if (rxp->rxi_nSendFrags)
3350 rxi_nSendFrags = rxp->rxi_nSendFrags;
3351 if (rxp->rxi_nRecvFrags)
3352 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3353 if (rxp->rxi_OrphanFragSize)
3354 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3355 if (rxp->rx_maxReceiveSize)
3357 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3358 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3360 if (rxp->rx_MyMaxSendSize)
3361 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3366 static int PGetInitParams(avc, afun, areq, ain, aout, ainSize, aoutSize)
3369 struct vrequest *areq;
3373 afs_int32 *aoutSize; /* set this */
3375 if (sizeof(struct cm_initparams) > PIGGYSIZE)
3378 memcpy(aout, (char*)&cm_initParams, sizeof(struct cm_initparams));
3379 *aoutSize = sizeof(struct cm_initparams);
3383 #ifdef AFS_SGI65_ENV
3384 /* They took crget() from us, so fake it. */
3385 static cred_t *crget(void)
3388 cr = crdup(get_current_cred());
3389 memset((char*)cr, 0, sizeof(cred_t));
3390 #if CELL || CELL_PREPARE
3398 PGetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3401 struct vrequest *areq;
3404 afs_int32 *aoutSize;
3405 struct AFS_UCRED *acred;
3407 memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3408 *aoutSize=sizeof(afs_int32);
3413 PSetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3416 struct vrequest *areq;
3419 afs_int32 *aoutSize;
3420 struct AFS_UCRED *acred;
3424 if (!afs_osi_suser(acred))
3426 if (ainSize != sizeof(afs_int32) || ain == NULL)
3428 memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3429 /* if new mappings added later this will need to be changed */
3430 if (tmpval != 0 && tmpval != 1)
3437 * Create new credentials to correspond to a remote user with given
3438 * <hostaddr, uid, g0, g1>. This allows a server running as root to
3439 * provide pioctl (and other) services to foreign clients (i.e. nfs
3440 * clients) by using this call to `become' the client.
3443 #define PIOCTL_HEADER 6
3444 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3447 afs_uint32 hostaddr;
3448 afs_int32 uid, g0, g1, i, code, pag, exporter_type;
3449 extern struct afs_exporter *exporter_find();
3450 struct afs_exporter *exporter, *outexporter;
3451 struct AFS_UCRED *newcred;
3452 struct unixuser *au;
3454 #if defined(AFS_DEC_ENV) || (defined(AFS_NONFSTRANS) && !defined(AFS_AIX_IAUTH_ENV))
3455 return EINVAL; /* NFS trans not supported for Ultrix */
3457 #if defined(AFS_SGIMP_ENV)
3458 osi_Assert(ISAFS_GLOCK());
3460 AFS_STATCNT(HandleClientContext);
3461 if (ablob->in_size < PIOCTL_HEADER*sizeof(afs_int32)) {
3462 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3463 return EINVAL; /* Too small to be good */
3465 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3466 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER*sizeof(afs_int32), code);
3468 osi_FreeLargeSpace(inData);
3472 /* Extract information for remote user */
3473 hostaddr = *((afs_uint32 *)ain);
3474 ain += sizeof(hostaddr);
3475 uid = *((afs_uint32 *)ain);
3477 g0 = *((afs_uint32 *)ain);
3479 g1 = *((afs_uint32 *)ain);
3481 *com = *((afs_uint32 *)ain);
3482 ain += sizeof(afs_int32);
3483 exporter_type = *((afs_uint32 *)ain); /* In case we support more than NFS */
3486 * Of course, one must be root for most of these functions, but
3487 * we'll allow (for knfs) you to set things if the pag is 0 and
3488 * you're setting tokens or unlogging.
3491 if (!afs_osi_suser(credp)) {
3493 #ifndef AFS_SGI64_ENV
3494 /* Since SGI's suser() returns explicit failure after the call.. */
3498 /* check for acceptable opcodes for normal folks, which are, so far,
3499 * set tokens and unlog.
3501 if (i != 9 && i != 3 && i != 38 && i != 8) {
3502 osi_FreeLargeSpace(inData);
3507 ablob->in_size -= PIOCTL_HEADER*sizeof(afs_int32);
3508 ablob->in += PIOCTL_HEADER*sizeof(afs_int32);
3509 osi_FreeLargeSpace(inData);
3512 * We map uid 0 to nobody to match the mapping that the nfs
3513 * server does and to ensure that the suser() calls in the afs
3514 * code fails for remote client roots.
3516 uid = afs_nobody; /* NFS_NOBODY == -2 */
3519 #ifdef AFS_AIX41_ENV
3522 newcred->cr_gid = RMTUSER_REQ;
3523 newcred->cr_groups[0] = g0;
3524 newcred->cr_groups[1] = g1;
3526 newcred->cr_ngrps = 2;
3528 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)
3529 newcred->cr_ngroups = 2;
3531 for (i=2; i<NGROUPS; i++)
3532 newcred->cr_groups[i] = NOGROUP;
3535 #if !defined(AFS_OSF_ENV) && !defined(AFS_DEC_ENV)
3536 afs_nfsclient_init(); /* before looking for exporter, ensure one exists */
3538 if (!(exporter = exporter_find(exporter_type))) {
3539 /* Exporter wasn't initialized or an invalid exporter type */
3543 if (exporter->exp_states & EXP_PWSYNC) {
3544 if (uid != credp->cr_uid) {
3546 return ENOEXEC; /* XXX Find a better errno XXX */
3549 newcred->cr_uid = uid; /* Only temporary */
3550 code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
3551 /* The client's pag is the only unique identifier for it */
3552 newcred->cr_uid = pag;
3554 if (!code && *com == PSETPAG) {
3555 /* Special case for 'setpag' */
3556 afs_uint32 pagvalue = genpag();
3558 au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
3560 * Note that we leave the 'outexporter' struct held so it won't
3563 au->exporter = outexporter;
3564 if (ablob->out_size >= 4) {
3565 AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32), code);
3567 afs_PutUser(au, WRITE_LOCK);
3568 if (code) return code;
3569 return PSETPAG; /* Special return for setpag */
3571 EXP_RELE(outexporter);
3574 #endif /*defined(AFS_DEC_ENV) || defined(AFS_NONFSTRANS)*/
3577 /* get all interface addresses of this client */
3580 PGetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3583 struct vrequest *areq;
3586 afs_int32 *aoutSize;
3588 struct sprefrequest *spin; /* input */
3589 struct sprefinfo *spout; /* output */
3590 struct spref *srvout; /* one output component */
3594 AFS_STATCNT(PGetCPrefs);
3595 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3596 return EIO; /* Inappropriate ioctl for device */
3598 if ( ainSize < sizeof (struct sprefrequest ))
3601 spin = (struct sprefrequest *) ain;
3602 spout = (struct sprefinfo *) aout;
3604 maxNumber = spin->num_servers; /* max addrs this time */
3605 srvout = spout->servers;
3607 ObtainReadLock(&afs_xinterface);
3609 /* copy out the client interface information from the
3610 ** kernel data structure "interface" to the output buffer
3612 for ( i=spin->offset, j=0; (i < afs_cb_interface.numberOfInterfaces)
3613 && ( j< maxNumber) ; i++, j++, srvout++)
3614 srvout->host.s_addr = afs_cb_interface.addr_in[i];
3616 spout->num_servers = j;
3617 *aoutSize = sizeof(struct sprefinfo) +(j-1)* sizeof (struct spref);
3619 if ( i >= afs_cb_interface.numberOfInterfaces )
3620 spout->next_offset = 0; /* start from beginning again */
3622 spout->next_offset = spin->offset + j;
3624 ReleaseReadLock(&afs_xinterface);
3629 PSetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3632 struct vrequest *areq;
3635 afs_int32 *aoutSize;
3637 struct setspref *sin;
3640 AFS_STATCNT(PSetCPrefs);
3641 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3642 return EIO; /* Inappropriate ioctl for device */
3644 sin = (struct setspref *)ain;
3646 if ( ainSize < sizeof(struct setspref) )
3648 #if 0 /* num_servers is unsigned */
3649 if ( sin->num_servers < 0 )
3652 if ( sin->num_servers > AFS_MAX_INTERFACE_ADDR)
3655 ObtainWriteLock(&afs_xinterface, 412);
3656 afs_cb_interface.numberOfInterfaces = sin->num_servers;
3657 for ( i=0; (unsigned short)i < sin->num_servers; i++)
3658 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
3660 ReleaseWriteLock(&afs_xinterface);
3664 static PFlushMount(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3667 struct vrequest *areq;
3670 afs_int32 *aoutSize;
3671 struct AFS_UCRED *acred; {
3672 register afs_int32 code;
3673 register struct vcache *tvc;
3674 register struct dcache *tdc;
3675 struct VenusFid tfid;
3677 struct sysname_info sysState;
3678 afs_size_t offset, len;
3680 AFS_STATCNT(PFlushMount);
3681 if (!avc) return EINVAL;
3682 code = afs_VerifyVCache(avc, areq);
3683 if (code) return code;
3684 if (vType(avc) != VDIR) {
3687 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
3688 if (!tdc) return ENOENT;
3689 Check_AtSys(avc, ain, &sysState, areq);
3690 ObtainReadLock(&tdc->lock);
3692 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
3693 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
3694 ReleaseReadLock(&tdc->lock);
3695 afs_PutDCache(tdc); /* we're done with the data */
3696 bufp = sysState.name;
3700 tfid.Cell = avc->fid.Cell;
3701 tfid.Fid.Volume = avc->fid.Fid.Volume;
3702 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
3703 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
3705 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
3712 if (tvc->mvstat != 1) {
3713 afs_PutVCache(tvc, WRITE_LOCK);
3717 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3718 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3720 ObtainWriteLock(&tvc->lock,649);
3721 ObtainWriteLock(&afs_xcbhash, 650);
3722 afs_DequeueCallback(tvc);
3723 tvc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
3724 ReleaseWriteLock(&afs_xcbhash);
3725 /* now find the disk cache entries */
3726 afs_TryToSmush(tvc, acred, 1);
3727 osi_dnlc_purgedp(tvc);
3728 afs_symhint_inval(tvc);
3729 if (tvc->linkData && !(tvc->states & CCore)) {
3730 afs_osi_Free(tvc->linkData, strlen(tvc->linkData)+1);
3731 tvc->linkData = (char *) 0;
3733 ReleaseWriteLock(&tvc->lock);
3734 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3735 afs_BozonUnlock(&tvc->pvnLock, tvc);
3737 afs_PutVCache(tvc, WRITE_LOCK);
3739 if (sysState.allocked) osi_FreeLargeSpace(bufp);
3743 static PRxStatProc(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3746 struct vrequest *areq;
3749 afs_int32 *aoutSize;
3750 struct AFS_UCRED *acred;
3755 if (!afs_osi_suser(acred)) {
3759 if (ainSize != sizeof(afs_int32)) {
3763 memcpy((char *)&flags, ain, sizeof(afs_int32));
3764 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3768 if (flags & AFSCALL_RXSTATS_ENABLE) {
3769 rx_enableProcessRPCStats();
3771 if (flags & AFSCALL_RXSTATS_DISABLE) {
3772 rx_disableProcessRPCStats();
3774 if (flags & AFSCALL_RXSTATS_CLEAR) {
3775 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
3783 static PRxStatPeer(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3786 struct vrequest *areq;
3789 afs_int32 *aoutSize;
3790 struct AFS_UCRED *acred;
3795 if (!afs_osi_suser(acred)) {
3799 if (ainSize != sizeof(afs_int32)) {
3803 memcpy((char *)&flags, ain, sizeof(afs_int32));
3804 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3808 if (flags & AFSCALL_RXSTATS_ENABLE) {
3809 rx_enablePeerRPCStats();
3811 if (flags & AFSCALL_RXSTATS_DISABLE) {
3812 rx_disablePeerRPCStats();
3814 if (flags & AFSCALL_RXSTATS_CLEAR) {
3815 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
3822 static PPrefetchFromTape(avc, afun, areq, ain, aout, ainSize, aoutSize)
3825 struct vrequest *areq;
3828 afs_int32 *aoutSize; /* set this */
3830 register afs_int32 code, code1;
3833 struct rx_call *tcall;
3834 struct AFSVolSync tsync;
3835 struct AFSFetchStatus OutStatus;
3836 struct AFSCallBack CallBack;
3837 struct VenusFid tfid;
3842 AFS_STATCNT(PSetAcl);
3846 if (ain && (ainSize == 3 * sizeof(afs_int32)))
3847 Fid = (struct AFSFid *) ain;
3849 Fid = &avc->fid.Fid;
3850 tfid.Cell = avc->fid.Cell;
3851 tfid.Fid.Volume = Fid->Volume;
3852 tfid.Fid.Vnode = Fid->Vnode;
3853 tfid.Fid.Unique = Fid->Unique;
3855 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
3858 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3859 ICL_TYPE_POINTER, tvc,
3860 ICL_TYPE_FID, &tfid,
3861 ICL_TYPE_FID, &avc->fid);
3864 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3865 ICL_TYPE_POINTER, tvc,
3866 ICL_TYPE_FID, &tfid,
3867 ICL_TYPE_FID, &tvc->fid);
3870 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3874 tcall = rx_NewCall(tc->id);
3875 code = StartRXAFS_FetchData(tcall,
3876 (struct AFSFid *) &tvc->fid.Fid, 0, 0);
3878 bytes = rx_Read(tcall, (char *) aout, sizeof(afs_int32));
3879 code = EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
3881 code1 = rx_EndCall(tcall, code);
3886 (afs_Analyze(tc, code, &tvc->fid, areq,
3887 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
3889 /* This call is done only to have the callback things handled correctly */
3890 afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
3891 afs_PutVCache(tvc, WRITE_LOCK);
3894 *aoutSize = sizeof(afs_int32);
3899 static PResidencyCmd(avc, afun, areq, ain, aout, ainSize, aoutSize)
3902 struct vrequest *areq;
3905 afs_int32 *aoutSize; /* set this */
3907 register afs_int32 code;
3910 struct ResidencyCmdInputs *Inputs;
3911 struct ResidencyCmdOutputs *Outputs;
3912 struct VenusFid tfid;
3915 Inputs = (struct ResidencyCmdInputs *) ain;
3916 Outputs = (struct ResidencyCmdOutputs *) aout;
3917 if (!avc) return EINVAL;
3918 if (!ain || ainSize != sizeof(struct ResidencyCmdInputs)) return EINVAL;
3922 Fid = &avc->fid.Fid;
3924 tfid.Cell = avc->fid.Cell;
3925 tfid.Fid.Volume = Fid->Volume;
3926 tfid.Fid.Vnode = Fid->Vnode;
3927 tfid.Fid.Unique = Fid->Unique;
3929 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
3931 afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD,
3932 ICL_TYPE_POINTER, tvc,
3933 ICL_TYPE_INT32, Inputs->command,
3934 ICL_TYPE_FID, &tfid);
3938 if (Inputs->command) {
3940 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3943 code = RXAFS_ResidencyCmd(tc->id, Fid,
3945 (struct ResidencyCmdOutputs *) aout);
3950 (afs_Analyze(tc, code, &tvc->fid, areq,
3951 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
3953 /* This call is done to have the callback things handled correctly */
3954 afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3955 } else { /* just a status request, return also link data */
3957 Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3958 Outputs->chars[0] = 0;
3959 if (vType(tvc) == VLNK) {
3960 ObtainWriteLock(&tvc->lock,555);
3961 if (afs_HandleLink(tvc, areq) == 0)
3962 strncpy((char *) &Outputs->chars, tvc->linkData, MAXCMDCHARS);
3963 ReleaseWriteLock(&tvc->lock);
3967 afs_PutVCache(tvc, WRITE_LOCK);
3970 *aoutSize = sizeof(struct ResidencyCmdOutputs);