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 "../afs/param.h" /* Should be always first */
11 #include <afsconfig.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();
71 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp);
73 extern struct cm_initparams cm_initParams;
75 static int (*(pioctlSw[]))() = {
80 PGetVolumeStatus, /* 4 */
81 PSetVolumeStatus, /* 5 */
86 PCheckServers, /* 10 */
87 PCheckVolNames, /* 11 */
89 PBogus, /* 13 -- used to be quick check time */
91 PBogus, /* 15 -- prefetch is now special-cased; see pioctl code! */
92 PBogus, /* 16 -- used to be testing code */
93 PNoop, /* 17 -- used to be enable group */
94 PNoop, /* 18 -- used to be disable group */
95 PBogus, /* 19 -- used to be list group */
97 PUnlog, /* 21 -- unlog *is* unpag in this system */
98 PGetFID, /* 22 -- get file ID */
99 PBogus, /* 23 -- used to be waitforever */
100 PSetCacheSize, /* 24 */
101 PRemoveCallBack, /* 25 -- flush only the callback */
104 PRemoveMount, /* 28 -- delete mount point */
105 PNewStatMount, /* 29 -- new style mount point stat */
106 PGetFileCell, /* 30 -- get cell name for input file */
107 PGetWSCell, /* 31 -- get cell name for workstation */
108 PMariner, /* 32 - set/get mariner host */
109 PGetUserCell, /* 33 -- get cell name for user */
110 PVenusLogging, /* 34 -- Enable/Disable logging */
111 PGetCellStatus, /* 35 */
112 PSetCellStatus, /* 36 */
113 PFlushVolumeData, /* 37 -- flush all data from a volume */
114 PSetSysName, /* 38 - Set system name */
115 PExportAfs, /* 39 - Export Afs to remote nfs clients */
116 PGetCacheSize, /* 40 - get cache size and usage */
117 PGetVnodeXStatus, /* 41 - get vcache's special status */
118 PSetSPrefs33, /* 42 - Set CM Server preferences... */
119 PGetSPrefs, /* 43 - Get CM Server preferences... */
120 PGag, /* 44 - turn off/on all CM messages */
121 PTwiddleRx, /* 45 - adjust some RX params */
122 PSetSPrefs, /* 46 - Set CM Server preferences... */
123 PStoreBehind, /* 47 - set degree of store behind to be done */
124 PGCPAGs, /* 48 - disable automatic pag gc-ing */
125 PGetInitParams, /* 49 - get initial cm params */
126 PGetCPrefs, /* 50 - get client interface addresses */
127 PSetCPrefs, /* 51 - set client interface addresses */
128 PFlushMount, /* 52 - flush mount symlink data */
129 PRxStatProc, /* 53 - control process RX statistics */
130 PRxStatPeer, /* 54 - control peer RX statistics */
131 PGetRxkcrypt, /* 55 -- Get rxkad encryption flag */
132 PSetRxkcrypt, /* 56 -- Set rxkad encryption flag */
133 PNoop, /* 57 -- arla: set file prio */
134 PNoop, /* 58 -- arla: fallback getfh */
135 PNoop, /* 59 -- arla: fallback fhopen */
136 PNoop, /* 60 -- arla: controls xfsdebug */
137 PNoop, /* 61 -- arla: controls arla debug */
138 PNoop, /* 62 -- arla: debug interface */
139 PNoop, /* 63 -- arla: print xfs status */
140 PNoop, /* 64 -- arla: force cache check */
141 PNoop, /* 65 -- arla: break callback */
142 PPrefetchFromTape, /* 66 -- MR-AFS: prefetch file from tape */
143 PResidencyCmd, /* 67 -- MR-AFS: generic commnd interface */
146 #define PSetClientContext 99 /* Special pioctl to setup caller's creds */
147 int afs_nobody = NFS_NOBODY;
150 afs_ioctl32_to_afs_ioctl(const struct afs_ioctl32 *src, struct afs_ioctl *dst)
152 dst->in = (char *)(unsigned long)src->in;
153 dst->out = (char *)(unsigned long)src->out;
154 dst->in_size = src->in_size;
155 dst->out_size = src->out_size;
159 * If you need to change copyin_afs_ioctl(), you may also need to change
164 copyin_afs_ioctl(caddr_t cmarg, struct afs_ioctl *dst)
168 #if defined(AFS_HPUX_64BIT_ENV)
169 struct afs_ioctl32 dst32;
171 if (is_32bit(u.u_procp)) /* is_32bit() in proc_iface.h */
173 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
175 afs_ioctl32_to_afs_ioctl(&dst32, dst);
178 #endif /* defined(AFS_HPUX_64BIT_ENV) */
180 #if defined(AFS_SUN57_64BIT_ENV)
181 struct afs_ioctl32 dst32;
183 if (get_udatamodel() == DATAMODEL_ILP32) {
184 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
186 afs_ioctl32_to_afs_ioctl(&dst32, dst);
189 #endif /* defined(AFS_SUN57_64BIT_ENV) */
191 #if defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64)
192 struct afs_ioctl32 dst32;
194 if (!ABI_IS_64BIT(get_current_abi()))
196 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
198 afs_ioctl32_to_afs_ioctl(&dst32, dst);
201 #endif /* defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64) */
203 #if defined(AFS_LINUX_64BIT_KERNEL) && !defined(AFS_ALPHA_LINUX20_ENV)
204 struct afs_ioctl32 dst32;
206 #ifdef AFS_SPARC64_LINUX24_ENV
207 if (current->thread.flags & SPARC_FLAG_32BIT)
208 #elif AFS_SPARC64_LINUX20_ENV
209 if (current->tss.flags & SPARC_FLAG_32BIT)
211 #error Not done for this linux type
212 #endif /* AFS_SPARC64_LINUX20_ENV */
214 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
216 afs_ioctl32_to_afs_ioctl(&dst32, dst);
219 #endif /* defined(AFS_LINUX_64BIT_KERNEL) */
221 AFS_COPYIN(cmarg, (caddr_t) dst, sizeof *dst, code);
225 HandleIoctl(avc, acom, adata)
226 register struct vcache *avc;
227 register afs_int32 acom;
228 struct afs_ioctl *adata; {
229 register afs_int32 code;
232 AFS_STATCNT(HandleIoctl);
234 switch(acom & 0xff) {
236 avc->states |= CSafeStore;
240 /* case 2 used to be abort store, but this is no longer provided,
241 since it is impossible to implement under normal Unix.
245 /* return the name of the cell this file is open on */
246 register struct cell *tcell;
247 register afs_int32 i;
249 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
251 i = strlen(tcell->cellName) + 1; /* bytes to copy out */
253 if (i > adata->out_size) {
254 /* 0 means we're not interested in the output */
255 if (adata->out_size != 0) code = EFAULT;
259 AFS_COPYOUT(tcell->cellName, adata->out, i, code);
261 afs_PutCell(tcell, READ_LOCK);
267 case 49: /* VIOC_GETINITPARAMS */
268 if (adata->out_size < sizeof(struct cm_initparams)) {
272 AFS_COPYOUT(&cm_initParams, adata->out,
273 sizeof(struct cm_initparams), code);
282 return code; /* so far, none implemented */
287 /* For aix we don't temporarily bypass ioctl(2) but rather do our
288 * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
289 * is now called from afs_gn_ioctl.
291 afs_ioctl(tvc, cmd, arg)
296 struct afs_ioctl data;
299 AFS_STATCNT(afs_ioctl);
300 if (((cmd >> 8) & 0xff) == 'V') {
301 /* This is a VICEIOCTL call */
302 AFS_COPYIN(arg, (caddr_t) &data, sizeof(data), error);
305 error = HandleIoctl(tvc, cmd, &data);
308 /* No-op call; just return. */
312 #endif /* AFS_AIX_ENV */
314 #if defined(AFS_SGI_ENV)
315 afs_ioctl(OSI_VN_DECL(tvc), int cmd, void * arg, int flag, cred_t *cr, rval_t *rvalp
321 struct afs_ioctl data;
327 AFS_STATCNT(afs_ioctl);
328 if (((cmd >> 8) & 0xff) == 'V') {
329 /* This is a VICEIOCTL call */
330 error = copyin_afs_ioctl(arg, &data);
333 locked = ISAFS_GLOCK();
336 error = HandleIoctl(tvc, cmd, &data);
341 /* No-op call; just return. */
345 #endif /* AFS_SGI_ENV */
348 /* unlike most calls here, this one uses u.u_error to return error conditions,
349 since this is really an intercepted chapter 2 call, rather than a vnode
352 /* AFS_HPUX102 and up uses VNODE ioctl instead */
353 #ifndef AFS_HPUX102_ENV
354 #if !defined(AFS_SGI_ENV)
356 kioctl(fdes, com, arg, ext)
363 } u_uap, *uap = &u_uap;
367 struct afs_ioctl_sys {
373 afs_xioctl (uap, rvp)
374 struct afs_ioctl_sys *uap;
379 afs_xioctl (p, args, retval)
388 } *uap = (struct a *)args;
389 #else /* AFS_OSF_ENV */
390 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
396 afs_xioctl(p, uap, retval)
398 register struct ioctl_args *uap;
402 #ifdef AFS_LINUX22_ENV
403 struct afs_ioctl_sys {
407 asmlinkage int afs_xioctl(struct inode *ip, struct file *fp,
408 unsigned int com, unsigned long arg)
410 struct afs_ioctl_sys ua, *uap = &ua;
418 } *uap = (struct a *)u.u_ap;
419 #endif /* AFS_LINUX22_ENV */
420 #endif /* AFS_DARWIN_ENV || AFS_FBSD_ENV */
421 #endif /* AFS_OSF_ENV */
422 #endif /* AFS_SUN5_ENV */
424 #ifndef AFS_LINUX22_ENV
425 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
428 register struct file *fd;
431 register struct vcache *tvc;
432 register int ioctlDone = 0, code = 0;
434 AFS_STATCNT(afs_xioctl);
435 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
436 if ((code=fdgetf(p, uap->fd, &fd)))
439 #ifdef AFS_LINUX22_ENV
447 if (setuerror(getf(uap->fd, &fd))) {
453 if (code = getf(&fd, uap->fd, FILE_FLAGS_NULL, &u.u_file_state))
455 #else /* AFS_OSF_ENV */
457 #if defined(AFS_SUN57_ENV)
459 if (!fd) return(EBADF);
460 #elif defined(AFS_SUN54_ENV)
462 if (!fd) return(EBADF);
464 if (code = getf(uap->fd, &fd)) {
477 /* first determine whether this is any sort of vnode */
478 #ifdef AFS_LINUX22_ENV
479 tvc = (struct vcache *)ip;
483 if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
485 if (fd->f_type == DTYPE_VNODE) {
487 /* good, this is a vnode; next see if it is an AFS vnode */
488 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
489 tvc = (struct vcache *) fd->f_vnode; /* valid, given a vnode */
491 tvc = (struct vcache *) fd->f_data; /* valid, given a vnode */
493 #endif /* AFS_LINUX22_ENV */
494 if (tvc && IsAfsVnode((struct vnode *)tvc)) {
496 tvc = (struct vcache *) afs_gntovn((struct gnode *) tvc);
497 if (!tvc) { /* shouldn't happen with held gnodes */
502 /* This is an AFS vnode */
503 if (((uap->com >> 8) & 0xff) == 'V') {
504 register struct afs_ioctl *datap;
506 datap = (struct afs_ioctl *) osi_AllocSmallSpace(AFS_SMALLOCSIZ);
507 AFS_COPYIN((char *)uap->arg, (caddr_t) datap, sizeof (struct afs_ioctl), code);
509 osi_FreeSmallSpace(datap);
511 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
514 #if defined(AFS_SUN5_ENV)
529 #else /* AFS_OSF_ENV */
533 #ifdef AFS_LINUX22_ENV
543 code = HandleIoctl(tvc, uap->com, datap);
544 osi_FreeSmallSpace(datap);
558 #if defined(AFS_LINUX22_ENV)
568 code = okioctl(fdes, com, arg, ext);
572 okioctl(fdes, com, arg, ext);
574 #if defined(AFS_SUN5_ENV)
575 #if defined(AFS_SUN57_ENV)
577 #elif defined(AFS_SUN54_ENV)
582 code = ioctl(uap, rvp);
584 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
585 return ioctl(p, uap, retval);
588 code = ioctl(p, args, retval);
595 #else /* AFS_OSF_ENV */
596 #ifndef AFS_LINUX22_ENV
614 #ifdef AFS_LINUX22_ENV
617 #if !defined(AFS_OSF_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
620 #if defined(AFS_AIX32_ENV) && !defined(AFS_AIX41_ENV)
621 return (getuerror() ? -1 : u.u_ioctlrv);
623 return getuerror() ? -1 : 0;
626 #endif /* AFS_LINUX22_ENV */
627 #endif /* AFS_SUN5_ENV */
628 #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
632 #endif /* AFS_SGI_ENV */
633 #endif /* AFS_HPUX102_ENV */
635 #if defined(AFS_SGI_ENV)
636 /* "pioctl" system call entry point; just pass argument to the parameterized
645 afs_pioctl(struct pioctlargs *uap, rval_t *rvp)
649 AFS_STATCNT(afs_pioctl);
651 code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
659 #endif /* AFS_SGI_ENV */
662 afs_pioctl(p, args, retval)
672 } *uap = (struct a *) args;
674 AFS_STATCNT(afs_pioctl);
675 return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow));
678 extern struct mount *afs_globalVFS;
679 #else /* AFS_OSF_ENV */
680 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
681 afs_pioctl(p, args, retval)
691 } *uap = (struct a *) args;
693 AFS_STATCNT(afs_pioctl);
694 return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow, p->p_cred->pc_ucred));
697 extern struct mount *afs_globalVFS;
698 #else /* AFS_OSF_ENV */
699 extern struct vfs *afs_globalVFS;
703 /* macro to avoid adding any more #ifdef's to pioctl code. */
704 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
705 #define PIOCTL_FREE_CRED() crfree(credp)
707 #define PIOCTL_FREE_CRED()
711 afs_syscall_pioctl(path, com, cmarg, follow, rvp, credp)
713 struct AFS_UCRED *credp;
715 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
716 afs_syscall_pioctl(path, com, cmarg, follow, credp)
717 struct AFS_UCRED *credp;
719 afs_syscall_pioctl(path, com, cmarg, follow)
727 struct afs_ioctl data;
728 struct AFS_UCRED *tmpcred, *foreigncreds = 0;
729 register afs_int32 code = 0;
735 struct ucred *credp = crref(); /* don't free until done! */
737 #ifdef AFS_LINUX22_ENV
738 cred_t *credp = crref(); /* don't free until done! */
741 AFS_STATCNT(afs_syscall_pioctl);
742 if (follow) follow = 1; /* compat. with old venus */
744 if (! _VALIDVICEIOCTL(com)) {
746 #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
748 #else /* AFS_OSF_ENV */
749 #if defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV)
758 code = copyin_afs_ioctl(cmarg, &data);
761 #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)
768 if ((com & 0xff) == PSetClientContext) {
769 #if defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
770 return EINVAL; /* Not handling these yet. */
772 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
773 code = HandleClientContext(&data, &com, &foreigncreds, credp);
775 #if defined(AFS_HPUX101_ENV)
776 code=HandleClientContext(&data, &com, &foreigncreds, p_cred(u.u_procp));
779 code = HandleClientContext(&data, &com, &foreigncreds, OSI_GET_CURRENT_CRED());
781 code = HandleClientContext(&data, &com, &foreigncreds, u.u_cred);
782 #endif /* AFS_SGI_ENV */
788 crfree(foreigncreds);
791 #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)
794 return (setuerror(code), code);
798 #if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
801 * We could have done without temporary setting the u.u_cred below
802 * (foreigncreds could be passed as param the pioctl modules)
803 * but calls such as afs_osi_suser() doesn't allow that since it
804 * references u.u_cred directly. We could, of course, do something
805 * like afs_osi_suser(cred) which, I think, is better since it
806 * generalizes and supports multi cred environments...
810 credp = foreigncreds;
813 tmpcred = crref(); /* XXX */
816 #if defined(AFS_HPUX101_ENV)
817 tmpcred = p_cred(u.u_procp);
818 set_p_cred(u.u_procp, foreigncreds);
821 tmpcred = OSI_GET_CURRENT_CRED();
822 OSI_SET_CURRENT_CRED(foreigncreds);
825 u.u_cred = foreigncreds;
826 #endif /* AFS_SGI64_ENV */
827 #endif /* AFS_HPUX101_ENV */
832 if ((com & 0xff) == 15) {
833 /* special case prefetch so entire pathname eval occurs in helper process.
834 otherwise, the pioctl call is essentially useless */
835 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
836 code = Prefetch(path, &data, follow,
837 foreigncreds ? foreigncreds : credp);
839 #if defined(AFS_HPUX101_ENV)
840 code = Prefetch(path, &data, follow, p_cred(u.u_procp));
843 code = Prefetch(path, &data, follow, OSI_GET_CURRENT_CRED());
845 code = Prefetch(path, &data, follow, u.u_cred);
846 #endif /* AFS_SGI64_ENV */
847 #endif /* AFS_HPUX101_ENV */
849 #if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
852 crset(tmpcred); /* restore original credentials */
854 #if defined(AFS_HPUX101_ENV)
855 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
859 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
861 u.u_cred = tmpcred; /* restore original credentials */
864 #endif /* AFS_HPUX101_ENV */
865 crfree(foreigncreds);
868 #endif /* AFS_LINUX22_ENV */
870 #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)
873 return (setuerror(code), code);
879 code = lookupname(path, USR, follow, NULL, &vp,
880 foreigncreds ? foreigncreds : credp);
882 #ifdef AFS_LINUX22_ENV
883 code = gop_lookupname(path, AFS_UIOUSER, follow, (struct vnode **) 0, &dp);
885 vp = (struct vnode *)dp->d_inode;
887 code = gop_lookupname(path, AFS_UIOUSER, follow, (struct vnode **) 0, &vp);
888 #endif /* AFS_LINUX22_ENV */
889 #endif /* AFS_AIX41_ENV */
892 #if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
895 crset(tmpcred); /* restore original credentials */
897 #if defined(AFS_HPUX101_ENV)
898 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
900 #if !defined(AFS_SUN5_ENV)
902 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
904 u.u_cred = tmpcred; /* restore original credentials */
905 #endif /* AFS_SGI64_ENV */
907 #endif /* AFS_HPUX101_ENV */
908 crfree(foreigncreds);
911 #endif /* AFS_LINUX22_ENV */
913 #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)
916 return(setuerror(code), code);
920 else vp = (struct vnode *) 0;
922 /* now make the call if we were passed no file, or were passed an AFS file */
923 if (!vp || IsAfsVnode(vp)) {
925 /* Ultrix 4.0: can't get vcache entry unless we've got an AFS gnode.
926 * So, we must test in this part of the code. Also, must arrange to
927 * GRELE the original gnode pointer when we're done, since in Ultrix 4.0,
928 * we hold gnodes, whose references hold our vcache entries.
931 gp = vp; /* remember for "put" */
932 vp = (struct vnode *) afs_gntovn(vp); /* get vcache from gp */
934 else gp = (struct vnode *) 0;
937 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
941 struct ucred *cred1, *cred2;
944 cred1 = cred2 = foreigncreds;
946 cred1 = cred2 = credp;
948 code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
949 if (cred1 != cred2) {
950 /* something changed the creds */
955 #if defined(AFS_HPUX101_ENV)
957 struct ucred *cred = p_cred(u.u_procp);
958 code = afs_HandlePioctl(vp, com, &data, follow, &cred);
964 credp = OSI_GET_CURRENT_CRED();
965 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
968 #if defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
969 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
971 code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
973 #endif /* AFS_SGI_ENV */
974 #endif /* AFS_HPUX101_ENV */
975 #endif /* AFS_AIX41_ENV */
976 #endif /* AFS_SUN5_ENV */
978 #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)
979 code = EINVAL; /* not in /afs */
986 vp = (struct vnode *) 0;
991 #if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
996 #if defined(AFS_HPUX101_ENV)
997 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
1001 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
1003 u.u_cred = tmpcred; /* restore original credentials */
1004 #endif /* ASF_SGI64_ENV */
1006 #endif /* AFS_HPUX101_ENV */
1007 crfree(foreigncreds);
1010 #endif /* AFS_LINUX22_ENV */
1012 #ifdef AFS_LINUX22_ENV
1015 AFS_RELE(vp); /* put vnode back */
1019 #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)
1024 return (getuerror());
1029 afs_HandlePioctl(avc, acom, ablob, afollow, acred)
1030 register struct vcache *avc;
1032 struct AFS_UCRED **acred;
1033 register struct afs_ioctl *ablob;
1036 struct vrequest treq;
1037 register afs_int32 code;
1038 register afs_int32 function;
1039 afs_int32 inSize, outSize;
1040 char *inData, *outData;
1042 afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
1043 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
1044 AFS_STATCNT(HandlePioctl);
1045 if (code = afs_InitReq(&treq, *acred)) return code;
1046 function = acom & 0xff;
1047 if (function >= (sizeof(pioctlSw) / sizeof(char *))) {
1048 return EINVAL; /* out of range */
1050 inSize = ablob->in_size;
1051 if (inSize >= PIGGYSIZE) return E2BIG;
1052 inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1054 AFS_COPYIN(ablob->in, inData, inSize, code);
1058 osi_FreeLargeSpace(inData);
1061 outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1063 if (function == 3) /* PSetTokens */
1064 code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, acred);
1066 code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, *acred);
1067 osi_FreeLargeSpace(inData);
1068 if (code == 0 && ablob->out_size > 0) {
1069 if (outSize > ablob->out_size) outSize = ablob->out_size;
1070 if (outSize >= PIGGYSIZE) code = E2BIG;
1072 AFS_COPYOUT(outData, ablob->out, outSize, code);
1074 osi_FreeLargeSpace(outData);
1075 return afs_CheckCode(code, &treq, 41);
1078 static PGetFID(avc, afun, areq, ain, aout, ainSize, aoutSize)
1081 struct vrequest *areq;
1084 afs_int32 *aoutSize; /* set this */ {
1085 register afs_int32 code;
1087 AFS_STATCNT(PGetFID);
1088 if (!avc) return EINVAL;
1089 bcopy((char *)&avc->fid, aout, sizeof(struct VenusFid));
1090 *aoutSize = sizeof(struct VenusFid);
1094 static PSetAcl(avc, afun, areq, ain, aout, ainSize, aoutSize)
1097 struct vrequest *areq;
1100 afs_int32 *aoutSize; /* set this */ {
1101 register afs_int32 code;
1103 struct AFSOpaque acl;
1104 struct AFSVolSync tsync;
1105 struct AFSFetchStatus OutStatus;
1108 AFS_STATCNT(PSetAcl);
1111 if ((acl.AFSOpaque_len = strlen(ain)+1) > 1000)
1114 acl.AFSOpaque_val = ain;
1116 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1118 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1119 #ifdef RX_ENABLE_LOCKS
1121 #endif /* RX_ENABLE_LOCKS */
1122 code = RXAFS_StoreACL(tconn->id, (struct AFSFid *) &avc->fid.Fid,
1123 &acl, &OutStatus, &tsync);
1124 #ifdef RX_ENABLE_LOCKS
1126 #endif /* RX_ENABLE_LOCKS */
1131 (afs_Analyze(tconn, code, &avc->fid, areq,
1132 AFS_STATS_FS_RPCIDX_STOREACL, SHARED_LOCK, (struct cell *)0));
1134 /* now we've forgotten all of the access info */
1135 ObtainWriteLock(&afs_xcbhash, 455);
1137 afs_DequeueCallback(avc);
1138 avc->states &= ~(CStatd | CUnique);
1139 ReleaseWriteLock(&afs_xcbhash);
1140 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1141 osi_dnlc_purgedp(avc);
1145 int afs_defaultAsynchrony = 0;
1147 static PStoreBehind(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1150 struct vrequest *areq;
1153 afs_int32 *aoutSize; /* set this */
1154 struct AFS_UCRED *acred;
1157 struct sbstruct *sbr;
1159 sbr = (struct sbstruct *)ain;
1160 if (sbr->sb_default != -1) {
1161 if (afs_osi_suser(acred))
1162 afs_defaultAsynchrony = sbr->sb_default;
1166 if (avc && (sbr->sb_thisfile != -1))
1167 if (afs_AccessOK(avc, PRSFS_WRITE | PRSFS_ADMINISTER,
1168 areq, DONT_CHECK_MODE_BITS))
1169 avc->asynchrony = sbr->sb_thisfile;
1172 *aoutSize = sizeof(struct sbstruct);
1173 sbr = (struct sbstruct *)aout;
1174 sbr->sb_default = afs_defaultAsynchrony;
1176 sbr->sb_thisfile = avc->asynchrony;
1182 static PGCPAGs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1185 struct vrequest *areq;
1188 afs_int32 *aoutSize; /* set this */
1189 struct AFS_UCRED *acred;
1191 if (!afs_osi_suser(acred)) {
1194 afs_gcpags = AFS_GCPAGS_USERDISABLED;
1198 static PGetAcl(avc, afun, areq, ain, aout, ainSize, aoutSize)
1201 struct vrequest *areq;
1204 afs_int32 *aoutSize; /* set this */ {
1205 struct AFSOpaque acl;
1206 struct AFSVolSync tsync;
1207 struct AFSFetchStatus OutStatus;
1213 AFS_STATCNT(PGetAcl);
1214 if (!avc) return EINVAL;
1215 Fid.Volume = avc->fid.Fid.Volume;
1216 Fid.Vnode = avc->fid.Fid.Vnode;
1217 Fid.Unique = avc->fid.Fid.Unique;
1218 if (avc->states & CForeign) {
1220 * For a dfs xlator acl we have a special hack so that the
1221 * xlator will distinguish which type of acl will return. So
1222 * we currently use the top 2-bytes (vals 0-4) to tell which
1223 * type of acl to bring back. Horrible hack but this will
1224 * cause the least number of changes to code size and interfaces.
1226 if (Fid.Vnode & 0xc0000000)
1228 Fid.Vnode |= (ainSize << 30);
1230 acl.AFSOpaque_val = aout;
1232 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1235 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1236 #ifdef RX_ENABLE_LOCKS
1238 #endif /* RX_ENABLE_LOCKS */
1239 code = RXAFS_FetchACL(tconn->id, &Fid,
1240 &acl, &OutStatus, &tsync);
1241 #ifdef RX_ENABLE_LOCKS
1243 #endif /* RX_ENABLE_LOCKS */
1248 (afs_Analyze(tconn, code, &avc->fid, areq,
1249 AFS_STATS_FS_RPCIDX_FETCHACL,
1250 SHARED_LOCK, (struct cell *)0));
1253 *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1264 AFS_STATCNT(PBogus);
1268 static PGetFileCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1271 struct vrequest *areq;
1275 afs_int32 *aoutSize; /* set this */ {
1276 register struct cell *tcell;
1278 AFS_STATCNT(PGetFileCell);
1279 if (!avc) return EINVAL;
1280 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
1281 if (!tcell) return ESRCH;
1282 strcpy(aout, tcell->cellName);
1283 afs_PutCell(tcell, READ_LOCK);
1284 *aoutSize = strlen(aout) + 1;
1288 static PGetWSCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1291 struct vrequest *areq;
1295 afs_int32 *aoutSize; /* set this */ {
1296 register struct cell *tcell=0, *cellOne=0;
1297 register struct afs_q *cq, *tq;
1299 AFS_STATCNT(PGetWSCell);
1300 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1301 return EIO; /* Inappropriate ioctl for device */
1303 ObtainReadLock(&afs_xcell);
1304 cellOne = (struct cell *) 0;
1306 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
1307 tcell = QTOC(cq); tq = QNext(cq);
1308 if (tcell->states & CPrimary) break;
1309 if (tcell->cell == 1) cellOne = tcell;
1312 ReleaseReadLock(&afs_xcell);
1313 if (!tcell) { /* no primary cell, use cell #1 */
1314 if (!cellOne) return ESRCH;
1317 strcpy(aout, tcell->cellName);
1318 *aoutSize = strlen(aout) + 1;
1322 static PGetUserCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1325 struct vrequest *areq;
1329 afs_int32 *aoutSize; /* set this */ {
1330 register afs_int32 i;
1331 register struct unixuser *tu;
1332 register struct cell *tcell;
1334 AFS_STATCNT(PGetUserCell);
1335 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1336 return EIO; /* Inappropriate ioctl for device */
1338 /* return the cell name of the primary cell for this user */
1339 i = UHash(areq->uid);
1340 ObtainWriteLock(&afs_xuser,224);
1341 for(tu = afs_users[i]; tu; tu = tu->next) {
1342 if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1344 ReleaseWriteLock(&afs_xuser);
1349 tcell = afs_GetCell(tu->cell, READ_LOCK);
1350 afs_PutUser(tu, WRITE_LOCK);
1351 if (!tcell) return ESRCH;
1353 strcpy(aout, tcell->cellName);
1354 afs_PutCell(tcell, READ_LOCK);
1355 *aoutSize = strlen(aout)+1; /* 1 for the null */
1359 ReleaseWriteLock(&afs_xuser);
1366 static PSetTokens(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1369 struct vrequest *areq;
1373 afs_int32 *aoutSize; /* set this */
1374 struct AFS_UCRED **acred;
1377 register struct unixuser *tu;
1378 struct ClearToken clear;
1379 register struct cell *tcell;
1382 struct vrequest treq;
1383 afs_int32 flag, set_parent_pag = 0;
1385 AFS_STATCNT(PSetTokens);
1386 if (!afs_resourceinit_flag) {
1389 bcopy(ain, (char *)&i, sizeof(afs_int32));
1390 ain += sizeof(afs_int32);
1391 stp = ain; /* remember where the ticket is */
1392 if (i < 0 || i > 2000) return EINVAL; /* malloc may fail */
1394 ain += i; /* skip over ticket */
1395 bcopy(ain, (char *)&i, sizeof(afs_int32));
1396 ain += sizeof(afs_int32);
1397 if (i != sizeof(struct ClearToken)) {
1400 bcopy(ain, (char *)&clear, sizeof(struct ClearToken));
1401 if (clear.AuthHandle == -1) clear.AuthHandle = 999; /* more rxvab compat stuff */
1402 ain += sizeof(struct ClearToken);
1403 if (ainSize != 2*sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1404 /* still stuff left? we've got primary flag and cell name. Set these */
1405 bcopy(ain, (char *)&flag, sizeof(afs_int32)); /* primary id flag */
1406 ain += sizeof(afs_int32); /* skip id field */
1407 /* rest is cell name, look it up */
1408 if (flag & 0x8000) { /* XXX Use Constant XXX */
1412 tcell = afs_GetCellByName(ain, READ_LOCK);
1421 /* default to cell 1, primary id */
1422 flag = 1; /* primary id */
1423 i = 1; /* cell number */
1424 tcell = afs_GetCell(1, READ_LOCK);
1425 if (!tcell) goto nocell;
1427 afs_PutCell(tcell, READ_LOCK);
1428 if (set_parent_pag) {
1430 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1431 struct proc *p=current_proc(); /* XXX */
1432 uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1433 p->p_pid, p->p_comm);
1434 if (!setpag(p, acred, -1, &pag, 1)) {
1437 if (!setpag(u.u_procp, acred, -1, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
1439 if (!setpag(acred, -1, &pag, 1)) {
1442 afs_InitReq(&treq, *acred);
1446 /* now we just set the tokens */
1447 tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1448 tu->vid = clear.ViceId;
1449 if (tu->stp != (char *) 0) {
1450 afs_osi_Free(tu->stp, tu->stLen);
1452 tu->stp = (char *) afs_osi_Alloc(stLen);
1454 bcopy(stp, tu->stp, stLen);
1457 afs_stats_cmfullperf.authent.TicketUpdates++;
1458 afs_ComputePAGStats();
1459 #endif /* AFS_NOSTATS */
1460 tu->states |= UHasTokens;
1461 tu->states &= ~UTokensBad;
1462 afs_SetPrimary(tu, flag);
1463 tu->tokenTime =osi_Time();
1464 afs_ResetUserConns(tu);
1465 afs_PutUser(tu, WRITE_LOCK);
1480 static PGetVolumeStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
1483 struct vrequest *areq;
1486 afs_int32 *aoutSize; /* set this */ {
1488 char offLineMsg[256];
1490 register struct conn *tc;
1491 register afs_int32 code;
1492 struct VolumeStatus volstat;
1494 char *Name, *OfflineMsg, *MOTD;
1497 AFS_STATCNT(PGetVolumeStatus);
1498 if (!avc) return EINVAL;
1500 OfflineMsg = offLineMsg;
1503 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1505 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1506 #ifdef RX_ENABLE_LOCKS
1508 #endif /* RX_ENABLE_LOCKS */
1509 code = RXAFS_GetVolumeStatus(tc->id, avc->fid.Fid.Volume, &volstat,
1510 &Name, &OfflineMsg, &MOTD);
1511 #ifdef RX_ENABLE_LOCKS
1513 #endif /* RX_ENABLE_LOCKS */
1518 (afs_Analyze(tc, code, &avc->fid, areq,
1519 AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1520 SHARED_LOCK, (struct cell *)0));
1522 if (code) return code;
1523 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1525 bcopy((char *)&volstat, cp, sizeof(VolumeStatus));
1526 cp += sizeof(VolumeStatus);
1527 strcpy(cp, volName);
1528 cp += strlen(volName)+1;
1529 strcpy(cp, offLineMsg);
1530 cp += strlen(offLineMsg)+1;
1532 cp += strlen(motd)+1;
1533 *aoutSize = (cp - aout);
1537 static PSetVolumeStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
1540 struct vrequest *areq;
1543 afs_int32 *aoutSize; /* set this */ {
1545 char offLineMsg[256];
1547 register struct conn *tc;
1548 register afs_int32 code;
1549 struct AFSFetchVolumeStatus volstat;
1550 struct AFSStoreVolumeStatus storeStat;
1551 register struct volume *tvp;
1555 AFS_STATCNT(PSetVolumeStatus);
1556 if (!avc) return EINVAL;
1558 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
1560 if (tvp->states & (VRO | VBackup)) {
1561 afs_PutVolume(tvp, READ_LOCK);
1564 afs_PutVolume(tvp, READ_LOCK);
1567 /* Copy the junk out, using cp as a roving pointer. */
1569 bcopy(cp, (char *)&volstat, sizeof(AFSFetchVolumeStatus));
1570 cp += sizeof(AFSFetchVolumeStatus);
1571 if (strlen(cp) >= sizeof(volName))
1573 strcpy(volName, cp);
1574 cp += strlen(volName)+1;
1575 if (strlen(cp) >= sizeof(offLineMsg))
1577 strcpy(offLineMsg, cp);
1578 cp += strlen(offLineMsg)+1;
1579 if (strlen(cp) >= sizeof(motd))
1583 if (volstat.MinQuota != -1) {
1584 storeStat.MinQuota = volstat.MinQuota;
1585 storeStat.Mask |= AFS_SETMINQUOTA;
1587 if (volstat.MaxQuota != -1) {
1588 storeStat.MaxQuota = volstat.MaxQuota;
1589 storeStat.Mask |= AFS_SETMAXQUOTA;
1592 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1594 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1595 #ifdef RX_ENABLE_LOCKS
1597 #endif /* RX_ENABLE_LOCKS */
1598 code = RXAFS_SetVolumeStatus(tc->id, avc->fid.Fid.Volume,
1599 &storeStat, volName, offLineMsg, motd);
1600 #ifdef RX_ENABLE_LOCKS
1602 #endif /* RX_ENABLE_LOCKS */
1607 (afs_Analyze(tc, code, &avc->fid, areq,
1608 AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1609 SHARED_LOCK, (struct cell *)0));
1611 if (code) return code;
1612 /* we are sending parms back to make compat. with prev system. should
1613 change interface later to not ask for current status, just set new status */
1615 bcopy((char *)&volstat, cp, sizeof(VolumeStatus));
1616 cp += sizeof(VolumeStatus);
1617 strcpy(cp, volName);
1618 cp += strlen(volName)+1;
1619 strcpy(cp, offLineMsg);
1620 cp += strlen(offLineMsg)+1;
1622 cp += strlen(motd)+1;
1623 *aoutSize = cp - aout;
1627 static PFlush(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1628 register struct vcache *avc;
1630 struct vrequest *areq;
1633 afs_int32 *aoutSize; /* set this */
1634 struct AFS_UCRED *acred;
1637 AFS_STATCNT(PFlush);
1638 if (!avc) return EINVAL;
1639 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1640 afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
1642 ObtainWriteLock(&avc->lock,225);
1643 ObtainWriteLock(&afs_xcbhash, 456);
1644 afs_DequeueCallback(avc);
1645 avc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
1646 ReleaseWriteLock(&afs_xcbhash);
1647 /* now find the disk cache entries */
1648 afs_TryToSmush(avc, acred, 1);
1649 osi_dnlc_purgedp(avc);
1650 afs_symhint_inval(avc);
1651 if (avc->linkData && !(avc->states & CCore)) {
1652 afs_osi_Free(avc->linkData, strlen(avc->linkData)+1);
1653 avc->linkData = (char *) 0;
1655 ReleaseWriteLock(&avc->lock);
1656 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1657 afs_BozonUnlock(&avc->pvnLock, avc);
1662 static PNewStatMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
1665 struct vrequest *areq;
1668 afs_int32 *aoutSize; /* set this */ {
1669 register afs_int32 code;
1670 register struct vcache *tvc;
1671 register struct dcache *tdc;
1672 struct VenusFid tfid;
1674 struct sysname_info sysState;
1675 afs_int32 offset, len;
1677 AFS_STATCNT(PNewStatMount);
1678 if (!avc) return EINVAL;
1679 code = afs_VerifyVCache(avc, areq);
1680 if (code) return code;
1681 if (vType(avc) != VDIR) {
1684 tdc = afs_GetDCache(avc, 0, areq, &offset, &len, 1);
1685 if (!tdc) return ENOENT;
1686 Check_AtSys(avc, ain, &sysState, areq);
1688 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
1689 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1690 bufp = sysState.name;
1695 tfid.Cell = avc->fid.Cell;
1696 tfid.Fid.Volume = avc->fid.Fid.Volume;
1697 afs_PutDCache(tdc); /* we're done with the data */
1698 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
1699 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
1701 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
1708 if (vType(tvc) != VLNK) {
1709 afs_PutVCache(tvc, WRITE_LOCK);
1713 ObtainWriteLock(&tvc->lock,226);
1714 code = afs_HandleLink(tvc, areq);
1716 if (tvc->linkData) {
1717 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1720 /* we have the data */
1721 strcpy(aout, tvc->linkData);
1722 *aoutSize = strlen(tvc->linkData)+1;
1727 ReleaseWriteLock(&tvc->lock);
1728 afs_PutVCache(tvc, WRITE_LOCK);
1730 if (sysState.allocked) osi_FreeLargeSpace(bufp);
1734 static PGetTokens(avc, afun, areq, ain, aout, ainSize, aoutSize)
1737 struct vrequest *areq;
1740 afs_int32 *aoutSize; /* set this */ {
1741 register struct cell *tcell;
1742 register afs_int32 i;
1743 register struct unixuser *tu;
1748 AFS_STATCNT(PGetTokens);
1749 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1750 return EIO; /* Inappropriate ioctl for device */
1752 /* weird interface. If input parameter is present, it is an integer and
1753 we're supposed to return the parm'th tokens for this unix uid.
1754 If not present, we just return tokens for cell 1.
1755 If counter out of bounds, return EDOM.
1756 If no tokens for the particular cell, return ENOTCONN.
1757 Also, if this mysterious parm is present, we return, along with the
1758 tokens, the primary cell indicator (an afs_int32 0) and the cell name
1759 at the end, in that order.
1761 if (newStyle = (ainSize > 0)) {
1762 bcopy(ain, (char *)&iterator, sizeof(afs_int32));
1764 i = UHash(areq->uid);
1765 ObtainReadLock(&afs_xuser);
1766 for(tu = afs_users[i]; tu; tu=tu->next) {
1768 if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1769 if (iterator-- == 0) break; /* are we done yet? */
1773 if (tu->uid == areq->uid && tu->cell == 1) break;
1778 * No need to hold a read lock on each user entry
1782 ReleaseReadLock(&afs_xuser);
1787 if (((tu->states & UHasTokens) == 0) || (tu->ct.EndTimestamp < osi_Time())) {
1788 tu->states |= (UTokensBad | UNeedsReset);
1789 afs_PutUser(tu, READ_LOCK);
1792 /* use iterator for temp */
1794 iterator = tu->stLen; /* for compat, we try to return 56 byte tix if they fit */
1795 if (iterator < 56) iterator = 56; /* # of bytes we're returning */
1796 bcopy((char *)&iterator, cp, sizeof(afs_int32));
1797 cp += sizeof(afs_int32);
1798 bcopy(tu->stp, cp, tu->stLen); /* copy out st */
1800 iterator = sizeof(struct ClearToken);
1801 bcopy((char *)&iterator, cp, sizeof(afs_int32));
1802 cp += sizeof(afs_int32);
1803 bcopy((char *)&tu->ct, cp, sizeof(struct ClearToken));
1804 cp += sizeof(struct ClearToken);
1806 /* put out primary id and cell name, too */
1807 iterator = (tu->states & UPrimary ? 1 : 0);
1808 bcopy((char *)&iterator, cp, sizeof(afs_int32));
1809 cp += sizeof(afs_int32);
1810 tcell = afs_GetCell(tu->cell, READ_LOCK);
1812 strcpy(cp, tcell->cellName);
1813 cp += strlen(tcell->cellName)+1;
1814 afs_PutCell(tcell, READ_LOCK);
1818 *aoutSize = cp - aout;
1819 afs_PutUser(tu, READ_LOCK);
1823 static PUnlog(avc, afun, areq, ain, aout, ainSize, aoutSize)
1826 struct vrequest *areq;
1829 afs_int32 *aoutSize; /* set this */ {
1830 register afs_int32 i;
1831 register struct unixuser *tu;
1833 AFS_STATCNT(PUnlog);
1834 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1835 return EIO; /* Inappropriate ioctl for device */
1837 i = UHash(areq->uid);
1838 ObtainWriteLock(&afs_xuser,227);
1839 for(tu=afs_users[i]; tu; tu=tu->next) {
1840 if (tu->uid == areq->uid) {
1842 tu->states &= ~UHasTokens;
1843 /* security is not having to say you're sorry */
1844 bzero((char *)&tu->ct, sizeof(struct ClearToken));
1846 ReleaseWriteLock(&afs_xuser);
1847 /* We have to drop the lock over the call to afs_ResetUserConns, since
1848 * it obtains the afs_xvcache lock. We could also keep the lock, and
1849 * modify ResetUserConns to take parm saying we obtained the lock
1850 * already, but that is overkill. By keeping the "tu" pointer
1851 * held over the released lock, we guarantee that we won't lose our
1852 * place, and that we'll pass over every user conn that existed when
1853 * we began this call.
1855 afs_ResetUserConns(tu);
1857 ObtainWriteLock(&afs_xuser,228);
1859 /* set the expire times to 0, causes
1860 * afs_GCUserData to remove this entry
1862 tu->ct.EndTimestamp = 0;
1864 #endif /* UKERNEL */
1867 ReleaseWriteLock(&afs_xuser);
1871 static PMariner(avc, afun, areq, ain, aout, ainSize, aoutSize)
1874 struct vrequest *areq;
1877 afs_int32 *aoutSize; /* set this */ {
1878 afs_int32 newHostAddr;
1879 afs_int32 oldHostAddr;
1881 AFS_STATCNT(PMariner);
1883 bcopy((char *)&afs_marinerHost, (char *)&oldHostAddr, sizeof(afs_int32));
1885 oldHostAddr = 0xffffffff; /* disabled */
1887 bcopy(ain, (char *)&newHostAddr, sizeof(afs_int32));
1888 if (newHostAddr == 0xffffffff) {
1889 /* disable mariner operations */
1892 else if (newHostAddr) {
1894 afs_marinerHost = newHostAddr;
1896 bcopy((char *)&oldHostAddr, aout, sizeof(afs_int32));
1897 *aoutSize = sizeof(afs_int32);
1901 static PCheckServers(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1904 struct vrequest *areq;
1907 afs_int32 *aoutSize; /* set this */
1908 struct AFS_UCRED *acred;
1910 register char *cp = 0;
1912 register struct server *ts;
1913 afs_int32 temp, *lp = (afs_int32 *)ain, havecell=0;
1915 struct chservinfo *pcheck;
1917 AFS_STATCNT(PCheckServers);
1919 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1920 return EIO; /* Inappropriate ioctl for device */
1922 if (*lp == 0x12345678) { /* For afs3.3 version */
1923 pcheck=(struct chservinfo *)ain;
1924 if (pcheck->tinterval >= 0) {
1926 bcopy((char *)&PROBE_INTERVAL, cp, sizeof(afs_int32));
1927 *aoutSize = sizeof(afs_int32);
1928 if (pcheck->tinterval > 0) {
1929 if (!afs_osi_suser(acred))
1931 PROBE_INTERVAL=pcheck->tinterval;
1937 temp=pcheck->tflags;
1938 cp = pcheck->tbuffer;
1939 } else { /* For pre afs3.3 versions */
1940 bcopy(ain, (char *)&temp, sizeof(afs_int32));
1941 cp = ain+sizeof(afs_int32);
1942 if (ainSize > sizeof(afs_int32))
1947 * 1: fast check, don't contact servers.
1948 * 2: local cell only.
1951 /* have cell name, too */
1952 cellp = afs_GetCellByName(cp, READ_LOCK);
1953 if (!cellp) return ENOENT;
1955 else cellp = (struct cell *) 0;
1956 if (!cellp && (temp & 2)) {
1957 /* use local cell */
1958 cellp = afs_GetCell(1, READ_LOCK);
1960 if (!(temp & 1)) { /* if not fast, call server checker routine */
1961 afs_CheckServers(1, cellp); /* check down servers */
1962 afs_CheckServers(0, cellp); /* check up servers */
1964 /* now return the current down server list */
1966 ObtainReadLock(&afs_xserver);
1967 for(i=0;i<NSERVERS;i++) {
1968 for(ts = afs_servers[i]; ts; ts=ts->next) {
1969 if (cellp && ts->cell != cellp) continue; /* cell spec'd and wrong */
1970 if ((ts->flags & SRVR_ISDOWN) && ts->addr->sa_portal != ts->cell->vlport) {
1971 bcopy((char *)&ts->addr->sa_ip, cp, sizeof(afs_int32));
1972 cp += sizeof(afs_int32);
1976 ReleaseReadLock(&afs_xserver);
1977 if (cellp) afs_PutCell(cellp, READ_LOCK);
1978 *aoutSize = cp - aout;
1982 static PCheckVolNames(avc, afun, areq, ain, aout, ainSize, aoutSize)
1985 struct vrequest *areq;
1988 afs_int32 *aoutSize; /* set this */ {
1989 AFS_STATCNT(PCheckVolNames);
1990 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1991 return EIO; /* Inappropriate ioctl for device */
1993 afs_CheckRootVolume();
1994 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE |
1995 AFS_VOLCHECK_EXPIRED |
1997 AFS_VOLCHECK_MTPTS);
2001 static PCheckAuth(avc, afun, areq, ain, aout, ainSize, aoutSize)
2004 struct vrequest *areq;
2007 afs_int32 *aoutSize; /* set this */ {
2011 struct unixuser *tu;
2013 extern afs_rwlock_t afs_xsrvAddr;
2015 AFS_STATCNT(PCheckAuth);
2016 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2017 return EIO; /* Inappropriate ioctl for device */
2020 tu = afs_GetUser(areq->uid, 1, READ_LOCK); /* check local cell authentication */
2021 if (!tu) retValue = EACCES;
2023 /* we have a user */
2024 ObtainReadLock(&afs_xsrvAddr);
2025 ObtainReadLock(&afs_xconn);
2027 /* any tokens set? */
2028 if ((tu->states & UHasTokens) == 0) retValue = EACCES;
2029 /* all connections in cell 1 working? */
2030 for(i=0;i<NSERVERS;i++) {
2031 for(sa = afs_srvAddrs[i]; sa; sa=sa->next_bkt) {
2032 for (tc = sa->conns; tc; tc=tc->next) {
2033 if (tc->user == tu && (tu->states & UTokensBad))
2038 ReleaseReadLock(&afs_xsrvAddr);
2039 ReleaseReadLock(&afs_xconn);
2040 afs_PutUser(tu, READ_LOCK);
2042 bcopy((char *)&retValue, aout, sizeof(afs_int32));
2043 *aoutSize = sizeof(afs_int32);
2047 static Prefetch(apath, adata, afollow, acred)
2049 struct afs_ioctl *adata;
2051 struct AFS_UCRED *acred;
2054 register afs_int32 code;
2055 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2061 AFS_STATCNT(Prefetch);
2062 if (!apath) return EINVAL;
2063 tp = osi_AllocLargeSpace(1024);
2064 AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2066 osi_FreeLargeSpace(tp);
2069 if (afs_BBusy()) { /* do this as late as possible */
2070 osi_FreeLargeSpace(tp);
2071 return EWOULDBLOCK; /* pretty close */
2073 afs_BQueue(BOP_PATH, (struct vcache*)0, 0, 0, acred, (long)tp, 0L, 0L, 0L);
2077 static PFindVolume(avc, afun, areq, ain, aout, ainSize, aoutSize)
2080 struct vrequest *areq;
2083 afs_int32 *aoutSize; /* set this */ {
2084 register struct volume *tvp;
2085 register struct server *ts;
2086 register afs_int32 i;
2089 AFS_STATCNT(PFindVolume);
2090 if (!avc) return EINVAL;
2091 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
2094 for(i=0;i<MAXHOSTS;i++) {
2095 ts = tvp->serverHost[i];
2097 bcopy((char *)&ts->addr->sa_ip, cp, sizeof(afs_int32));
2098 cp += sizeof(afs_int32);
2101 /* still room for terminating NULL, add it on */
2102 ainSize = 0; /* reuse vbl */
2103 bcopy((char *)&ainSize, cp, sizeof(afs_int32));
2104 cp += sizeof(afs_int32);
2106 *aoutSize = cp - aout;
2107 afs_PutVolume(tvp, READ_LOCK);
2113 static PViceAccess(avc, afun, areq, ain, aout, ainSize, aoutSize)
2116 struct vrequest *areq;
2119 afs_int32 *aoutSize; /* set this */ {
2120 register afs_int32 code;
2123 AFS_STATCNT(PViceAccess);
2124 if (!avc) return EINVAL;
2125 code = afs_VerifyVCache(avc, areq);
2126 if (code) return code;
2127 bcopy(ain, (char *)&temp, sizeof(afs_int32));
2128 code = afs_AccessOK(avc,temp, areq, CHECK_MODE_BITS);
2133 static PSetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2136 struct vrequest *areq;
2139 afs_int32 *aoutSize; /* set this */
2140 struct AFS_UCRED *acred;
2145 AFS_STATCNT(PSetCacheSize);
2146 if (!afs_osi_suser(acred))
2148 /* too many things are setup initially in mem cache version */
2149 if (cacheDiskType == AFS_FCACHE_TYPE_MEM) return EROFS;
2150 bcopy(ain, (char *)&newValue, sizeof(afs_int32));
2151 if (newValue == 0) afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2153 extern u_int afs_min_cache;
2154 if (newValue < afs_min_cache)
2155 afs_cacheBlocks = afs_min_cache;
2157 afs_cacheBlocks = newValue;
2159 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2160 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2161 afs_MaybeWakeupTruncateDaemon();
2162 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2163 afs_osi_Wait(1000, 0, 0);
2164 afs_MaybeWakeupTruncateDaemon();
2169 #define MAXGCSTATS 16
2170 static PGetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize)
2173 struct vrequest *areq;
2176 afs_int32 *aoutSize; /* set this */ {
2177 afs_int32 results[MAXGCSTATS];
2179 AFS_STATCNT(PGetCacheSize);
2180 bzero((char *)results, sizeof(results));
2181 results[0] = afs_cacheBlocks;
2182 results[1] = afs_blocksUsed;
2183 bcopy((char *)results, aout, sizeof(results));
2184 *aoutSize = sizeof(results);
2188 static PRemoveCallBack(avc, afun, areq, ain, aout, ainSize, aoutSize)
2191 struct vrequest *areq;
2194 afs_int32 *aoutSize; /* set this */ {
2195 register struct conn *tc;
2196 register afs_int32 code;
2197 struct AFSCallBack CallBacks_Array[1];
2198 struct AFSCBFids theFids;
2199 struct AFSCBs theCBs;
2202 AFS_STATCNT(PRemoveCallBack);
2203 if (!avc) return EINVAL;
2204 if (avc->states & CRO) return 0; /* read-only-ness can't change */
2205 ObtainWriteLock(&avc->lock,229);
2206 theFids.AFSCBFids_len = 1;
2207 theCBs.AFSCBs_len = 1;
2208 theFids.AFSCBFids_val = (struct AFSFid *) &avc->fid.Fid;
2209 theCBs.AFSCBs_val = CallBacks_Array;
2210 CallBacks_Array[0].CallBackType = CB_DROPPED;
2211 if (avc->callback) {
2213 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2215 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2216 #ifdef RX_ENABLE_LOCKS
2218 #endif /* RX_ENABLE_LOCKS */
2219 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2220 #ifdef RX_ENABLE_LOCKS
2222 #endif /* RX_ENABLE_LOCKS */
2225 /* don't set code on failure since we wouldn't use it */
2227 (afs_Analyze(tc, code, &avc->fid, areq,
2228 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS,
2229 SHARED_LOCK, (struct cell *)0));
2231 ObtainWriteLock(&afs_xcbhash, 457);
2232 afs_DequeueCallback(avc);
2234 avc->states &= ~(CStatd | CUnique);
2235 ReleaseWriteLock(&afs_xcbhash);
2236 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2237 osi_dnlc_purgedp(avc);
2239 ReleaseWriteLock(&avc->lock);
2243 static PNewCell(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2246 struct vrequest *areq;
2250 struct AFS_UCRED *acred;
2251 afs_int32 *aoutSize; /* set this */ {
2252 /* create a new cell */
2253 afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic=0;
2254 register struct cell *tcell;
2255 char *newcell=0, *linkedcell=0, *tp= ain;
2256 register afs_int32 code, linkedstate=0, ls;
2257 u_short fsport = 0, vlport = 0;
2260 AFS_STATCNT(PNewCell);
2261 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2262 return EIO; /* Inappropriate ioctl for device */
2264 if (!afs_osi_suser(acred))
2267 bcopy(tp, (char *)&magic, sizeof(afs_int32));
2268 tp += sizeof(afs_int32);
2269 if (magic != 0x12345678)
2272 /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2273 * server addresses while the 3.5 fs newcell command passes
2274 * MAXHOSTS. To figure out which is which, check if the cellname
2277 newcell = tp + (MAXCELLHOSTS+3)*sizeof(afs_int32);
2278 scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2280 /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2281 bcopy(tp, (char *)cellHosts, MAXCELLHOSTS * sizeof(afs_int32));
2282 tp += (scount * sizeof(afs_int32));
2284 lp = (afs_int32 *)tp;
2287 if (fsport < 1024) fsport = 0; /* Privileged ports not allowed */
2288 if (vlport < 1024) vlport = 0; /* Privileged ports not allowed */
2289 tp += (3 * sizeof(afs_int32));
2291 if ((ls = *lp) & 1) {
2292 linkedcell = tp + strlen(newcell)+1;
2293 linkedstate |= CLinkedCell;
2296 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2297 code = afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport, vlport, (int)0);
2301 static PListCells(avc, afun, areq, ain, aout, ainSize, aoutSize)
2304 struct vrequest *areq;
2307 afs_int32 *aoutSize; /* set this */ {
2308 afs_int32 whichCell;
2309 register struct cell *tcell=0;
2310 register afs_int32 i;
2311 register char *cp, *tp = ain;
2312 register struct afs_q *cq, *tq;
2314 AFS_STATCNT(PListCells);
2315 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2316 return EIO; /* Inappropriate ioctl for device */
2318 bcopy(tp, (char *)&whichCell, sizeof(afs_int32));
2319 tp += sizeof(afs_int32);
2320 ObtainReadLock(&afs_xcell);
2321 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2322 tcell = QTOC(cq); tq = QNext(cq);
2323 if (whichCell == 0) break;
2324 if (tq == &CellLRU) tcell = 0;
2329 bzero(cp, MAXCELLHOSTS * sizeof(afs_int32));
2330 for(i=0;i<MAXCELLHOSTS;i++) {
2331 if (tcell->cellHosts[i] == 0) break;
2332 bcopy((char *)&tcell->cellHosts[i]->addr->sa_ip, cp, sizeof(afs_int32));
2333 cp += sizeof(afs_int32);
2335 cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2336 strcpy(cp, tcell->cellName);
2337 cp += strlen(tcell->cellName)+1;
2338 *aoutSize = cp - aout;
2340 ReleaseReadLock(&afs_xcell);
2341 if (tcell) return 0;
2345 static PRemoveMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
2348 struct vrequest *areq;
2352 afs_int32 *aoutSize; /* set this */ {
2353 register afs_int32 code;
2355 struct sysname_info sysState;
2356 afs_int32 offset, len;
2357 register struct conn *tc;
2358 register struct dcache *tdc;
2359 register struct vcache *tvc;
2360 struct AFSFetchStatus OutDirStatus;
2361 struct VenusFid tfid;
2362 struct AFSVolSync tsync;
2366 /* "ain" is the name of the file in this dir to remove */
2368 AFS_STATCNT(PRemoveMount);
2369 if (!avc) return EINVAL;
2370 code = afs_VerifyVCache(avc, areq);
2371 if (code) return code;
2372 if (vType(avc) != VDIR) return ENOTDIR;
2374 tdc = afs_GetDCache(avc, 0, areq, &offset, &len, 1); /* test for error below */
2375 if (!tdc) return ENOENT;
2376 Check_AtSys(avc, ain, &sysState, areq);
2378 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
2379 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2380 bufp = sysState.name;
2385 tfid.Cell = avc->fid.Cell;
2386 tfid.Fid.Volume = avc->fid.Fid.Volume;
2387 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
2388 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
2390 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0,
2391 (struct vcache*)0/*xxx avc?*/, WRITE_LOCK);
2398 if (vType(tvc) != VLNK) {
2400 afs_PutVCache(tvc, WRITE_LOCK);
2404 ObtainWriteLock(&tvc->lock,230);
2405 code = afs_HandleLink(tvc, areq);
2407 if (tvc->linkData) {
2408 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2413 ReleaseWriteLock(&tvc->lock);
2414 osi_dnlc_purgedp(tvc);
2415 afs_PutVCache(tvc, WRITE_LOCK);
2420 ObtainWriteLock(&avc->lock,231);
2421 osi_dnlc_remove(avc, bufp, tvc);
2423 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2425 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2426 #ifdef RX_ENABLE_LOCKS
2428 #endif /* RX_ENABLE_LOCKS */
2429 code = RXAFS_RemoveFile(tc->id, (struct AFSFid *) &avc->fid.Fid,
2430 bufp, &OutDirStatus, &tsync);
2431 #ifdef RX_ENABLE_LOCKS
2433 #endif /* RX_ENABLE_LOCKS */
2438 (afs_Analyze(tc, code, &avc->fid, areq,
2439 AFS_STATS_FS_RPCIDX_REMOVEFILE,
2440 SHARED_LOCK, (struct cell *)0));
2443 if (tdc) afs_PutDCache(tdc);
2444 ReleaseWriteLock(&avc->lock);
2448 /* we have the thing in the cache */
2449 if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2450 /* we can do it locally */
2451 code = afs_dir_Delete(&tdc->f.inode, bufp);
2453 ZapDCE(tdc); /* surprise error -- invalid value */
2454 DZap(&tdc->f.inode);
2457 afs_PutDCache(tdc); /* drop ref count */
2459 avc->states &= ~CUnique; /* For the dfs xlator */
2460 ReleaseWriteLock(&avc->lock);
2463 if (sysState.allocked) osi_FreeLargeSpace(bufp);
2467 static PVenusLogging(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2470 struct vrequest *areq;
2474 struct AFS_UCRED *acred;
2475 afs_int32 *aoutSize; /* set this */ {
2476 return EINVAL; /* OBSOLETE */
2479 static PGetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2482 struct vrequest *areq;
2485 afs_int32 *aoutSize; /* set this */ {
2486 register struct cell *tcell;
2489 AFS_STATCNT(PGetCellStatus);
2490 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2491 return EIO; /* Inappropriate ioctl for device */
2493 tcell = afs_GetCellByName(ain, READ_LOCK);
2494 if (!tcell) return ENOENT;
2495 temp = tcell->states;
2496 afs_PutCell(tcell, READ_LOCK);
2497 bcopy((char *)&temp, aout, sizeof(afs_int32));
2498 *aoutSize = sizeof(afs_int32);
2502 static PSetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2505 struct vrequest *areq;
2508 struct AFS_UCRED *acred;
2509 afs_int32 *aoutSize; /* set this */ {
2510 register struct cell *tcell;
2513 if (!afs_osi_suser(acred))
2515 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2516 return EIO; /* Inappropriate ioctl for device */
2518 tcell = afs_GetCellByName(ain+2*sizeof(afs_int32), WRITE_LOCK);
2519 if (!tcell) return ENOENT;
2520 bcopy(ain, (char *)&temp, sizeof(afs_int32));
2522 tcell->states |= CNoSUID;
2524 tcell->states &= ~CNoSUID;
2525 afs_PutCell(tcell, WRITE_LOCK);
2529 static PFlushVolumeData(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2532 struct vrequest *areq;
2535 afs_int32 *aoutSize; /* set this */
2536 struct AFS_UCRED *acred;
2538 extern struct volume *afs_volumes[NVOLS];
2539 register afs_int32 i;
2540 register struct dcache *tdc;
2541 register struct vcache *tvc;
2542 register struct volume *tv;
2543 afs_int32 cell, volume;
2545 AFS_STATCNT(PFlushVolumeData);
2548 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2549 return EIO; /* Inappropriate ioctl for device */
2551 volume = avc->fid.Fid.Volume; /* who to zap */
2552 cell = avc->fid.Cell;
2555 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
2556 * the vcaches associated with the volume.
2558 ObtainReadLock(&afs_xvcache);
2559 for(i = 0; i < VCSIZE; i++) {
2560 for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
2561 if (tvc->fid.Fid.Volume == volume && tvc->fid.Cell == cell) {
2562 #if defined(AFS_SGI_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV)
2563 VN_HOLD((struct vnode *)tvc);
2565 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2571 ReleaseReadLock(&afs_xvcache);
2572 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2573 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
2575 ObtainWriteLock(&tvc->lock,232);
2577 ObtainWriteLock(&afs_xcbhash, 458);
2578 afs_DequeueCallback(tvc);
2579 tvc->states &= ~(CStatd | CDirty);
2580 ReleaseWriteLock(&afs_xcbhash);
2581 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
2582 osi_dnlc_purgedp(tvc);
2583 afs_TryToSmush(tvc, acred, 1);
2584 ReleaseWriteLock(&tvc->lock);
2585 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2586 afs_BozonUnlock(&tvc->pvnLock, tvc);
2588 ObtainReadLock(&afs_xvcache);
2589 /* our tvc ptr is still good until now */
2594 ReleaseReadLock(&afs_xvcache);
2597 MObtainWriteLock(&afs_xdcache,328); /* needed if you're going to flush any stuff */
2598 for(i=0;i<afs_cacheFiles;i++) {
2599 if (!(afs_indexFlags[i] & IFEverUsed)) continue; /* never had any data */
2600 tdc = afs_GetDSlot(i, (struct dcache *) 0);
2601 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
2602 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
2603 if (! (afs_indexFlags[i] & IFDataMod)) {
2604 /* if the file is modified, but has a ref cnt of only 1, then
2605 someone probably has the file open and is writing into it.
2606 Better to skip flushing such a file, it will be brought back
2607 immediately on the next write anyway.
2609 If we *must* flush, then this code has to be rearranged to call
2610 afs_storeAllSegments() first */
2611 afs_FlushDCache(tdc);
2615 tdc->refCount--; /* bumped by getdslot */
2617 MReleaseWriteLock(&afs_xdcache);
2619 ObtainReadLock(&afs_xvolume);
2620 for (i=0;i<NVOLS;i++) {
2621 for (tv = afs_volumes[i]; tv; tv=tv->next) {
2622 if (tv->volume == volume) {
2623 afs_ResetVolumeInfo(tv);
2628 ReleaseReadLock(&afs_xvolume);
2630 /* probably, a user is doing this, probably, because things are screwed up.
2631 * maybe it's the dnlc's fault? */
2638 static PGetVnodeXStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2641 struct vrequest *areq;
2644 afs_int32 *aoutSize; /* set this */ {
2645 register afs_int32 code;
2646 struct vcxstat stat;
2649 /* AFS_STATCNT(PGetVnodeXStatus); */
2650 if (!avc) return EINVAL;
2651 code = afs_VerifyVCache(avc, areq);
2652 if (code) return code;
2653 if (vType(avc) == VDIR)
2654 mode = PRSFS_LOOKUP;
2657 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
2659 stat.fid = avc->fid;
2660 hset32(stat.DataVersion, hgetlo(avc->m.DataVersion));
2661 stat.lock = avc->lock;
2662 stat.parentVnode = avc->parentVnode;
2663 stat.parentUnique = avc->parentUnique;
2664 hset(stat.flushDV, avc->flushDV);
2665 hset(stat.mapDV, avc->mapDV);
2666 stat.truncPos = avc->truncPos;
2667 { /* just grab the first two - won't break anything... */
2668 struct axscache *ac;
2670 for (i=0, ac=avc->Access; ac && i < CPSIZE; i++, ac=ac->next) {
2671 stat.randomUid[i] = ac->uid;
2672 stat.randomAccess[i] = ac->axess;
2675 stat.callback = afs_data_pointer_to_int32(avc->callback);
2676 stat.cbExpires = avc->cbExpires;
2677 stat.anyAccess = avc->anyAccess;
2678 stat.opens = avc->opens;
2679 stat.execsOrWriters = avc->execsOrWriters;
2680 stat.flockCount = avc->flockCount;
2681 stat.mvstat = avc->mvstat;
2682 stat.states = avc->states;
2683 bcopy((char *)&stat, aout, sizeof(struct vcxstat));
2684 *aoutSize = sizeof(struct vcxstat);
2689 /* We require root for local sysname changes, but not for remote */
2690 /* (since we don't really believe remote uids anyway) */
2691 /* outname[] shouldn't really be needed- this is left as an excercise */
2692 /* for the reader. */
2693 static PSetSysName(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2696 struct vrequest *areq;
2699 afs_int32 *aoutSize; /* set this */
2700 register struct AFS_UCRED *acred;
2702 char *cp, inname[MAXSYSNAME], outname[MAXSYSNAME];
2703 int setsysname, foundname=0;
2704 register struct afs_exporter *exporter;
2705 extern struct unixuser *afs_FindUser();
2706 extern char *afs_sysname;
2707 extern char *afs_sysnamelist[];
2708 extern int afs_sysnamecount;
2709 register struct unixuser *au;
2710 register afs_int32 pag, error;
2714 AFS_STATCNT(PSetSysName);
2715 if (!afs_globalVFS) {
2716 /* Afsd is NOT running; disable it */
2717 #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)
2720 return (setuerror(EINVAL), EINVAL);
2723 bzero(inname, MAXSYSNAME);
2724 bcopy(ain, (char *)&setsysname, sizeof(afs_int32));
2725 ain += sizeof(afs_int32);
2729 if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
2731 for(cp = ain,count = 0;count < setsysname;count++) {
2732 /* won't go past end of ain since maxsysname*num < ain length */
2734 if (t >= MAXSYSNAME || t <= 0)
2736 /* check for names that can shoot us in the foot */
2737 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
2743 /* inname gets first entry in case we're being a translater */
2745 bcopy(ain, inname, t+1); /* include terminating null */
2748 if (acred->cr_gid == RMTUSER_REQ) { /* Handles all exporters */
2749 pag = PagInCred(acred);
2751 return EINVAL; /* Better than panicing */
2753 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
2754 return EINVAL; /* Better than panicing */
2756 if (!(exporter = au->exporter)) {
2757 afs_PutUser(au, READ_LOCK);
2758 return EINVAL; /* Better than panicing */
2760 error = EXP_SYSNAME(exporter, (setsysname? inname : (char *)0), outname);
2762 if (error == ENODEV) foundname = 0; /* sysname not set yet! */
2764 afs_PutUser(au, READ_LOCK);
2769 afs_PutUser(au, READ_LOCK);
2772 /* Not xlating, so local case */
2773 if (!afs_sysname) osi_Panic("PSetSysName: !afs_sysname\n");
2774 if (!setsysname) { /* user just wants the info */
2775 strcpy(outname, afs_sysname);
2776 foundname = afs_sysnamecount;
2777 } else { /* Local guy; only root can change sysname */
2778 if (!afs_osi_suser(acred))
2781 /* clear @sys entries from the dnlc, once afs_lookup can
2782 do lookups of @sys entries and thinks it can trust them */
2783 /* privs ok, store the entry, ... */
2784 strcpy(afs_sysname, inname);
2785 if (setsysname > 1) { /* ... or list */
2787 for(count=1; count < setsysname;++count) {
2788 if (!afs_sysnamelist[count])
2789 osi_Panic("PSetSysName: no afs_sysnamelist entry to write\n");
2791 bcopy(cp, afs_sysnamelist[count], t+1); /* include null */
2795 afs_sysnamecount = setsysname;
2799 cp = aout; /* not changing so report back the count and ... */
2800 bcopy((char *)&foundname, cp, sizeof(afs_int32));
2801 cp += sizeof(afs_int32);
2803 strcpy(cp, outname); /* ... the entry, ... */
2804 cp += strlen(outname)+1;
2805 for(count=1; count < foundname; ++count) { /* ... or list. */
2806 /* Note: we don't support @sys lists for exporters */
2807 if (!afs_sysnamelist[count])
2808 osi_Panic("PSetSysName: no afs_sysnamelist entry to read\n");
2809 t = strlen(afs_sysnamelist[count]);
2810 if (t >= MAXSYSNAME)
2811 osi_Panic("PSetSysName: sysname entry garbled\n");
2812 strcpy(cp, afs_sysnamelist[count]);
2816 *aoutSize = cp - aout;
2821 /* sequential search through the list of touched cells is not a good
2822 * long-term solution here. For small n, though, it should be just
2823 * fine. Should consider special-casing the local cell for large n.
2824 * Likewise for PSetSPrefs.
2826 static void ReSortCells(s,l, vlonly)
2827 int s; /* number of ids in array l[] -- NOT index of last id */
2828 afs_int32 l[]; /* array of cell ids which have volumes that need to be sorted */
2829 int vlonly; /* sort vl servers or file servers?*/
2831 extern struct volume *afs_volumes[NVOLS]; /* volume hash table */
2840 tcell = afs_GetCell(l[k], WRITE_LOCK);
2841 if (!tcell) continue;
2842 afs_SortServers(tcell->cellHosts, MAXCELLHOSTS);
2843 afs_PutCell(tcell, WRITE_LOCK);
2848 ObtainReadLock(&afs_xvolume);
2849 for (i= 0; i< NVOLS; i++) {
2850 for (j=afs_volumes[i];j;j=j->next) {
2852 if (j->cell == l[k]) {
2853 ObtainWriteLock(&j->lock,233);
2854 afs_SortServers(j->serverHost, MAXHOSTS);
2855 ReleaseWriteLock(&j->lock);
2860 ReleaseReadLock(&afs_xvolume);
2865 static int afs_setsprefs(sp, num, vlonly)
2868 unsigned int vlonly;
2871 int i,j,k,matches,touchedSize;
2872 struct server *srvr = NULL;
2873 afs_int32 touched[34];
2877 for (k=0; k < num; sp++, k++) {
2879 printf ("sp host=%x, rank=%d\n",sp->host.s_addr, sp->rank);
2882 ObtainReadLock(&afs_xserver);
2884 i = SHash(sp->host.s_addr);
2885 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2886 if (sa->sa_ip == sp->host.s_addr) {
2888 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
2889 || (sa->sa_portal == AFS_FSPORT);
2890 if ((!vlonly && isfs) || (vlonly && !isfs)) {
2897 if (sa && matches) { /* found one! */
2899 printf ("sa ip=%x, ip_rank=%d\n",sa->sa_ip, sa->sa_iprank);
2901 sa->sa_iprank = sp->rank + afs_randomMod15();
2902 afs_SortOneServer(sa->server);
2905 /* if we don't know yet what cell it's in, this is moot */
2906 for (j=touchedSize-1; j>=0 && touched[j] != srvr->cell->cell; j--)
2907 /* is it in our list of touched cells ? */ ;
2908 if (j < 0) { /* no, it's not */
2909 touched[touchedSize++] = srvr->cell->cell;
2910 if (touchedSize >= 32) { /* watch for ovrflow */
2911 ReleaseReadLock(&afs_xserver);
2912 ReSortCells(touchedSize, touched, vlonly);
2914 ObtainReadLock(&afs_xserver);
2920 ReleaseReadLock(&afs_xserver);
2921 /* if we didn't find one, start to create one. */
2922 /* Note that it doesn't have a cell yet... */
2924 afs_uint32 temp = sp->host.s_addr;
2925 srvr = afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
2926 WRITE_LOCK, (afsUUID *)0,0);
2927 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
2928 afs_PutServer(srvr, WRITE_LOCK);
2930 } /* for all cited preferences */
2932 ReSortCells(touchedSize, touched, vlonly);
2936 /* Note that this may only be performed by the local root user.
2939 PSetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2942 struct vrequest *areq;
2945 struct AFS_UCRED *acred;
2946 afs_int32 *aoutSize;
2948 struct setspref *ssp;
2949 AFS_STATCNT(PSetSPrefs);
2951 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2952 return EIO; /* Inappropriate ioctl for device */
2954 if (!afs_osi_suser(acred))
2957 if (ainSize < sizeof(struct setspref))
2960 ssp = (struct setspref *)ain;
2961 if (ainSize < sizeof(struct spref)*ssp->num_servers)
2964 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
2965 (ssp->flags & DBservers));
2970 PSetSPrefs33(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2973 struct vrequest *areq;
2976 struct AFS_UCRED *acred;
2977 afs_int32 *aoutSize;
2980 AFS_STATCNT(PSetSPrefs);
2981 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2982 return EIO; /* Inappropriate ioctl for device */
2985 if (!afs_osi_suser(acred))
2988 sp = (struct spref *)ain;
2989 afs_setsprefs(sp, ainSize/(sizeof(struct spref)), 0 /*!vlonly*/);
2993 /* some notes on the following code...
2994 * in the hash table of server structs, all servers with the same IP address
2995 * will be on the same overflow chain.
2996 * This could be sped slightly in some circumstances by having it cache the
2997 * immediately previous slot in the hash table and some supporting information
2998 * Only reports file servers now.
3001 PGetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3004 struct vrequest *areq;
3007 afs_int32 *aoutSize;
3009 struct sprefrequest *spin; /* input */
3010 struct sprefinfo *spout; /* output */
3011 struct spref *srvout; /* one output component */
3012 int i,j; /* counters for hash table traversal */
3013 struct server *srvr; /* one of CM's server structs */
3016 int vlonly; /* just return vlservers ? */
3019 AFS_STATCNT(PGetSPrefs);
3020 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3021 return EIO; /* Inappropriate ioctl for device */
3024 if (ainSize < sizeof (struct sprefrequest_33)) {
3028 spin = ((struct sprefrequest *) ain);
3031 if (ainSize > sizeof (struct sprefrequest_33)) {
3032 vlonly = (spin->flags & DBservers);
3036 /* struct sprefinfo includes 1 server struct... that size gets added
3037 * in during the loop that follows.
3039 *aoutSize = sizeof(struct sprefinfo) - sizeof (struct spref);
3040 spout = (struct sprefinfo *) aout;
3041 spout->next_offset = spin->offset;
3042 spout->num_servers = 0;
3043 srvout = spout->servers;
3045 ObtainReadLock(&afs_xserver);
3046 for (i=0, j=0; j < NSERVERS; j++) { /* sift through hash table */
3047 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3048 if (spin->offset > (unsigned short)i) {
3049 continue; /* catch up to where we left off */
3051 spout->next_offset++;
3054 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3055 || (sa->sa_portal == AFS_FSPORT);
3057 if ((vlonly && isfs) || (!vlonly && !isfs)) {
3058 /* only report ranks for vl servers */
3062 srvout->host.s_addr = sa->sa_ip;
3063 srvout->rank = sa->sa_iprank;
3064 *aoutSize += sizeof(struct spref);
3065 spout->num_servers++;
3068 if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3069 ReleaseReadLock(&afs_xserver); /* no more room! */
3074 ReleaseReadLock(&afs_xserver);
3076 spout->next_offset = 0; /* start over from the beginning next time */
3080 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3081 int afs_NFSRootOnly = 1;
3082 /*static*/ PExportAfs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3085 struct vrequest *areq;
3088 afs_int32 *aoutSize; /* set this */
3089 struct AFS_UCRED *acred;
3091 afs_int32 export, newint=0, type, changestate, handleValue, convmode, pwsync, smounts;
3092 extern struct afs_exporter *exporter_find();
3093 register struct afs_exporter *exporter;
3095 AFS_STATCNT(PExportAfs);
3096 bcopy(ain, (char *)&handleValue, sizeof(afs_int32));
3097 type = handleValue >> 24;
3102 exporter = exporter_find(type);
3104 export = handleValue & 3;
3105 changestate = handleValue & 0xff;
3106 smounts = (handleValue >> 2) & 3;
3107 pwsync = (handleValue >> 4) & 3;
3108 convmode = (handleValue >> 6) & 3;
3110 changestate = (handleValue >> 16) & 0x1;
3111 convmode = (handleValue >> 16) & 0x2;
3112 pwsync = (handleValue >> 16) & 0x4;
3113 smounts = (handleValue >> 16) & 0x8;
3114 export = handleValue & 0xff;
3117 /* Failed finding desired exporter; */
3121 handleValue = exporter->exp_states;
3122 bcopy((char *)&handleValue, aout, sizeof(afs_int32));
3123 *aoutSize = sizeof(afs_int32);
3125 if (!afs_osi_suser(acred))
3126 return EACCES; /* Only superuser can do this */
3130 exporter->exp_states |= EXP_EXPORTED;
3132 exporter->exp_states &= ~EXP_EXPORTED;
3136 exporter->exp_states |= EXP_UNIXMODE;
3138 exporter->exp_states &= ~EXP_UNIXMODE;
3142 exporter->exp_states |= EXP_PWSYNC;
3144 exporter->exp_states &= ~EXP_PWSYNC;
3148 afs_NFSRootOnly = 0;
3149 exporter->exp_states |= EXP_SUBMOUNTS;
3151 afs_NFSRootOnly = 1;
3152 exporter->exp_states &= ~EXP_SUBMOUNTS;
3155 handleValue = exporter->exp_states;
3156 bcopy((char *)&handleValue, aout, sizeof(afs_int32));
3157 *aoutSize = sizeof(afs_int32);
3160 exporter->exp_states |= EXP_EXPORTED;
3162 exporter->exp_states &= ~EXP_EXPORTED;
3164 exporter->exp_states |= EXP_UNIXMODE;
3166 exporter->exp_states &= ~EXP_UNIXMODE;
3168 exporter->exp_states |= EXP_PWSYNC;
3170 exporter->exp_states &= ~EXP_PWSYNC;
3172 afs_NFSRootOnly = 0;
3173 exporter->exp_states |= EXP_SUBMOUNTS;
3175 afs_NFSRootOnly = 1;
3176 exporter->exp_states &= ~EXP_SUBMOUNTS;
3185 PGag(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3188 struct vrequest *areq;
3191 struct AFS_UCRED *acred;
3192 afs_int32 *aoutSize; /* set this */
3194 struct gaginfo *gagflags;
3196 if (!afs_osi_suser(acred))
3199 gagflags = (struct gaginfo *) ain;
3200 afs_showflags = gagflags->showflags;
3207 PTwiddleRx(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3210 struct vrequest *areq;
3213 struct AFS_UCRED *acred;
3214 afs_int32 *aoutSize;
3216 struct rxparams *rxp;
3218 if (!afs_osi_suser(acred))
3221 rxp = (struct rxparams *) ain;
3223 if (rxp->rx_initReceiveWindow)
3224 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3225 if (rxp->rx_maxReceiveWindow)
3226 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3227 if (rxp->rx_initSendWindow)
3228 rx_initSendWindow = rxp->rx_initSendWindow;
3229 if (rxp->rx_maxSendWindow)
3230 rx_maxSendWindow = rxp->rx_maxSendWindow;
3231 if (rxp->rxi_nSendFrags)
3232 rxi_nSendFrags = rxp->rxi_nSendFrags;
3233 if (rxp->rxi_nRecvFrags)
3234 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3235 if (rxp->rxi_OrphanFragSize)
3236 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3237 if (rxp->rx_maxReceiveSize)
3239 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3240 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3242 if (rxp->rx_MyMaxSendSize)
3243 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3248 static int PGetInitParams(avc, afun, areq, ain, aout, ainSize, aoutSize)
3251 struct vrequest *areq;
3255 afs_int32 *aoutSize; /* set this */
3257 if (sizeof(struct cm_initparams) > PIGGYSIZE)
3260 bcopy((char*)&cm_initParams, aout, sizeof(struct cm_initparams));
3261 *aoutSize = sizeof(struct cm_initparams);
3265 #ifdef AFS_SGI65_ENV
3266 /* They took crget() from us, so fake it. */
3267 static cred_t *crget(void)
3270 cr = crdup(get_current_cred());
3271 bzero((char*)cr, sizeof(cred_t));
3272 #if CELL || CELL_PREPARE
3280 PGetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3283 struct vrequest *areq;
3286 afs_int32 *aoutSize;
3287 struct AFS_UCRED *acred;
3289 bcopy((char *)&cryptall, aout, sizeof(afs_int32));
3290 *aoutSize=sizeof(afs_int32);
3295 PSetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3298 struct vrequest *areq;
3301 afs_int32 *aoutSize;
3302 struct AFS_UCRED *acred;
3306 if (!afs_osi_suser(acred))
3308 if (ainSize != sizeof(afs_int32) || ain == NULL)
3310 bcopy(ain, (char *)&tmpval, sizeof(afs_int32));
3311 /* if new mappings added later this will need to be changed */
3312 if (tmpval != 0 && tmpval != 1)
3319 * Create new credentials to correspond to a remote user with given
3320 * <hostaddr, uid, g0, g1>. This allows a server running as root to
3321 * provide pioctl (and other) services to foreign clients (i.e. nfs
3322 * clients) by using this call to `become' the client.
3325 #define PIOCTL_HEADER 6
3326 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3329 afs_uint32 hostaddr;
3330 afs_int32 uid, g0, g1, i, code, pag, exporter_type;
3331 extern struct afs_exporter *exporter_find();
3332 struct afs_exporter *exporter, *outexporter;
3333 struct AFS_UCRED *newcred;
3334 struct unixuser *au;
3336 #if defined(AFS_DEC_ENV) || (defined(AFS_NONFSTRANS) && !defined(AFS_AIX_IAUTH_ENV))
3337 return EINVAL; /* NFS trans not supported for Ultrix */
3339 #if defined(AFS_SGIMP_ENV)
3340 osi_Assert(ISAFS_GLOCK());
3342 AFS_STATCNT(HandleClientContext);
3343 if (ablob->in_size < PIOCTL_HEADER*sizeof(afs_int32)) {
3344 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3345 return EINVAL; /* Too small to be good */
3347 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3348 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER*sizeof(afs_int32), code);
3350 osi_FreeLargeSpace(inData);
3354 /* Extract information for remote user */
3355 hostaddr = *((afs_uint32 *)ain);
3356 ain += sizeof(hostaddr);
3357 uid = *((afs_uint32 *)ain);
3359 g0 = *((afs_uint32 *)ain);
3361 g1 = *((afs_uint32 *)ain);
3363 *com = *((afs_uint32 *)ain);
3364 ain += sizeof(afs_int32);
3365 exporter_type = *((afs_uint32 *)ain); /* In case we support more than NFS */
3368 * Of course, one must be root for most of these functions, but
3369 * we'll allow (for knfs) you to set things if the pag is 0 and
3370 * you're setting tokens or unlogging.
3373 if (!afs_osi_suser(credp)) {
3375 #ifndef AFS_SGI64_ENV
3376 /* Since SGI's suser() returns explicit failure after the call.. */
3380 /* check for acceptable opcodes for normal folks, which are, so far,
3381 * set tokens and unlog.
3383 if (i != 9 && i != 3 && i != 38 && i != 8) {
3384 osi_FreeLargeSpace(inData);
3389 ablob->in_size -= PIOCTL_HEADER*sizeof(afs_int32);
3390 ablob->in += PIOCTL_HEADER*sizeof(afs_int32);
3391 osi_FreeLargeSpace(inData);
3394 * We map uid 0 to nobody to match the mapping that the nfs
3395 * server does and to ensure that the suser() calls in the afs
3396 * code fails for remote client roots.
3398 uid = afs_nobody; /* NFS_NOBODY == -2 */
3401 #ifdef AFS_AIX41_ENV
3404 newcred->cr_gid = RMTUSER_REQ;
3405 newcred->cr_groups[0] = g0;
3406 newcred->cr_groups[1] = g1;
3408 newcred->cr_ngrps = 2;
3410 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)
3411 newcred->cr_ngroups = 2;
3413 for (i=2; i<NGROUPS; i++)
3414 newcred->cr_groups[i] = NOGROUP;
3417 #if !defined(AFS_OSF_ENV) && !defined(AFS_DEC_ENV)
3418 afs_nfsclient_init(); /* before looking for exporter, ensure one exists */
3420 if (!(exporter = exporter_find(exporter_type))) {
3421 /* Exporter wasn't initialized or an invalid exporter type */
3425 if (exporter->exp_states & EXP_PWSYNC) {
3426 if (uid != credp->cr_uid) {
3428 return ENOEXEC; /* XXX Find a better errno XXX */
3431 newcred->cr_uid = uid; /* Only temporary */
3432 code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
3433 /* The client's pag is the only unique identifier for it */
3434 newcred->cr_uid = pag;
3436 if (!code && *com == PSETPAG) {
3437 /* Special case for 'setpag' */
3438 afs_uint32 pagvalue = genpag();
3440 au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
3442 * Note that we leave the 'outexporter' struct held so it won't
3445 au->exporter = outexporter;
3446 if (ablob->out_size >= 4) {
3447 AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32), code);
3449 afs_PutUser(au, WRITE_LOCK);
3450 if (code) return code;
3451 return PSETPAG; /* Special return for setpag */
3453 EXP_RELE(outexporter);
3456 #endif /*defined(AFS_DEC_ENV) || defined(AFS_NONFSTRANS)*/
3459 /* get all interface addresses of this client */
3462 PGetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3465 struct vrequest *areq;
3468 afs_int32 *aoutSize;
3470 struct sprefrequest *spin; /* input */
3471 struct sprefinfo *spout; /* output */
3472 struct spref *srvout; /* one output component */
3476 AFS_STATCNT(PGetCPrefs);
3477 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3478 return EIO; /* Inappropriate ioctl for device */
3480 if ( ainSize < sizeof (struct sprefrequest ))
3483 spin = (struct sprefrequest *) ain;
3484 spout = (struct sprefinfo *) aout;
3486 maxNumber = spin->num_servers; /* max addrs this time */
3487 srvout = spout->servers;
3489 ObtainReadLock(&afs_xinterface);
3491 /* copy out the client interface information from the
3492 ** kernel data structure "interface" to the output buffer
3494 for ( i=spin->offset, j=0; (i < afs_cb_interface.numberOfInterfaces)
3495 && ( j< maxNumber) ; i++, j++, srvout++)
3496 srvout->host.s_addr = afs_cb_interface.addr_in[i];
3498 spout->num_servers = j;
3499 *aoutSize = sizeof(struct sprefinfo) +(j-1)* sizeof (struct spref);
3501 if ( i >= afs_cb_interface.numberOfInterfaces )
3502 spout->next_offset = 0; /* start from beginning again */
3504 spout->next_offset = spin->offset + j;
3506 ReleaseReadLock(&afs_xinterface);
3511 PSetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3514 struct vrequest *areq;
3517 afs_int32 *aoutSize;
3519 struct setspref *sin;
3522 AFS_STATCNT(PSetCPrefs);
3523 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3524 return EIO; /* Inappropriate ioctl for device */
3526 sin = (struct setspref *)ain;
3528 if ( ainSize < sizeof(struct setspref) )
3530 #if 0 /* num_servers is unsigned */
3531 if ( sin->num_servers < 0 )
3534 if ( sin->num_servers > AFS_MAX_INTERFACE_ADDR)
3537 ObtainWriteLock(&afs_xinterface, 412);
3538 afs_cb_interface.numberOfInterfaces = sin->num_servers;
3539 for ( i=0; (unsigned short)i < sin->num_servers; i++)
3540 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
3542 ReleaseWriteLock(&afs_xinterface);
3546 static PFlushMount(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3549 struct vrequest *areq;
3552 afs_int32 *aoutSize;
3553 struct AFS_UCRED *acred; {
3554 register afs_int32 code;
3555 register struct vcache *tvc;
3556 register struct dcache *tdc;
3557 struct VenusFid tfid;
3559 struct sysname_info sysState;
3560 afs_int32 offset, len;
3562 AFS_STATCNT(PFlushMount);
3563 if (!avc) return EINVAL;
3564 code = afs_VerifyVCache(avc, areq);
3565 if (code) return code;
3566 if (vType(avc) != VDIR) {
3569 tdc = afs_GetDCache(avc, 0, areq, &offset, &len, 1);
3570 if (!tdc) return ENOENT;
3571 Check_AtSys(avc, ain, &sysState, areq);
3573 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
3574 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
3575 bufp = sysState.name;
3580 tfid.Cell = avc->fid.Cell;
3581 tfid.Fid.Volume = avc->fid.Fid.Volume;
3582 afs_PutDCache(tdc); /* we're done with the data */
3583 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
3584 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
3586 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
3593 if (vType(tvc) != VLNK) {
3594 afs_PutVCache(tvc, WRITE_LOCK);
3598 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3599 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3601 ObtainWriteLock(&tvc->lock,645);
3602 ObtainWriteLock(&afs_xcbhash, 646);
3603 afs_DequeueCallback(tvc);
3604 tvc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
3605 ReleaseWriteLock(&afs_xcbhash);
3606 /* now find the disk cache entries */
3607 afs_TryToSmush(tvc, acred, 1);
3608 osi_dnlc_purgedp(tvc);
3609 afs_symhint_inval(tvc);
3610 if (tvc->linkData && !(tvc->states & CCore)) {
3611 afs_osi_Free(tvc->linkData, strlen(tvc->linkData)+1);
3612 tvc->linkData = (char *) 0;
3614 ReleaseWriteLock(&tvc->lock);
3615 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3616 afs_BozonUnlock(&tvc->pvnLock, tvc);
3618 afs_PutVCache(tvc, WRITE_LOCK);
3620 if (sysState.allocked) osi_FreeLargeSpace(bufp);
3624 static PRxStatProc(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3627 struct vrequest *areq;
3630 afs_int32 *aoutSize;
3631 struct AFS_UCRED *acred;
3636 if (!afs_osi_suser(acred)) {
3640 if (ainSize != sizeof(afs_int32)) {
3644 bcopy(ain, (char *)&flags, sizeof(afs_int32));
3645 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3649 if (flags & AFSCALL_RXSTATS_ENABLE) {
3650 rx_enableProcessRPCStats();
3652 if (flags & AFSCALL_RXSTATS_DISABLE) {
3653 rx_disableProcessRPCStats();
3655 if (flags & AFSCALL_RXSTATS_CLEAR) {
3656 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
3664 static PRxStatPeer(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3667 struct vrequest *areq;
3670 afs_int32 *aoutSize;
3671 struct AFS_UCRED *acred;
3676 if (!afs_osi_suser(acred)) {
3680 if (ainSize != sizeof(afs_int32)) {
3684 bcopy(ain, (char *)&flags, sizeof(afs_int32));
3685 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3689 if (flags & AFSCALL_RXSTATS_ENABLE) {
3690 rx_enablePeerRPCStats();
3692 if (flags & AFSCALL_RXSTATS_DISABLE) {
3693 rx_disablePeerRPCStats();
3695 if (flags & AFSCALL_RXSTATS_CLEAR) {
3696 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
3703 static PPrefetchFromTape(avc, afun, areq, ain, aout, ainSize, aoutSize)
3706 struct vrequest *areq;
3709 afs_int32 *aoutSize; /* set this */
3711 register afs_int32 code, code1;
3714 struct rx_call *tcall;
3715 struct AFSVolSync tsync;
3716 struct AFSFetchStatus OutStatus;
3717 struct AFSCallBack CallBack;
3718 struct VenusFid tfid;
3723 AFS_STATCNT(PSetAcl);
3727 if (ain && (ainSize == 3 * sizeof(afs_int32)))
3728 Fid = (struct AFSFid *) ain;
3730 Fid = &avc->fid.Fid;
3731 tfid.Cell = avc->fid.Cell;
3732 tfid.Fid.Volume = Fid->Volume;
3733 tfid.Fid.Vnode = Fid->Vnode;
3734 tfid.Fid.Unique = Fid->Unique;
3736 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
3739 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3740 ICL_TYPE_POINTER, tvc,
3741 ICL_TYPE_FID, &tfid,
3742 ICL_TYPE_FID, &avc->fid);
3745 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3746 ICL_TYPE_POINTER, tvc,
3747 ICL_TYPE_FID, &tfid,
3748 ICL_TYPE_FID, &tvc->fid);
3751 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3754 #ifdef RX_ENABLE_LOCKS
3756 #endif /* RX_ENABLE_LOCKS */
3757 tcall = rx_NewCall(tc->id);
3758 code = StartRXAFS_FetchData(tcall,
3759 (struct AFSFid *) &tvc->fid.Fid, 0, 0);
3761 bytes = rx_Read(tcall, (char *) aout, sizeof(afs_int32));
3762 code = EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
3764 code1 = rx_EndCall(tcall, code);
3765 #ifdef RX_ENABLE_LOCKS
3767 #endif /* RX_ENABLE_LOCKS */
3771 (afs_Analyze(tc, code, &tvc->fid, areq,
3772 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
3774 /* This call is done only to have the callback things handled correctly */
3775 afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
3776 afs_PutVCache(tvc, WRITE_LOCK);
3779 *aoutSize = sizeof(afs_int32);
3784 static PResidencyCmd(avc, afun, areq, ain, aout, ainSize, aoutSize)
3787 struct vrequest *areq;
3790 afs_int32 *aoutSize; /* set this */
3792 register afs_int32 code;
3795 struct ResidencyCmdInputs *Inputs;
3796 struct ResidencyCmdOutputs *Outputs;
3797 struct VenusFid tfid;
3800 Inputs = (struct ResidencyCmdInputs *) ain;
3801 Outputs = (struct ResidencyCmdOutputs *) aout;
3802 if (!avc) return EINVAL;
3803 if (!ain || ainSize != sizeof(struct ResidencyCmdInputs)) return EINVAL;
3807 Fid = &avc->fid.Fid;
3809 tfid.Cell = avc->fid.Cell;
3810 tfid.Fid.Volume = Fid->Volume;
3811 tfid.Fid.Vnode = Fid->Vnode;
3812 tfid.Fid.Unique = Fid->Unique;
3814 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
3816 afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD,
3817 ICL_TYPE_POINTER, tvc,
3818 ICL_TYPE_INT32, Inputs->command,
3819 ICL_TYPE_FID, &tfid);
3823 if (Inputs->command) {
3825 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3827 #ifdef RX_ENABLE_LOCKS
3829 #endif /* RX_ENABLE_LOCKS */
3830 code = RXAFS_ResidencyCmd(tc->id, Fid,
3832 (struct ResidencyCmdOutputs *) aout);
3833 #ifdef RX_ENABLE_LOCKS
3835 #endif /* RX_ENABLE_LOCKS */
3839 (afs_Analyze(tc, code, &tvc->fid, areq,
3840 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
3842 /* This call is done to have the callback things handled correctly */
3843 afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3844 } else { /* just a status request, return also link data */
3846 Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3847 Outputs->chars[0] = 0;
3848 if (vType(tvc) == VLNK) {
3849 ObtainWriteLock(&tvc->lock,555);
3850 if (afs_HandleLink(tvc, areq) == 0)
3851 strncpy((char *) &Outputs->chars, tvc->linkData, MAXCMDCHARS);
3852 ReleaseWriteLock(&tvc->lock);
3856 afs_PutVCache(tvc, WRITE_LOCK);
3859 *aoutSize = sizeof(struct ResidencyCmdOutputs);