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 PNoop, /* 57 -- arla: set file prio */
135 PNoop, /* 58 -- arla: fallback getfh */
136 PNoop, /* 59 -- arla: fallback fhopen */
137 PNoop, /* 60 -- arla: controls xfsdebug */
138 PNoop, /* 61 -- arla: controls arla debug */
139 PNoop, /* 62 -- arla: debug interface */
140 PNoop, /* 63 -- arla: print xfs status */
141 PNoop, /* 64 -- arla: force cache check */
142 PNoop, /* 65 -- arla: break callback */
143 PPrefetchFromTape, /* 66 -- MR-AFS: prefetch file from tape */
144 PResidencyCmd, /* 67 -- MR-AFS: generic commnd interface */
145 PNoop, /* 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)
1039 register struct vcache *avc;
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))();
1053 afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
1054 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
1055 AFS_STATCNT(HandlePioctl);
1056 if (code = afs_InitReq(&treq, *acred)) return code;
1057 device = (acom & 0xff00) >> 8;
1059 case 'V': /* Original pioctl's */
1060 pioctlSw = VpioctlSw;
1061 pioctlSwSize = sizeof(VpioctlSw);
1063 case 'C': /* Coordinated/common pioctl's */
1064 pioctlSw = CpioctlSw;
1065 pioctlSwSize = sizeof(CpioctlSw);
1070 function = acom & 0xff;
1071 if (function >= (pioctlSwSize / sizeof(char *))) {
1072 return EINVAL; /* out of range */
1074 inSize = ablob->in_size;
1075 if (inSize >= PIGGYSIZE) return E2BIG;
1076 inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1078 AFS_COPYIN(ablob->in, inData, inSize, code);
1082 osi_FreeLargeSpace(inData);
1085 outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1087 if (function == 3 && device == 'V') /* PSetTokens */
1088 code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, acred);
1090 code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, *acred);
1091 osi_FreeLargeSpace(inData);
1092 if (code == 0 && ablob->out_size > 0) {
1093 if (outSize > ablob->out_size) outSize = ablob->out_size;
1094 if (outSize >= PIGGYSIZE) code = E2BIG;
1096 AFS_COPYOUT(outData, ablob->out, outSize, code);
1098 osi_FreeLargeSpace(outData);
1099 return afs_CheckCode(code, &treq, 41);
1102 static PGetFID(avc, afun, areq, ain, aout, ainSize, aoutSize)
1105 struct vrequest *areq;
1108 afs_int32 *aoutSize; /* set this */ {
1109 register afs_int32 code;
1111 AFS_STATCNT(PGetFID);
1112 if (!avc) return EINVAL;
1113 memcpy(aout, (char *)&avc->fid, sizeof(struct VenusFid));
1114 *aoutSize = sizeof(struct VenusFid);
1118 static PSetAcl(avc, afun, areq, ain, aout, ainSize, aoutSize)
1121 struct vrequest *areq;
1124 afs_int32 *aoutSize; /* set this */ {
1125 register afs_int32 code;
1127 struct AFSOpaque acl;
1128 struct AFSVolSync tsync;
1129 struct AFSFetchStatus OutStatus;
1132 AFS_STATCNT(PSetAcl);
1135 if ((acl.AFSOpaque_len = strlen(ain)+1) > 1000)
1138 acl.AFSOpaque_val = ain;
1140 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1142 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1144 code = RXAFS_StoreACL(tconn->id, (struct AFSFid *) &avc->fid.Fid,
1145 &acl, &OutStatus, &tsync);
1151 (afs_Analyze(tconn, code, &avc->fid, areq,
1152 AFS_STATS_FS_RPCIDX_STOREACL, SHARED_LOCK, (struct cell *)0));
1154 /* now we've forgotten all of the access info */
1155 ObtainWriteLock(&afs_xcbhash, 455);
1157 afs_DequeueCallback(avc);
1158 avc->states &= ~(CStatd | CUnique);
1159 ReleaseWriteLock(&afs_xcbhash);
1160 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1161 osi_dnlc_purgedp(avc);
1165 int afs_defaultAsynchrony = 0;
1167 static PStoreBehind(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1170 struct vrequest *areq;
1173 afs_int32 *aoutSize; /* set this */
1174 struct AFS_UCRED *acred;
1177 struct sbstruct *sbr;
1179 sbr = (struct sbstruct *)ain;
1180 if (sbr->sb_default != -1) {
1181 if (afs_osi_suser(acred))
1182 afs_defaultAsynchrony = sbr->sb_default;
1186 if (avc && (sbr->sb_thisfile != -1)) {
1187 if (afs_AccessOK(avc, PRSFS_WRITE | PRSFS_ADMINISTER,
1188 areq, DONT_CHECK_MODE_BITS))
1189 avc->asynchrony = sbr->sb_thisfile;
1193 *aoutSize = sizeof(struct sbstruct);
1194 sbr = (struct sbstruct *)aout;
1195 sbr->sb_default = afs_defaultAsynchrony;
1197 sbr->sb_thisfile = avc->asynchrony;
1203 static PGCPAGs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1206 struct vrequest *areq;
1209 afs_int32 *aoutSize; /* set this */
1210 struct AFS_UCRED *acred;
1212 if (!afs_osi_suser(acred)) {
1215 afs_gcpags = AFS_GCPAGS_USERDISABLED;
1219 static PGetAcl(avc, afun, areq, ain, aout, ainSize, aoutSize)
1222 struct vrequest *areq;
1225 afs_int32 *aoutSize; /* set this */ {
1226 struct AFSOpaque acl;
1227 struct AFSVolSync tsync;
1228 struct AFSFetchStatus OutStatus;
1234 AFS_STATCNT(PGetAcl);
1235 if (!avc) return EINVAL;
1236 Fid.Volume = avc->fid.Fid.Volume;
1237 Fid.Vnode = avc->fid.Fid.Vnode;
1238 Fid.Unique = avc->fid.Fid.Unique;
1239 if (avc->states & CForeign) {
1241 * For a dfs xlator acl we have a special hack so that the
1242 * xlator will distinguish which type of acl will return. So
1243 * we currently use the top 2-bytes (vals 0-4) to tell which
1244 * type of acl to bring back. Horrible hack but this will
1245 * cause the least number of changes to code size and interfaces.
1247 if (Fid.Vnode & 0xc0000000)
1249 Fid.Vnode |= (ainSize << 30);
1251 acl.AFSOpaque_val = aout;
1253 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1256 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1258 code = RXAFS_FetchACL(tconn->id, &Fid,
1259 &acl, &OutStatus, &tsync);
1265 (afs_Analyze(tconn, code, &avc->fid, areq,
1266 AFS_STATS_FS_RPCIDX_FETCHACL,
1267 SHARED_LOCK, (struct cell *)0));
1270 *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1281 AFS_STATCNT(PBogus);
1285 static PGetFileCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1288 struct vrequest *areq;
1292 afs_int32 *aoutSize; /* set this */ {
1293 register struct cell *tcell;
1295 AFS_STATCNT(PGetFileCell);
1296 if (!avc) return EINVAL;
1297 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
1298 if (!tcell) return ESRCH;
1299 strcpy(aout, tcell->cellName);
1300 afs_PutCell(tcell, READ_LOCK);
1301 *aoutSize = strlen(aout) + 1;
1305 static PGetWSCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1308 struct vrequest *areq;
1312 afs_int32 *aoutSize; /* set this */ {
1313 register struct cell *tcell=0, *cellOne=0;
1314 register struct afs_q *cq, *tq;
1316 AFS_STATCNT(PGetWSCell);
1317 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1318 return EIO; /* Inappropriate ioctl for device */
1320 ObtainReadLock(&afs_xcell);
1321 cellOne = (struct cell *) 0;
1323 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
1324 tcell = QTOC(cq); tq = QNext(cq);
1325 if (tcell->states & CPrimary) break;
1326 if (tcell->cell == 1) cellOne = tcell;
1329 ReleaseReadLock(&afs_xcell);
1330 if (!tcell) { /* no primary cell, use cell #1 */
1331 if (!cellOne) return ESRCH;
1334 strcpy(aout, tcell->cellName);
1335 *aoutSize = strlen(aout) + 1;
1339 static PGetUserCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1342 struct vrequest *areq;
1346 afs_int32 *aoutSize; /* set this */ {
1347 register afs_int32 i;
1348 register struct unixuser *tu;
1349 register struct cell *tcell;
1351 AFS_STATCNT(PGetUserCell);
1352 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1353 return EIO; /* Inappropriate ioctl for device */
1355 /* return the cell name of the primary cell for this user */
1356 i = UHash(areq->uid);
1357 ObtainWriteLock(&afs_xuser,224);
1358 for(tu = afs_users[i]; tu; tu = tu->next) {
1359 if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1361 ReleaseWriteLock(&afs_xuser);
1366 tcell = afs_GetCell(tu->cell, READ_LOCK);
1367 afs_PutUser(tu, WRITE_LOCK);
1368 if (!tcell) return ESRCH;
1370 strcpy(aout, tcell->cellName);
1371 afs_PutCell(tcell, READ_LOCK);
1372 *aoutSize = strlen(aout)+1; /* 1 for the null */
1376 ReleaseWriteLock(&afs_xuser);
1383 static PSetTokens(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1386 struct vrequest *areq;
1390 afs_int32 *aoutSize; /* set this */
1391 struct AFS_UCRED **acred;
1394 register struct unixuser *tu;
1395 struct ClearToken clear;
1396 register struct cell *tcell;
1399 struct vrequest treq;
1400 afs_int32 flag, set_parent_pag = 0;
1402 AFS_STATCNT(PSetTokens);
1403 if (!afs_resourceinit_flag) {
1406 memcpy((char *)&i, ain, sizeof(afs_int32));
1407 ain += sizeof(afs_int32);
1408 stp = ain; /* remember where the ticket is */
1409 if (i < 0 || i > 2000) return EINVAL; /* malloc may fail */
1411 ain += i; /* skip over ticket */
1412 memcpy((char *)&i, ain, sizeof(afs_int32));
1413 ain += sizeof(afs_int32);
1414 if (i != sizeof(struct ClearToken)) {
1417 memcpy((char *)&clear, ain, sizeof(struct ClearToken));
1418 if (clear.AuthHandle == -1) clear.AuthHandle = 999; /* more rxvab compat stuff */
1419 ain += sizeof(struct ClearToken);
1420 if (ainSize != 2*sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1421 /* still stuff left? we've got primary flag and cell name. Set these */
1422 memcpy((char *)&flag, ain, sizeof(afs_int32)); /* primary id flag */
1423 ain += sizeof(afs_int32); /* skip id field */
1424 /* rest is cell name, look it up */
1425 if (flag & 0x8000) { /* XXX Use Constant XXX */
1429 tcell = afs_GetCellByName(ain, READ_LOCK);
1438 /* default to cell 1, primary id */
1439 flag = 1; /* primary id */
1440 i = 1; /* cell number */
1441 tcell = afs_GetCell(1, READ_LOCK);
1442 if (!tcell) goto nocell;
1444 afs_PutCell(tcell, READ_LOCK);
1445 if (set_parent_pag) {
1447 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1448 #if defined(AFS_DARWIN_ENV)
1449 struct proc *p=current_proc(); /* XXX */
1451 struct proc *p=curproc; /* XXX */
1453 uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1454 p->p_pid, p->p_comm);
1455 if (!setpag(p, acred, -1, &pag, 1)) {
1458 if (!setpag(u.u_procp, acred, -1, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
1460 if (!setpag(acred, -1, &pag, 1)) {
1463 afs_InitReq(&treq, *acred);
1467 /* now we just set the tokens */
1468 tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1469 tu->vid = clear.ViceId;
1470 if (tu->stp != (char *) 0) {
1471 afs_osi_Free(tu->stp, tu->stLen);
1473 tu->stp = (char *) afs_osi_Alloc(stLen);
1475 memcpy(tu->stp, stp, stLen);
1478 afs_stats_cmfullperf.authent.TicketUpdates++;
1479 afs_ComputePAGStats();
1480 #endif /* AFS_NOSTATS */
1481 tu->states |= UHasTokens;
1482 tu->states &= ~UTokensBad;
1483 afs_SetPrimary(tu, flag);
1484 tu->tokenTime =osi_Time();
1485 afs_ResetUserConns(tu);
1486 afs_PutUser(tu, WRITE_LOCK);
1501 static PGetVolumeStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
1504 struct vrequest *areq;
1507 afs_int32 *aoutSize; /* set this */ {
1509 char offLineMsg[256];
1511 register struct conn *tc;
1512 register afs_int32 code;
1513 struct VolumeStatus volstat;
1515 char *Name, *OfflineMsg, *MOTD;
1518 AFS_STATCNT(PGetVolumeStatus);
1519 if (!avc) return EINVAL;
1521 OfflineMsg = offLineMsg;
1524 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1526 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1528 code = RXAFS_GetVolumeStatus(tc->id, avc->fid.Fid.Volume, &volstat,
1529 &Name, &OfflineMsg, &MOTD);
1535 (afs_Analyze(tc, code, &avc->fid, areq,
1536 AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1537 SHARED_LOCK, (struct cell *)0));
1539 if (code) return code;
1540 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1542 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1543 cp += sizeof(VolumeStatus);
1544 strcpy(cp, volName);
1545 cp += strlen(volName)+1;
1546 strcpy(cp, offLineMsg);
1547 cp += strlen(offLineMsg)+1;
1549 cp += strlen(motd)+1;
1550 *aoutSize = (cp - aout);
1554 static PSetVolumeStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
1557 struct vrequest *areq;
1560 afs_int32 *aoutSize; /* set this */ {
1562 char offLineMsg[256];
1564 register struct conn *tc;
1565 register afs_int32 code;
1566 struct AFSFetchVolumeStatus volstat;
1567 struct AFSStoreVolumeStatus storeStat;
1568 register struct volume *tvp;
1572 AFS_STATCNT(PSetVolumeStatus);
1573 if (!avc) return EINVAL;
1575 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
1577 if (tvp->states & (VRO | VBackup)) {
1578 afs_PutVolume(tvp, READ_LOCK);
1581 afs_PutVolume(tvp, READ_LOCK);
1584 /* Copy the junk out, using cp as a roving pointer. */
1586 memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
1587 cp += sizeof(AFSFetchVolumeStatus);
1588 if (strlen(cp) >= sizeof(volName))
1590 strcpy(volName, cp);
1591 cp += strlen(volName)+1;
1592 if (strlen(cp) >= sizeof(offLineMsg))
1594 strcpy(offLineMsg, cp);
1595 cp += strlen(offLineMsg)+1;
1596 if (strlen(cp) >= sizeof(motd))
1600 if (volstat.MinQuota != -1) {
1601 storeStat.MinQuota = volstat.MinQuota;
1602 storeStat.Mask |= AFS_SETMINQUOTA;
1604 if (volstat.MaxQuota != -1) {
1605 storeStat.MaxQuota = volstat.MaxQuota;
1606 storeStat.Mask |= AFS_SETMAXQUOTA;
1609 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1611 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1613 code = RXAFS_SetVolumeStatus(tc->id, avc->fid.Fid.Volume,
1614 &storeStat, volName, offLineMsg, motd);
1620 (afs_Analyze(tc, code, &avc->fid, areq,
1621 AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1622 SHARED_LOCK, (struct cell *)0));
1624 if (code) return code;
1625 /* we are sending parms back to make compat. with prev system. should
1626 change interface later to not ask for current status, just set new status */
1628 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1629 cp += sizeof(VolumeStatus);
1630 strcpy(cp, volName);
1631 cp += strlen(volName)+1;
1632 strcpy(cp, offLineMsg);
1633 cp += strlen(offLineMsg)+1;
1635 cp += strlen(motd)+1;
1636 *aoutSize = cp - aout;
1640 static PFlush(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1641 register struct vcache *avc;
1643 struct vrequest *areq;
1646 afs_int32 *aoutSize; /* set this */
1647 struct AFS_UCRED *acred;
1650 AFS_STATCNT(PFlush);
1651 if (!avc) return EINVAL;
1652 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1653 afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
1655 ObtainWriteLock(&avc->lock,225);
1656 ObtainWriteLock(&afs_xcbhash, 456);
1657 afs_DequeueCallback(avc);
1658 avc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
1659 ReleaseWriteLock(&afs_xcbhash);
1660 /* now find the disk cache entries */
1661 afs_TryToSmush(avc, acred, 1);
1662 osi_dnlc_purgedp(avc);
1663 afs_symhint_inval(avc);
1664 if (avc->linkData && !(avc->states & CCore)) {
1665 afs_osi_Free(avc->linkData, strlen(avc->linkData)+1);
1666 avc->linkData = (char *) 0;
1668 ReleaseWriteLock(&avc->lock);
1669 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1670 afs_BozonUnlock(&avc->pvnLock, avc);
1675 static PNewStatMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
1678 struct vrequest *areq;
1681 afs_int32 *aoutSize; /* set this */ {
1682 register afs_int32 code;
1683 register struct vcache *tvc;
1684 register struct dcache *tdc;
1685 struct VenusFid tfid;
1687 struct sysname_info sysState;
1688 afs_size_t offset, len;
1690 AFS_STATCNT(PNewStatMount);
1691 if (!avc) return EINVAL;
1692 code = afs_VerifyVCache(avc, areq);
1693 if (code) return code;
1694 if (vType(avc) != VDIR) {
1697 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
1698 if (!tdc) return ENOENT;
1699 Check_AtSys(avc, ain, &sysState, areq);
1700 ObtainReadLock(&tdc->lock);
1702 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
1703 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1704 ReleaseReadLock(&tdc->lock);
1705 afs_PutDCache(tdc); /* we're done with the data */
1706 bufp = sysState.name;
1710 tfid.Cell = avc->fid.Cell;
1711 tfid.Fid.Volume = avc->fid.Fid.Volume;
1712 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
1713 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
1715 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
1722 if (vType(tvc) != VLNK) {
1723 afs_PutVCache(tvc, WRITE_LOCK);
1727 ObtainWriteLock(&tvc->lock,226);
1728 code = afs_HandleLink(tvc, areq);
1730 if (tvc->linkData) {
1731 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1734 /* we have the data */
1735 strcpy(aout, tvc->linkData);
1736 *aoutSize = strlen(tvc->linkData)+1;
1741 ReleaseWriteLock(&tvc->lock);
1742 afs_PutVCache(tvc, WRITE_LOCK);
1744 if (sysState.allocked) osi_FreeLargeSpace(bufp);
1748 static PGetTokens(avc, afun, areq, ain, aout, ainSize, aoutSize)
1751 struct vrequest *areq;
1754 afs_int32 *aoutSize; /* set this */ {
1755 register struct cell *tcell;
1756 register afs_int32 i;
1757 register struct unixuser *tu;
1762 AFS_STATCNT(PGetTokens);
1763 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1764 return EIO; /* Inappropriate ioctl for device */
1766 /* weird interface. If input parameter is present, it is an integer and
1767 we're supposed to return the parm'th tokens for this unix uid.
1768 If not present, we just return tokens for cell 1.
1769 If counter out of bounds, return EDOM.
1770 If no tokens for the particular cell, return ENOTCONN.
1771 Also, if this mysterious parm is present, we return, along with the
1772 tokens, the primary cell indicator (an afs_int32 0) and the cell name
1773 at the end, in that order.
1775 if (newStyle = (ainSize > 0)) {
1776 memcpy((char *)&iterator, ain, sizeof(afs_int32));
1778 i = UHash(areq->uid);
1779 ObtainReadLock(&afs_xuser);
1780 for(tu = afs_users[i]; tu; tu=tu->next) {
1782 if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1783 if (iterator-- == 0) break; /* are we done yet? */
1787 if (tu->uid == areq->uid && tu->cell == 1) break;
1792 * No need to hold a read lock on each user entry
1796 ReleaseReadLock(&afs_xuser);
1801 if (((tu->states & UHasTokens) == 0) || (tu->ct.EndTimestamp < osi_Time())) {
1802 tu->states |= (UTokensBad | UNeedsReset);
1803 afs_PutUser(tu, READ_LOCK);
1806 /* use iterator for temp */
1808 iterator = tu->stLen; /* for compat, we try to return 56 byte tix if they fit */
1809 if (iterator < 56) iterator = 56; /* # of bytes we're returning */
1810 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1811 cp += sizeof(afs_int32);
1812 memcpy(cp, tu->stp, tu->stLen); /* copy out st */
1814 iterator = sizeof(struct ClearToken);
1815 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1816 cp += sizeof(afs_int32);
1817 memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
1818 cp += sizeof(struct ClearToken);
1820 /* put out primary id and cell name, too */
1821 iterator = (tu->states & UPrimary ? 1 : 0);
1822 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1823 cp += sizeof(afs_int32);
1824 tcell = afs_GetCell(tu->cell, READ_LOCK);
1826 strcpy(cp, tcell->cellName);
1827 cp += strlen(tcell->cellName)+1;
1828 afs_PutCell(tcell, READ_LOCK);
1832 *aoutSize = cp - aout;
1833 afs_PutUser(tu, READ_LOCK);
1837 static PUnlog(avc, afun, areq, ain, aout, ainSize, aoutSize)
1840 struct vrequest *areq;
1843 afs_int32 *aoutSize; /* set this */ {
1844 register afs_int32 i;
1845 register struct unixuser *tu;
1847 AFS_STATCNT(PUnlog);
1848 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1849 return EIO; /* Inappropriate ioctl for device */
1851 i = UHash(areq->uid);
1852 ObtainWriteLock(&afs_xuser,227);
1853 for(tu=afs_users[i]; tu; tu=tu->next) {
1854 if (tu->uid == areq->uid) {
1856 tu->states &= ~UHasTokens;
1857 /* security is not having to say you're sorry */
1858 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
1860 ReleaseWriteLock(&afs_xuser);
1861 /* We have to drop the lock over the call to afs_ResetUserConns, since
1862 * it obtains the afs_xvcache lock. We could also keep the lock, and
1863 * modify ResetUserConns to take parm saying we obtained the lock
1864 * already, but that is overkill. By keeping the "tu" pointer
1865 * held over the released lock, we guarantee that we won't lose our
1866 * place, and that we'll pass over every user conn that existed when
1867 * we began this call.
1869 afs_ResetUserConns(tu);
1871 ObtainWriteLock(&afs_xuser,228);
1873 /* set the expire times to 0, causes
1874 * afs_GCUserData to remove this entry
1876 tu->ct.EndTimestamp = 0;
1878 #endif /* UKERNEL */
1881 ReleaseWriteLock(&afs_xuser);
1885 static PMariner(avc, afun, areq, ain, aout, ainSize, aoutSize)
1888 struct vrequest *areq;
1891 afs_int32 *aoutSize; /* set this */ {
1892 afs_int32 newHostAddr;
1893 afs_int32 oldHostAddr;
1895 AFS_STATCNT(PMariner);
1897 memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost, sizeof(afs_int32));
1899 oldHostAddr = 0xffffffff; /* disabled */
1901 memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
1902 if (newHostAddr == 0xffffffff) {
1903 /* disable mariner operations */
1906 else if (newHostAddr) {
1908 afs_marinerHost = newHostAddr;
1910 memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
1911 *aoutSize = sizeof(afs_int32);
1915 static PCheckServers(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1918 struct vrequest *areq;
1921 afs_int32 *aoutSize; /* set this */
1922 struct AFS_UCRED *acred;
1924 register char *cp = 0;
1926 register struct server *ts;
1927 afs_int32 temp, *lp = (afs_int32 *)ain, havecell=0;
1929 struct chservinfo *pcheck;
1931 AFS_STATCNT(PCheckServers);
1933 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1934 return EIO; /* Inappropriate ioctl for device */
1936 if (*lp == 0x12345678) { /* For afs3.3 version */
1937 pcheck=(struct chservinfo *)ain;
1938 if (pcheck->tinterval >= 0) {
1940 memcpy(cp, (char *)&PROBE_INTERVAL, sizeof(afs_int32));
1941 *aoutSize = sizeof(afs_int32);
1942 if (pcheck->tinterval > 0) {
1943 if (!afs_osi_suser(acred))
1945 PROBE_INTERVAL=pcheck->tinterval;
1951 temp=pcheck->tflags;
1952 cp = pcheck->tbuffer;
1953 } else { /* For pre afs3.3 versions */
1954 memcpy((char *)&temp, ain, sizeof(afs_int32));
1955 cp = ain+sizeof(afs_int32);
1956 if (ainSize > sizeof(afs_int32))
1961 * 1: fast check, don't contact servers.
1962 * 2: local cell only.
1965 /* have cell name, too */
1966 cellp = afs_GetCellByName(cp, READ_LOCK);
1967 if (!cellp) return ENOENT;
1969 else cellp = (struct cell *) 0;
1970 if (!cellp && (temp & 2)) {
1971 /* use local cell */
1972 cellp = afs_GetCell(1, READ_LOCK);
1974 if (!(temp & 1)) { /* if not fast, call server checker routine */
1975 afs_CheckServers(1, cellp); /* check down servers */
1976 afs_CheckServers(0, cellp); /* check up servers */
1978 /* now return the current down server list */
1980 ObtainReadLock(&afs_xserver);
1981 for(i=0;i<NSERVERS;i++) {
1982 for(ts = afs_servers[i]; ts; ts=ts->next) {
1983 if (cellp && ts->cell != cellp) continue; /* cell spec'd and wrong */
1984 if ((ts->flags & SRVR_ISDOWN) && ts->addr->sa_portal != ts->cell->vlport) {
1985 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
1986 cp += sizeof(afs_int32);
1990 ReleaseReadLock(&afs_xserver);
1991 if (cellp) afs_PutCell(cellp, READ_LOCK);
1992 *aoutSize = cp - aout;
1996 static PCheckVolNames(avc, afun, areq, ain, aout, ainSize, aoutSize)
1999 struct vrequest *areq;
2002 afs_int32 *aoutSize; /* set this */ {
2003 AFS_STATCNT(PCheckVolNames);
2004 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2005 return EIO; /* Inappropriate ioctl for device */
2007 afs_CheckRootVolume();
2008 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE |
2009 AFS_VOLCHECK_EXPIRED |
2011 AFS_VOLCHECK_MTPTS);
2015 static PCheckAuth(avc, afun, areq, ain, aout, ainSize, aoutSize)
2018 struct vrequest *areq;
2021 afs_int32 *aoutSize; /* set this */ {
2025 struct unixuser *tu;
2027 extern afs_rwlock_t afs_xsrvAddr;
2029 AFS_STATCNT(PCheckAuth);
2030 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2031 return EIO; /* Inappropriate ioctl for device */
2034 tu = afs_GetUser(areq->uid, 1, READ_LOCK); /* check local cell authentication */
2035 if (!tu) retValue = EACCES;
2037 /* we have a user */
2038 ObtainReadLock(&afs_xsrvAddr);
2039 ObtainReadLock(&afs_xconn);
2041 /* any tokens set? */
2042 if ((tu->states & UHasTokens) == 0) retValue = EACCES;
2043 /* all connections in cell 1 working? */
2044 for(i=0;i<NSERVERS;i++) {
2045 for(sa = afs_srvAddrs[i]; sa; sa=sa->next_bkt) {
2046 for (tc = sa->conns; tc; tc=tc->next) {
2047 if (tc->user == tu && (tu->states & UTokensBad))
2052 ReleaseReadLock(&afs_xsrvAddr);
2053 ReleaseReadLock(&afs_xconn);
2054 afs_PutUser(tu, READ_LOCK);
2056 memcpy(aout, (char *)&retValue, sizeof(afs_int32));
2057 *aoutSize = sizeof(afs_int32);
2061 static Prefetch(apath, adata, afollow, acred)
2063 struct afs_ioctl *adata;
2065 struct AFS_UCRED *acred;
2068 register afs_int32 code;
2069 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2075 AFS_STATCNT(Prefetch);
2076 if (!apath) return EINVAL;
2077 tp = osi_AllocLargeSpace(1024);
2078 AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2080 osi_FreeLargeSpace(tp);
2083 if (afs_BBusy()) { /* do this as late as possible */
2084 osi_FreeLargeSpace(tp);
2085 return EWOULDBLOCK; /* pretty close */
2087 afs_BQueue(BOP_PATH, (struct vcache*)0, 0, 0, acred,
2088 (afs_size_t) 0, (afs_size_t) 0, tp);
2092 static PFindVolume(avc, afun, areq, ain, aout, ainSize, aoutSize)
2095 struct vrequest *areq;
2098 afs_int32 *aoutSize; /* set this */ {
2099 register struct volume *tvp;
2100 register struct server *ts;
2101 register afs_int32 i;
2104 AFS_STATCNT(PFindVolume);
2105 if (!avc) return EINVAL;
2106 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
2109 for(i=0;i<MAXHOSTS;i++) {
2110 ts = tvp->serverHost[i];
2112 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2113 cp += sizeof(afs_int32);
2116 /* still room for terminating NULL, add it on */
2117 ainSize = 0; /* reuse vbl */
2118 memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
2119 cp += sizeof(afs_int32);
2121 *aoutSize = cp - aout;
2122 afs_PutVolume(tvp, READ_LOCK);
2128 static PViceAccess(avc, afun, areq, ain, aout, ainSize, aoutSize)
2131 struct vrequest *areq;
2134 afs_int32 *aoutSize; /* set this */ {
2135 register afs_int32 code;
2138 AFS_STATCNT(PViceAccess);
2139 if (!avc) return EINVAL;
2140 code = afs_VerifyVCache(avc, areq);
2141 if (code) return code;
2142 memcpy((char *)&temp, ain, sizeof(afs_int32));
2143 code = afs_AccessOK(avc,temp, areq, CHECK_MODE_BITS);
2148 static PSetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2151 struct vrequest *areq;
2154 afs_int32 *aoutSize; /* set this */
2155 struct AFS_UCRED *acred;
2160 AFS_STATCNT(PSetCacheSize);
2161 if (!afs_osi_suser(acred))
2163 /* too many things are setup initially in mem cache version */
2164 if (cacheDiskType == AFS_FCACHE_TYPE_MEM) return EROFS;
2165 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2166 if (newValue == 0) afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2168 extern u_int afs_min_cache;
2169 if (newValue < afs_min_cache)
2170 afs_cacheBlocks = afs_min_cache;
2172 afs_cacheBlocks = newValue;
2174 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2175 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2176 afs_MaybeWakeupTruncateDaemon();
2177 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2178 afs_osi_Wait(1000, 0, 0);
2179 afs_MaybeWakeupTruncateDaemon();
2184 #define MAXGCSTATS 16
2185 static PGetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize)
2188 struct vrequest *areq;
2191 afs_int32 *aoutSize; /* set this */ {
2192 afs_int32 results[MAXGCSTATS];
2194 AFS_STATCNT(PGetCacheSize);
2195 memset((char *)results, 0, sizeof(results));
2196 results[0] = afs_cacheBlocks;
2197 results[1] = afs_blocksUsed;
2198 memcpy(aout, (char *)results, sizeof(results));
2199 *aoutSize = sizeof(results);
2203 static PRemoveCallBack(avc, afun, areq, ain, aout, ainSize, aoutSize)
2206 struct vrequest *areq;
2209 afs_int32 *aoutSize; /* set this */ {
2210 register struct conn *tc;
2211 register afs_int32 code;
2212 struct AFSCallBack CallBacks_Array[1];
2213 struct AFSCBFids theFids;
2214 struct AFSCBs theCBs;
2217 AFS_STATCNT(PRemoveCallBack);
2218 if (!avc) return EINVAL;
2219 if (avc->states & CRO) return 0; /* read-only-ness can't change */
2220 ObtainWriteLock(&avc->lock,229);
2221 theFids.AFSCBFids_len = 1;
2222 theCBs.AFSCBs_len = 1;
2223 theFids.AFSCBFids_val = (struct AFSFid *) &avc->fid.Fid;
2224 theCBs.AFSCBs_val = CallBacks_Array;
2225 CallBacks_Array[0].CallBackType = CB_DROPPED;
2226 if (avc->callback) {
2228 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2230 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2232 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2236 /* don't set code on failure since we wouldn't use it */
2238 (afs_Analyze(tc, code, &avc->fid, areq,
2239 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS,
2240 SHARED_LOCK, (struct cell *)0));
2242 ObtainWriteLock(&afs_xcbhash, 457);
2243 afs_DequeueCallback(avc);
2245 avc->states &= ~(CStatd | CUnique);
2246 ReleaseWriteLock(&afs_xcbhash);
2247 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2248 osi_dnlc_purgedp(avc);
2250 ReleaseWriteLock(&avc->lock);
2254 static PNewCell(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2257 struct vrequest *areq;
2261 struct AFS_UCRED *acred;
2262 afs_int32 *aoutSize; /* set this */ {
2263 /* create a new cell */
2264 afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic=0;
2265 register struct cell *tcell;
2266 char *newcell=0, *linkedcell=0, *tp= ain;
2267 register afs_int32 code, linkedstate=0, ls;
2268 u_short fsport = 0, vlport = 0;
2271 AFS_STATCNT(PNewCell);
2272 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2273 return EIO; /* Inappropriate ioctl for device */
2275 if (!afs_osi_suser(acred))
2278 memcpy((char *)&magic, tp, sizeof(afs_int32));
2279 tp += sizeof(afs_int32);
2280 if (magic != 0x12345678)
2283 /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2284 * server addresses while the 3.5 fs newcell command passes
2285 * MAXHOSTS. To figure out which is which, check if the cellname
2288 newcell = tp + (MAXCELLHOSTS+3)*sizeof(afs_int32);
2289 scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2291 /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2292 memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
2293 tp += (scount * sizeof(afs_int32));
2295 lp = (afs_int32 *)tp;
2298 if (fsport < 1024) fsport = 0; /* Privileged ports not allowed */
2299 if (vlport < 1024) vlport = 0; /* Privileged ports not allowed */
2300 tp += (3 * sizeof(afs_int32));
2302 if ((ls = *lp) & 1) {
2303 linkedcell = tp + strlen(newcell)+1;
2304 linkedstate |= CLinkedCell;
2307 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2308 code = afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport, vlport, (int)0, (char *) 0);
2312 static PNewAlias(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2315 struct vrequest *areq;
2319 struct AFS_UCRED *acred;
2320 afs_int32 *aoutSize; /* set this */
2322 /* create a new cell alias */
2323 register struct cell *tcell;
2325 register afs_int32 code;
2326 char *realName, *aliasName;
2327 register struct afs_q *cq, *tq;
2329 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2330 return EIO; /* Inappropriate ioctl for device */
2332 if (!afs_osi_suser(acred))
2336 tp += strlen(aliasName) + 1;
2340 * Prevent user from shooting themselves in the foot -- don't allow
2341 * creation of aliases when a real cell already exists with that name.
2343 ObtainReadLock(&afs_xcell);
2344 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2345 tcell = QTOC(cq); tq = QNext(cq);
2346 if ((afs_strcasecmp(tcell->cellName, aliasName) == 0) &&
2347 !(tcell->states & CAlias)) {
2348 ReleaseReadLock(&afs_xcell);
2352 ReleaseReadLock(&afs_xcell);
2354 code = afs_NewCell(aliasName, 0, CAlias, 0, 0, 0, 0, realName);
2359 static PListCells(avc, afun, areq, ain, aout, ainSize, aoutSize)
2362 struct vrequest *areq;
2365 afs_int32 *aoutSize; /* set this */ {
2366 afs_int32 whichCell;
2367 register struct cell *tcell=0;
2368 register afs_int32 i;
2369 register char *cp, *tp = ain;
2370 register struct afs_q *cq, *tq;
2372 AFS_STATCNT(PListCells);
2373 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2374 return EIO; /* Inappropriate ioctl for device */
2376 memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2377 tp += sizeof(afs_int32);
2378 ObtainReadLock(&afs_xcell);
2379 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2380 tcell = QTOC(cq); tq = QNext(cq);
2381 if (tcell->states & CAlias) {
2385 if (whichCell == 0) break;
2391 memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
2392 for(i=0;i<MAXCELLHOSTS;i++) {
2393 if (tcell->cellHosts[i] == 0) break;
2394 memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip, sizeof(afs_int32));
2395 cp += sizeof(afs_int32);
2397 cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2398 strcpy(cp, tcell->cellName);
2399 cp += strlen(tcell->cellName)+1;
2400 *aoutSize = cp - aout;
2402 ReleaseReadLock(&afs_xcell);
2403 if (tcell) return 0;
2407 static PListAliases(avc, afun, areq, ain, aout, ainSize, aoutSize)
2410 struct vrequest *areq;
2413 afs_int32 *aoutSize; /* set this */
2415 afs_int32 whichAlias;
2416 register struct cell *tcell=0;
2417 register char *cp, *tp = ain;
2418 register struct afs_q *cq, *tq;
2420 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2421 return EIO; /* Inappropriate ioctl for device */
2422 if (ainSize < sizeof(afs_int32))
2425 memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2426 tp += sizeof(afs_int32);
2428 ObtainReadLock(&afs_xcell);
2429 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2430 tcell = QTOC(cq); tq = QNext(cq);
2431 if (!(tcell->states & CAlias)) {
2435 if (whichAlias == 0) break;
2441 strcpy(cp, tcell->cellName);
2442 cp += strlen(tcell->cellName)+1;
2443 strcpy(cp, tcell->realName);
2444 cp += strlen(tcell->realName)+1;
2445 *aoutSize = cp - aout;
2447 ReleaseReadLock(&afs_xcell);
2448 if (tcell) return 0;
2452 static PRemoveMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
2455 struct vrequest *areq;
2459 afs_int32 *aoutSize; /* set this */ {
2460 register afs_int32 code;
2462 struct sysname_info sysState;
2463 afs_size_t offset, len;
2464 register struct conn *tc;
2465 register struct dcache *tdc;
2466 register struct vcache *tvc;
2467 struct AFSFetchStatus OutDirStatus;
2468 struct VenusFid tfid;
2469 struct AFSVolSync tsync;
2473 /* "ain" is the name of the file in this dir to remove */
2475 AFS_STATCNT(PRemoveMount);
2476 if (!avc) return EINVAL;
2477 code = afs_VerifyVCache(avc, areq);
2478 if (code) return code;
2479 if (vType(avc) != VDIR) return ENOTDIR;
2481 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1); /* test for error below */
2482 if (!tdc) return ENOENT;
2483 Check_AtSys(avc, ain, &sysState, areq);
2484 ObtainReadLock(&tdc->lock);
2486 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
2487 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2488 ReleaseReadLock(&tdc->lock);
2489 bufp = sysState.name;
2494 tfid.Cell = avc->fid.Cell;
2495 tfid.Fid.Volume = avc->fid.Fid.Volume;
2496 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
2497 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
2499 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0,
2500 (struct vcache*)0/*xxx avc?*/, WRITE_LOCK);
2507 if (vType(tvc) != VLNK) {
2509 afs_PutVCache(tvc, WRITE_LOCK);
2513 ObtainWriteLock(&tvc->lock,230);
2514 code = afs_HandleLink(tvc, areq);
2516 if (tvc->linkData) {
2517 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2522 ReleaseWriteLock(&tvc->lock);
2523 osi_dnlc_purgedp(tvc);
2524 afs_PutVCache(tvc, WRITE_LOCK);
2529 ObtainWriteLock(&avc->lock,231);
2530 osi_dnlc_remove(avc, bufp, tvc);
2532 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2534 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2536 code = RXAFS_RemoveFile(tc->id, (struct AFSFid *) &avc->fid.Fid,
2537 bufp, &OutDirStatus, &tsync);
2543 (afs_Analyze(tc, code, &avc->fid, areq,
2544 AFS_STATS_FS_RPCIDX_REMOVEFILE,
2545 SHARED_LOCK, (struct cell *)0));
2548 if (tdc) afs_PutDCache(tdc);
2549 ReleaseWriteLock(&avc->lock);
2553 /* we have the thing in the cache */
2554 ObtainWriteLock(&tdc->lock, 661);
2555 if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2556 /* we can do it locally */
2557 code = afs_dir_Delete(&tdc->f.inode, bufp);
2559 ZapDCE(tdc); /* surprise error -- invalid value */
2560 DZap(&tdc->f.inode);
2563 ReleaseWriteLock(&tdc->lock);
2564 afs_PutDCache(tdc); /* drop ref count */
2566 avc->states &= ~CUnique; /* For the dfs xlator */
2567 ReleaseWriteLock(&avc->lock);
2570 if (sysState.allocked) osi_FreeLargeSpace(bufp);
2574 static PVenusLogging(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2577 struct vrequest *areq;
2581 struct AFS_UCRED *acred;
2582 afs_int32 *aoutSize; /* set this */ {
2583 return EINVAL; /* OBSOLETE */
2586 static PGetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2589 struct vrequest *areq;
2592 afs_int32 *aoutSize; /* set this */ {
2593 register struct cell *tcell;
2596 AFS_STATCNT(PGetCellStatus);
2597 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2598 return EIO; /* Inappropriate ioctl for device */
2600 tcell = afs_GetCellByName(ain, READ_LOCK);
2601 if (!tcell) return ENOENT;
2602 temp = tcell->states;
2603 afs_PutCell(tcell, READ_LOCK);
2604 memcpy(aout, (char *)&temp, sizeof(afs_int32));
2605 *aoutSize = sizeof(afs_int32);
2609 static PSetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2612 struct vrequest *areq;
2615 struct AFS_UCRED *acred;
2616 afs_int32 *aoutSize; /* set this */ {
2617 register struct cell *tcell;
2620 if (!afs_osi_suser(acred))
2622 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2623 return EIO; /* Inappropriate ioctl for device */
2625 tcell = afs_GetCellByName(ain+2*sizeof(afs_int32), WRITE_LOCK);
2626 if (!tcell) return ENOENT;
2627 memcpy((char *)&temp, ain, sizeof(afs_int32));
2629 tcell->states |= CNoSUID;
2631 tcell->states &= ~CNoSUID;
2632 afs_PutCell(tcell, WRITE_LOCK);
2636 static PFlushVolumeData(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2639 struct vrequest *areq;
2642 afs_int32 *aoutSize; /* set this */
2643 struct AFS_UCRED *acred;
2645 extern struct volume *afs_volumes[NVOLS];
2646 register afs_int32 i;
2647 register struct dcache *tdc;
2648 register struct vcache *tvc;
2649 register struct volume *tv;
2650 afs_int32 cell, volume;
2652 AFS_STATCNT(PFlushVolumeData);
2655 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2656 return EIO; /* Inappropriate ioctl for device */
2658 volume = avc->fid.Fid.Volume; /* who to zap */
2659 cell = avc->fid.Cell;
2662 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
2663 * the vcaches associated with the volume.
2665 ObtainReadLock(&afs_xvcache);
2666 for(i = 0; i < VCSIZE; i++) {
2667 for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
2668 if (tvc->fid.Fid.Volume == volume && tvc->fid.Cell == cell) {
2669 #if defined(AFS_SGI_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
2670 VN_HOLD(AFSTOV(tvc));
2672 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2678 ReleaseReadLock(&afs_xvcache);
2679 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2680 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
2682 ObtainWriteLock(&tvc->lock,232);
2684 ObtainWriteLock(&afs_xcbhash, 458);
2685 afs_DequeueCallback(tvc);
2686 tvc->states &= ~(CStatd | CDirty);
2687 ReleaseWriteLock(&afs_xcbhash);
2688 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
2689 osi_dnlc_purgedp(tvc);
2690 afs_TryToSmush(tvc, acred, 1);
2691 ReleaseWriteLock(&tvc->lock);
2692 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2693 afs_BozonUnlock(&tvc->pvnLock, tvc);
2695 ObtainReadLock(&afs_xvcache);
2696 /* our tvc ptr is still good until now */
2701 ReleaseReadLock(&afs_xvcache);
2704 MObtainWriteLock(&afs_xdcache,328); /* needed if you're going to flush any stuff */
2705 for(i=0;i<afs_cacheFiles;i++) {
2706 if (!(afs_indexFlags[i] & IFEverUsed)) continue; /* never had any data */
2707 tdc = afs_GetDSlot(i, (struct dcache *) 0);
2708 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
2709 ReleaseReadLock(&tdc->tlock);
2710 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
2711 if (! (afs_indexFlags[i] & IFDataMod)) {
2712 /* if the file is modified, but has a ref cnt of only 1, then
2713 someone probably has the file open and is writing into it.
2714 Better to skip flushing such a file, it will be brought back
2715 immediately on the next write anyway.
2717 If we *must* flush, then this code has to be rearranged to call
2718 afs_storeAllSegments() first */
2719 afs_FlushDCache(tdc);
2723 ReleaseReadLock(&tdc->tlock);
2725 afs_PutDCache(tdc); /* bumped by getdslot */
2727 MReleaseWriteLock(&afs_xdcache);
2729 ObtainReadLock(&afs_xvolume);
2730 for (i=0;i<NVOLS;i++) {
2731 for (tv = afs_volumes[i]; tv; tv=tv->next) {
2732 if (tv->volume == volume) {
2733 afs_ResetVolumeInfo(tv);
2738 ReleaseReadLock(&afs_xvolume);
2740 /* probably, a user is doing this, probably, because things are screwed up.
2741 * maybe it's the dnlc's fault? */
2748 static PGetVnodeXStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2751 struct vrequest *areq;
2754 afs_int32 *aoutSize; /* set this */ {
2755 register afs_int32 code;
2756 struct vcxstat stat;
2759 /* AFS_STATCNT(PGetVnodeXStatus); */
2760 if (!avc) return EINVAL;
2761 code = afs_VerifyVCache(avc, areq);
2762 if (code) return code;
2763 if (vType(avc) == VDIR)
2764 mode = PRSFS_LOOKUP;
2767 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
2769 stat.fid = avc->fid;
2770 hset32(stat.DataVersion, hgetlo(avc->m.DataVersion));
2771 stat.lock = avc->lock;
2772 stat.parentVnode = avc->parentVnode;
2773 stat.parentUnique = avc->parentUnique;
2774 hset(stat.flushDV, avc->flushDV);
2775 hset(stat.mapDV, avc->mapDV);
2776 stat.truncPos = avc->truncPos;
2777 { /* just grab the first two - won't break anything... */
2778 struct axscache *ac;
2780 for (i=0, ac=avc->Access; ac && i < CPSIZE; i++, ac=ac->next) {
2781 stat.randomUid[i] = ac->uid;
2782 stat.randomAccess[i] = ac->axess;
2785 stat.callback = afs_data_pointer_to_int32(avc->callback);
2786 stat.cbExpires = avc->cbExpires;
2787 stat.anyAccess = avc->anyAccess;
2788 stat.opens = avc->opens;
2789 stat.execsOrWriters = avc->execsOrWriters;
2790 stat.flockCount = avc->flockCount;
2791 stat.mvstat = avc->mvstat;
2792 stat.states = avc->states;
2793 memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
2794 *aoutSize = sizeof(struct vcxstat);
2799 /* We require root for local sysname changes, but not for remote */
2800 /* (since we don't really believe remote uids anyway) */
2801 /* outname[] shouldn't really be needed- this is left as an excercise */
2802 /* for the reader. */
2803 static PSetSysName(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2806 struct vrequest *areq;
2809 afs_int32 *aoutSize; /* set this */
2810 register struct AFS_UCRED *acred;
2812 char *cp, inname[MAXSYSNAME], outname[MAXSYSNAME];
2813 int setsysname, foundname=0;
2814 register struct afs_exporter *exporter;
2815 extern struct unixuser *afs_FindUser();
2816 extern char *afs_sysname;
2817 extern char *afs_sysnamelist[];
2818 extern int afs_sysnamecount;
2819 register struct unixuser *au;
2820 register afs_int32 pag, error;
2824 AFS_STATCNT(PSetSysName);
2825 if (!afs_globalVFS) {
2826 /* Afsd is NOT running; disable it */
2827 #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)
2830 return (setuerror(EINVAL), EINVAL);
2833 memset(inname, 0, MAXSYSNAME);
2834 memcpy((char *)&setsysname, ain, sizeof(afs_int32));
2835 ain += sizeof(afs_int32);
2839 if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
2841 for(cp = ain,count = 0;count < setsysname;count++) {
2842 /* won't go past end of ain since maxsysname*num < ain length */
2844 if (t >= MAXSYSNAME || t <= 0)
2846 /* check for names that can shoot us in the foot */
2847 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
2853 /* inname gets first entry in case we're being a translater */
2855 memcpy(inname, ain, t+1); /* include terminating null */
2858 if (acred->cr_gid == RMTUSER_REQ) { /* Handles all exporters */
2859 pag = PagInCred(acred);
2861 return EINVAL; /* Better than panicing */
2863 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
2864 return EINVAL; /* Better than panicing */
2866 if (!(exporter = au->exporter)) {
2867 afs_PutUser(au, READ_LOCK);
2868 return EINVAL; /* Better than panicing */
2870 error = EXP_SYSNAME(exporter, (setsysname? inname : (char *)0), outname);
2872 if (error == ENODEV) foundname = 0; /* sysname not set yet! */
2874 afs_PutUser(au, READ_LOCK);
2879 afs_PutUser(au, READ_LOCK);
2882 /* Not xlating, so local case */
2883 if (!afs_sysname) osi_Panic("PSetSysName: !afs_sysname\n");
2884 if (!setsysname) { /* user just wants the info */
2885 strcpy(outname, afs_sysname);
2886 foundname = afs_sysnamecount;
2887 } else { /* Local guy; only root can change sysname */
2888 if (!afs_osi_suser(acred))
2891 /* clear @sys entries from the dnlc, once afs_lookup can
2892 do lookups of @sys entries and thinks it can trust them */
2893 /* privs ok, store the entry, ... */
2894 strcpy(afs_sysname, inname);
2895 if (setsysname > 1) { /* ... or list */
2897 for(count=1; count < setsysname;++count) {
2898 if (!afs_sysnamelist[count])
2899 osi_Panic("PSetSysName: no afs_sysnamelist entry to write\n");
2901 memcpy(afs_sysnamelist[count], cp, t+1); /* include null */
2905 afs_sysnamecount = setsysname;
2909 cp = aout; /* not changing so report back the count and ... */
2910 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
2911 cp += sizeof(afs_int32);
2913 strcpy(cp, outname); /* ... the entry, ... */
2914 cp += strlen(outname)+1;
2915 for(count=1; count < foundname; ++count) { /* ... or list. */
2916 /* Note: we don't support @sys lists for exporters */
2917 if (!afs_sysnamelist[count])
2918 osi_Panic("PSetSysName: no afs_sysnamelist entry to read\n");
2919 t = strlen(afs_sysnamelist[count]);
2920 if (t >= MAXSYSNAME)
2921 osi_Panic("PSetSysName: sysname entry garbled\n");
2922 strcpy(cp, afs_sysnamelist[count]);
2926 *aoutSize = cp - aout;
2931 /* sequential search through the list of touched cells is not a good
2932 * long-term solution here. For small n, though, it should be just
2933 * fine. Should consider special-casing the local cell for large n.
2934 * Likewise for PSetSPrefs.
2936 static void ReSortCells(s,l, vlonly)
2937 int s; /* number of ids in array l[] -- NOT index of last id */
2938 afs_int32 l[]; /* array of cell ids which have volumes that need to be sorted */
2939 int vlonly; /* sort vl servers or file servers?*/
2941 extern struct volume *afs_volumes[NVOLS]; /* volume hash table */
2949 ObtainWriteLock(&afs_xcell,300);
2951 tcell = afs_GetCellNoLock(l[k], WRITE_LOCK);
2952 if (!tcell) continue;
2953 afs_SortServers(tcell->cellHosts, MAXCELLHOSTS);
2954 afs_PutCell(tcell, WRITE_LOCK);
2956 ReleaseWriteLock(&afs_xcell);
2960 ObtainReadLock(&afs_xvolume);
2961 for (i= 0; i< NVOLS; i++) {
2962 for (j=afs_volumes[i];j;j=j->next) {
2964 if (j->cell == l[k]) {
2965 ObtainWriteLock(&j->lock,233);
2966 afs_SortServers(j->serverHost, MAXHOSTS);
2967 ReleaseWriteLock(&j->lock);
2972 ReleaseReadLock(&afs_xvolume);
2977 static int afs_setsprefs(sp, num, vlonly)
2980 unsigned int vlonly;
2983 int i,j,k,matches,touchedSize;
2984 struct server *srvr = NULL;
2985 afs_int32 touched[34];
2989 for (k=0; k < num; sp++, k++) {
2991 printf ("sp host=%x, rank=%d\n",sp->host.s_addr, sp->rank);
2994 ObtainReadLock(&afs_xserver);
2996 i = SHash(sp->host.s_addr);
2997 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2998 if (sa->sa_ip == sp->host.s_addr) {
3000 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3001 || (sa->sa_portal == AFS_FSPORT);
3002 if ((!vlonly && isfs) || (vlonly && !isfs)) {
3009 if (sa && matches) { /* found one! */
3011 printf ("sa ip=%x, ip_rank=%d\n",sa->sa_ip, sa->sa_iprank);
3013 sa->sa_iprank = sp->rank + afs_randomMod15();
3014 afs_SortOneServer(sa->server);
3017 /* if we don't know yet what cell it's in, this is moot */
3018 for (j=touchedSize-1; j>=0 && touched[j] != srvr->cell->cell; j--)
3019 /* is it in our list of touched cells ? */ ;
3020 if (j < 0) { /* no, it's not */
3021 touched[touchedSize++] = srvr->cell->cell;
3022 if (touchedSize >= 32) { /* watch for ovrflow */
3023 ReleaseReadLock(&afs_xserver);
3024 ReSortCells(touchedSize, touched, vlonly);
3026 ObtainReadLock(&afs_xserver);
3032 ReleaseReadLock(&afs_xserver);
3033 /* if we didn't find one, start to create one. */
3034 /* Note that it doesn't have a cell yet... */
3036 afs_uint32 temp = sp->host.s_addr;
3037 srvr = afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
3038 WRITE_LOCK, (afsUUID *)0,0);
3039 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3040 afs_PutServer(srvr, WRITE_LOCK);
3042 } /* for all cited preferences */
3044 ReSortCells(touchedSize, touched, vlonly);
3048 /* Note that this may only be performed by the local root user.
3051 PSetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3054 struct vrequest *areq;
3057 struct AFS_UCRED *acred;
3058 afs_int32 *aoutSize;
3060 struct setspref *ssp;
3061 AFS_STATCNT(PSetSPrefs);
3063 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3064 return EIO; /* Inappropriate ioctl for device */
3066 if (!afs_osi_suser(acred))
3069 if (ainSize < sizeof(struct setspref))
3072 ssp = (struct setspref *)ain;
3073 if (ainSize < sizeof(struct spref)*ssp->num_servers)
3076 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
3077 (ssp->flags & DBservers));
3082 PSetSPrefs33(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3085 struct vrequest *areq;
3088 struct AFS_UCRED *acred;
3089 afs_int32 *aoutSize;
3092 AFS_STATCNT(PSetSPrefs);
3093 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3094 return EIO; /* Inappropriate ioctl for device */
3097 if (!afs_osi_suser(acred))
3100 sp = (struct spref *)ain;
3101 afs_setsprefs(sp, ainSize/(sizeof(struct spref)), 0 /*!vlonly*/);
3105 /* some notes on the following code...
3106 * in the hash table of server structs, all servers with the same IP address
3107 * will be on the same overflow chain.
3108 * This could be sped slightly in some circumstances by having it cache the
3109 * immediately previous slot in the hash table and some supporting information
3110 * Only reports file servers now.
3113 PGetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3116 struct vrequest *areq;
3119 afs_int32 *aoutSize;
3121 struct sprefrequest *spin; /* input */
3122 struct sprefinfo *spout; /* output */
3123 struct spref *srvout; /* one output component */
3124 int i,j; /* counters for hash table traversal */
3125 struct server *srvr; /* one of CM's server structs */
3128 int vlonly; /* just return vlservers ? */
3131 AFS_STATCNT(PGetSPrefs);
3132 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3133 return EIO; /* Inappropriate ioctl for device */
3136 if (ainSize < sizeof (struct sprefrequest_33)) {
3140 spin = ((struct sprefrequest *) ain);
3143 if (ainSize > sizeof (struct sprefrequest_33)) {
3144 vlonly = (spin->flags & DBservers);
3148 /* struct sprefinfo includes 1 server struct... that size gets added
3149 * in during the loop that follows.
3151 *aoutSize = sizeof(struct sprefinfo) - sizeof (struct spref);
3152 spout = (struct sprefinfo *) aout;
3153 spout->next_offset = spin->offset;
3154 spout->num_servers = 0;
3155 srvout = spout->servers;
3157 ObtainReadLock(&afs_xserver);
3158 for (i=0, j=0; j < NSERVERS; j++) { /* sift through hash table */
3159 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3160 if (spin->offset > (unsigned short)i) {
3161 continue; /* catch up to where we left off */
3163 spout->next_offset++;
3166 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3167 || (sa->sa_portal == AFS_FSPORT);
3169 if ((vlonly && isfs) || (!vlonly && !isfs)) {
3170 /* only report ranks for vl servers */
3174 srvout->host.s_addr = sa->sa_ip;
3175 srvout->rank = sa->sa_iprank;
3176 *aoutSize += sizeof(struct spref);
3177 spout->num_servers++;
3180 if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3181 ReleaseReadLock(&afs_xserver); /* no more room! */
3186 ReleaseReadLock(&afs_xserver);
3188 spout->next_offset = 0; /* start over from the beginning next time */
3192 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3193 int afs_NFSRootOnly = 1;
3194 /*static*/ PExportAfs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3197 struct vrequest *areq;
3200 afs_int32 *aoutSize; /* set this */
3201 struct AFS_UCRED *acred;
3203 afs_int32 export, newint=0, type, changestate, handleValue, convmode, pwsync, smounts;
3204 extern struct afs_exporter *exporter_find();
3205 register struct afs_exporter *exporter;
3207 AFS_STATCNT(PExportAfs);
3208 memcpy((char *)&handleValue, ain, sizeof(afs_int32));
3209 type = handleValue >> 24;
3214 exporter = exporter_find(type);
3216 export = handleValue & 3;
3217 changestate = handleValue & 0xff;
3218 smounts = (handleValue >> 2) & 3;
3219 pwsync = (handleValue >> 4) & 3;
3220 convmode = (handleValue >> 6) & 3;
3222 changestate = (handleValue >> 16) & 0x1;
3223 convmode = (handleValue >> 16) & 0x2;
3224 pwsync = (handleValue >> 16) & 0x4;
3225 smounts = (handleValue >> 16) & 0x8;
3226 export = handleValue & 0xff;
3229 /* Failed finding desired exporter; */
3233 handleValue = exporter->exp_states;
3234 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3235 *aoutSize = sizeof(afs_int32);
3237 if (!afs_osi_suser(acred))
3238 return EACCES; /* Only superuser can do this */
3242 exporter->exp_states |= EXP_EXPORTED;
3244 exporter->exp_states &= ~EXP_EXPORTED;
3248 exporter->exp_states |= EXP_UNIXMODE;
3250 exporter->exp_states &= ~EXP_UNIXMODE;
3254 exporter->exp_states |= EXP_PWSYNC;
3256 exporter->exp_states &= ~EXP_PWSYNC;
3260 afs_NFSRootOnly = 0;
3261 exporter->exp_states |= EXP_SUBMOUNTS;
3263 afs_NFSRootOnly = 1;
3264 exporter->exp_states &= ~EXP_SUBMOUNTS;
3267 handleValue = exporter->exp_states;
3268 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3269 *aoutSize = sizeof(afs_int32);
3272 exporter->exp_states |= EXP_EXPORTED;
3274 exporter->exp_states &= ~EXP_EXPORTED;
3276 exporter->exp_states |= EXP_UNIXMODE;
3278 exporter->exp_states &= ~EXP_UNIXMODE;
3280 exporter->exp_states |= EXP_PWSYNC;
3282 exporter->exp_states &= ~EXP_PWSYNC;
3284 afs_NFSRootOnly = 0;
3285 exporter->exp_states |= EXP_SUBMOUNTS;
3287 afs_NFSRootOnly = 1;
3288 exporter->exp_states &= ~EXP_SUBMOUNTS;
3297 PGag(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3300 struct vrequest *areq;
3303 struct AFS_UCRED *acred;
3304 afs_int32 *aoutSize; /* set this */
3306 struct gaginfo *gagflags;
3308 if (!afs_osi_suser(acred))
3311 gagflags = (struct gaginfo *) ain;
3312 afs_showflags = gagflags->showflags;
3319 PTwiddleRx(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3322 struct vrequest *areq;
3325 struct AFS_UCRED *acred;
3326 afs_int32 *aoutSize;
3328 struct rxparams *rxp;
3330 if (!afs_osi_suser(acred))
3333 rxp = (struct rxparams *) ain;
3335 if (rxp->rx_initReceiveWindow)
3336 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3337 if (rxp->rx_maxReceiveWindow)
3338 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3339 if (rxp->rx_initSendWindow)
3340 rx_initSendWindow = rxp->rx_initSendWindow;
3341 if (rxp->rx_maxSendWindow)
3342 rx_maxSendWindow = rxp->rx_maxSendWindow;
3343 if (rxp->rxi_nSendFrags)
3344 rxi_nSendFrags = rxp->rxi_nSendFrags;
3345 if (rxp->rxi_nRecvFrags)
3346 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3347 if (rxp->rxi_OrphanFragSize)
3348 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3349 if (rxp->rx_maxReceiveSize)
3351 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3352 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3354 if (rxp->rx_MyMaxSendSize)
3355 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3360 static int PGetInitParams(avc, afun, areq, ain, aout, ainSize, aoutSize)
3363 struct vrequest *areq;
3367 afs_int32 *aoutSize; /* set this */
3369 if (sizeof(struct cm_initparams) > PIGGYSIZE)
3372 memcpy(aout, (char*)&cm_initParams, sizeof(struct cm_initparams));
3373 *aoutSize = sizeof(struct cm_initparams);
3377 #ifdef AFS_SGI65_ENV
3378 /* They took crget() from us, so fake it. */
3379 static cred_t *crget(void)
3382 cr = crdup(get_current_cred());
3383 memset((char*)cr, 0, sizeof(cred_t));
3384 #if CELL || CELL_PREPARE
3392 PGetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3395 struct vrequest *areq;
3398 afs_int32 *aoutSize;
3399 struct AFS_UCRED *acred;
3401 memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3402 *aoutSize=sizeof(afs_int32);
3407 PSetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3410 struct vrequest *areq;
3413 afs_int32 *aoutSize;
3414 struct AFS_UCRED *acred;
3418 if (!afs_osi_suser(acred))
3420 if (ainSize != sizeof(afs_int32) || ain == NULL)
3422 memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3423 /* if new mappings added later this will need to be changed */
3424 if (tmpval != 0 && tmpval != 1)
3431 * Create new credentials to correspond to a remote user with given
3432 * <hostaddr, uid, g0, g1>. This allows a server running as root to
3433 * provide pioctl (and other) services to foreign clients (i.e. nfs
3434 * clients) by using this call to `become' the client.
3437 #define PIOCTL_HEADER 6
3438 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3441 afs_uint32 hostaddr;
3442 afs_int32 uid, g0, g1, i, code, pag, exporter_type;
3443 extern struct afs_exporter *exporter_find();
3444 struct afs_exporter *exporter, *outexporter;
3445 struct AFS_UCRED *newcred;
3446 struct unixuser *au;
3448 #if defined(AFS_DEC_ENV) || (defined(AFS_NONFSTRANS) && !defined(AFS_AIX_IAUTH_ENV))
3449 return EINVAL; /* NFS trans not supported for Ultrix */
3451 #if defined(AFS_SGIMP_ENV)
3452 osi_Assert(ISAFS_GLOCK());
3454 AFS_STATCNT(HandleClientContext);
3455 if (ablob->in_size < PIOCTL_HEADER*sizeof(afs_int32)) {
3456 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3457 return EINVAL; /* Too small to be good */
3459 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3460 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER*sizeof(afs_int32), code);
3462 osi_FreeLargeSpace(inData);
3466 /* Extract information for remote user */
3467 hostaddr = *((afs_uint32 *)ain);
3468 ain += sizeof(hostaddr);
3469 uid = *((afs_uint32 *)ain);
3471 g0 = *((afs_uint32 *)ain);
3473 g1 = *((afs_uint32 *)ain);
3475 *com = *((afs_uint32 *)ain);
3476 ain += sizeof(afs_int32);
3477 exporter_type = *((afs_uint32 *)ain); /* In case we support more than NFS */
3480 * Of course, one must be root for most of these functions, but
3481 * we'll allow (for knfs) you to set things if the pag is 0 and
3482 * you're setting tokens or unlogging.
3485 if (!afs_osi_suser(credp)) {
3487 #ifndef AFS_SGI64_ENV
3488 /* Since SGI's suser() returns explicit failure after the call.. */
3492 /* check for acceptable opcodes for normal folks, which are, so far,
3493 * set tokens and unlog.
3495 if (i != 9 && i != 3 && i != 38 && i != 8) {
3496 osi_FreeLargeSpace(inData);
3501 ablob->in_size -= PIOCTL_HEADER*sizeof(afs_int32);
3502 ablob->in += PIOCTL_HEADER*sizeof(afs_int32);
3503 osi_FreeLargeSpace(inData);
3506 * We map uid 0 to nobody to match the mapping that the nfs
3507 * server does and to ensure that the suser() calls in the afs
3508 * code fails for remote client roots.
3510 uid = afs_nobody; /* NFS_NOBODY == -2 */
3513 #ifdef AFS_AIX41_ENV
3516 newcred->cr_gid = RMTUSER_REQ;
3517 newcred->cr_groups[0] = g0;
3518 newcred->cr_groups[1] = g1;
3520 newcred->cr_ngrps = 2;
3522 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)
3523 newcred->cr_ngroups = 2;
3525 for (i=2; i<NGROUPS; i++)
3526 newcred->cr_groups[i] = NOGROUP;
3529 #if !defined(AFS_OSF_ENV) && !defined(AFS_DEC_ENV)
3530 afs_nfsclient_init(); /* before looking for exporter, ensure one exists */
3532 if (!(exporter = exporter_find(exporter_type))) {
3533 /* Exporter wasn't initialized or an invalid exporter type */
3537 if (exporter->exp_states & EXP_PWSYNC) {
3538 if (uid != credp->cr_uid) {
3540 return ENOEXEC; /* XXX Find a better errno XXX */
3543 newcred->cr_uid = uid; /* Only temporary */
3544 code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
3545 /* The client's pag is the only unique identifier for it */
3546 newcred->cr_uid = pag;
3548 if (!code && *com == PSETPAG) {
3549 /* Special case for 'setpag' */
3550 afs_uint32 pagvalue = genpag();
3552 au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
3554 * Note that we leave the 'outexporter' struct held so it won't
3557 au->exporter = outexporter;
3558 if (ablob->out_size >= 4) {
3559 AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32), code);
3561 afs_PutUser(au, WRITE_LOCK);
3562 if (code) return code;
3563 return PSETPAG; /* Special return for setpag */
3565 EXP_RELE(outexporter);
3568 #endif /*defined(AFS_DEC_ENV) || defined(AFS_NONFSTRANS)*/
3571 /* get all interface addresses of this client */
3574 PGetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3577 struct vrequest *areq;
3580 afs_int32 *aoutSize;
3582 struct sprefrequest *spin; /* input */
3583 struct sprefinfo *spout; /* output */
3584 struct spref *srvout; /* one output component */
3588 AFS_STATCNT(PGetCPrefs);
3589 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3590 return EIO; /* Inappropriate ioctl for device */
3592 if ( ainSize < sizeof (struct sprefrequest ))
3595 spin = (struct sprefrequest *) ain;
3596 spout = (struct sprefinfo *) aout;
3598 maxNumber = spin->num_servers; /* max addrs this time */
3599 srvout = spout->servers;
3601 ObtainReadLock(&afs_xinterface);
3603 /* copy out the client interface information from the
3604 ** kernel data structure "interface" to the output buffer
3606 for ( i=spin->offset, j=0; (i < afs_cb_interface.numberOfInterfaces)
3607 && ( j< maxNumber) ; i++, j++, srvout++)
3608 srvout->host.s_addr = afs_cb_interface.addr_in[i];
3610 spout->num_servers = j;
3611 *aoutSize = sizeof(struct sprefinfo) +(j-1)* sizeof (struct spref);
3613 if ( i >= afs_cb_interface.numberOfInterfaces )
3614 spout->next_offset = 0; /* start from beginning again */
3616 spout->next_offset = spin->offset + j;
3618 ReleaseReadLock(&afs_xinterface);
3623 PSetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3626 struct vrequest *areq;
3629 afs_int32 *aoutSize;
3631 struct setspref *sin;
3634 AFS_STATCNT(PSetCPrefs);
3635 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3636 return EIO; /* Inappropriate ioctl for device */
3638 sin = (struct setspref *)ain;
3640 if ( ainSize < sizeof(struct setspref) )
3642 #if 0 /* num_servers is unsigned */
3643 if ( sin->num_servers < 0 )
3646 if ( sin->num_servers > AFS_MAX_INTERFACE_ADDR)
3649 ObtainWriteLock(&afs_xinterface, 412);
3650 afs_cb_interface.numberOfInterfaces = sin->num_servers;
3651 for ( i=0; (unsigned short)i < sin->num_servers; i++)
3652 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
3654 ReleaseWriteLock(&afs_xinterface);
3658 static PFlushMount(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3661 struct vrequest *areq;
3664 afs_int32 *aoutSize;
3665 struct AFS_UCRED *acred; {
3666 register afs_int32 code;
3667 register struct vcache *tvc;
3668 register struct dcache *tdc;
3669 struct VenusFid tfid;
3671 struct sysname_info sysState;
3672 afs_size_t offset, len;
3674 AFS_STATCNT(PFlushMount);
3675 if (!avc) return EINVAL;
3676 code = afs_VerifyVCache(avc, areq);
3677 if (code) return code;
3678 if (vType(avc) != VDIR) {
3681 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
3682 if (!tdc) return ENOENT;
3683 Check_AtSys(avc, ain, &sysState, areq);
3684 ObtainReadLock(&tdc->lock);
3686 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
3687 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
3688 ReleaseReadLock(&tdc->lock);
3689 afs_PutDCache(tdc); /* we're done with the data */
3690 bufp = sysState.name;
3694 tfid.Cell = avc->fid.Cell;
3695 tfid.Fid.Volume = avc->fid.Fid.Volume;
3696 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
3697 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
3699 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
3706 if (vType(tvc) != VLNK) {
3707 afs_PutVCache(tvc, WRITE_LOCK);
3711 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3712 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3714 ObtainWriteLock(&tvc->lock,649);
3715 ObtainWriteLock(&afs_xcbhash, 650);
3716 afs_DequeueCallback(tvc);
3717 tvc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
3718 ReleaseWriteLock(&afs_xcbhash);
3719 /* now find the disk cache entries */
3720 afs_TryToSmush(tvc, acred, 1);
3721 osi_dnlc_purgedp(tvc);
3722 afs_symhint_inval(tvc);
3723 if (tvc->linkData && !(tvc->states & CCore)) {
3724 afs_osi_Free(tvc->linkData, strlen(tvc->linkData)+1);
3725 tvc->linkData = (char *) 0;
3727 ReleaseWriteLock(&tvc->lock);
3728 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3729 afs_BozonUnlock(&tvc->pvnLock, tvc);
3731 afs_PutVCache(tvc, WRITE_LOCK);
3733 if (sysState.allocked) osi_FreeLargeSpace(bufp);
3737 static PRxStatProc(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3740 struct vrequest *areq;
3743 afs_int32 *aoutSize;
3744 struct AFS_UCRED *acred;
3749 if (!afs_osi_suser(acred)) {
3753 if (ainSize != sizeof(afs_int32)) {
3757 memcpy((char *)&flags, ain, sizeof(afs_int32));
3758 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3762 if (flags & AFSCALL_RXSTATS_ENABLE) {
3763 rx_enableProcessRPCStats();
3765 if (flags & AFSCALL_RXSTATS_DISABLE) {
3766 rx_disableProcessRPCStats();
3768 if (flags & AFSCALL_RXSTATS_CLEAR) {
3769 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
3777 static PRxStatPeer(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3780 struct vrequest *areq;
3783 afs_int32 *aoutSize;
3784 struct AFS_UCRED *acred;
3789 if (!afs_osi_suser(acred)) {
3793 if (ainSize != sizeof(afs_int32)) {
3797 memcpy((char *)&flags, ain, sizeof(afs_int32));
3798 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3802 if (flags & AFSCALL_RXSTATS_ENABLE) {
3803 rx_enablePeerRPCStats();
3805 if (flags & AFSCALL_RXSTATS_DISABLE) {
3806 rx_disablePeerRPCStats();
3808 if (flags & AFSCALL_RXSTATS_CLEAR) {
3809 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
3816 static PPrefetchFromTape(avc, afun, areq, ain, aout, ainSize, aoutSize)
3819 struct vrequest *areq;
3822 afs_int32 *aoutSize; /* set this */
3824 register afs_int32 code, code1;
3827 struct rx_call *tcall;
3828 struct AFSVolSync tsync;
3829 struct AFSFetchStatus OutStatus;
3830 struct AFSCallBack CallBack;
3831 struct VenusFid tfid;
3836 AFS_STATCNT(PSetAcl);
3840 if (ain && (ainSize == 3 * sizeof(afs_int32)))
3841 Fid = (struct AFSFid *) ain;
3843 Fid = &avc->fid.Fid;
3844 tfid.Cell = avc->fid.Cell;
3845 tfid.Fid.Volume = Fid->Volume;
3846 tfid.Fid.Vnode = Fid->Vnode;
3847 tfid.Fid.Unique = Fid->Unique;
3849 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
3852 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3853 ICL_TYPE_POINTER, tvc,
3854 ICL_TYPE_FID, &tfid,
3855 ICL_TYPE_FID, &avc->fid);
3858 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3859 ICL_TYPE_POINTER, tvc,
3860 ICL_TYPE_FID, &tfid,
3861 ICL_TYPE_FID, &tvc->fid);
3864 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3868 tcall = rx_NewCall(tc->id);
3869 code = StartRXAFS_FetchData(tcall,
3870 (struct AFSFid *) &tvc->fid.Fid, 0, 0);
3872 bytes = rx_Read(tcall, (char *) aout, sizeof(afs_int32));
3873 code = EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
3875 code1 = rx_EndCall(tcall, code);
3880 (afs_Analyze(tc, code, &tvc->fid, areq,
3881 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
3883 /* This call is done only to have the callback things handled correctly */
3884 afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
3885 afs_PutVCache(tvc, WRITE_LOCK);
3888 *aoutSize = sizeof(afs_int32);
3893 static PResidencyCmd(avc, afun, areq, ain, aout, ainSize, aoutSize)
3896 struct vrequest *areq;
3899 afs_int32 *aoutSize; /* set this */
3901 register afs_int32 code;
3904 struct ResidencyCmdInputs *Inputs;
3905 struct ResidencyCmdOutputs *Outputs;
3906 struct VenusFid tfid;
3909 Inputs = (struct ResidencyCmdInputs *) ain;
3910 Outputs = (struct ResidencyCmdOutputs *) aout;
3911 if (!avc) return EINVAL;
3912 if (!ain || ainSize != sizeof(struct ResidencyCmdInputs)) return EINVAL;
3916 Fid = &avc->fid.Fid;
3918 tfid.Cell = avc->fid.Cell;
3919 tfid.Fid.Volume = Fid->Volume;
3920 tfid.Fid.Vnode = Fid->Vnode;
3921 tfid.Fid.Unique = Fid->Unique;
3923 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
3925 afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD,
3926 ICL_TYPE_POINTER, tvc,
3927 ICL_TYPE_INT32, Inputs->command,
3928 ICL_TYPE_FID, &tfid);
3932 if (Inputs->command) {
3934 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3937 code = RXAFS_ResidencyCmd(tc->id, Fid,
3939 (struct ResidencyCmdOutputs *) aout);
3944 (afs_Analyze(tc, code, &tvc->fid, areq,
3945 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
3947 /* This call is done to have the callback things handled correctly */
3948 afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3949 } else { /* just a status request, return also link data */
3951 Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3952 Outputs->chars[0] = 0;
3953 if (vType(tvc) == VLNK) {
3954 ObtainWriteLock(&tvc->lock,555);
3955 if (afs_HandleLink(tvc, areq) == 0)
3956 strncpy((char *) &Outputs->chars, tvc->linkData, MAXCMDCHARS);
3957 ReleaseWriteLock(&tvc->lock);
3961 afs_PutVCache(tvc, WRITE_LOCK);
3964 *aoutSize = sizeof(struct ResidencyCmdOutputs);