From ede82a2eb1c8180a117dbe78b3c42959f0efe0ec Mon Sep 17 00:00:00 2001 From: Derrick Brashear Date: Sat, 27 Feb 2010 15:30:06 -0500 Subject: [PATCH] BOP_MOVE and userspace move EXDEV helper turns background daemons into afsdb helper-like processes, which can exit and do work. for macos, add BOP_MOVE and implement mv in afsd: (macos EXDEV move is cp+rm, literally) run cp + rm and pass the return back in. if it fails, just give the client the error it had already Change-Id: Ia0d5d49725f6aa28b5c58d0b7c61cc22329a3bc1 Reviewed-on: http://gerrit.openafs.org/1371 Tested-by: Derrick Brashear Reviewed-by: Simon Wilkinson Reviewed-by: Derrick Brashear --- src/afs/DARWIN/osi_vnodeops.c | 74 +++++++++++++++--- src/afs/VNOPS/afs_vnop_lookup.c | 131 ++++++++++++++++++-------------- src/afs/afs.h | 3 + src/afs/afs_call.c | 63 +++++++++++---- src/afs/afs_daemons.c | 53 ++++++++++++- src/afs/afs_prototypes.h | 5 ++ src/afs/afs_util.c | 28 +++++++ src/afsd/afsd.c | 131 ++++++++++++++++++++++++++++++-- src/config/afs_args.h | 29 +++++++ 9 files changed, 430 insertions(+), 87 deletions(-) diff --git a/src/afs/DARWIN/osi_vnodeops.c b/src/afs/DARWIN/osi_vnodeops.c index f40a6df36..8fe2a509a 100644 --- a/src/afs/DARWIN/osi_vnodeops.c +++ b/src/afs/DARWIN/osi_vnodeops.c @@ -1390,18 +1390,72 @@ afs_vop_rename(ap) vrele(fdvp); vrele(fvp); #else -#ifdef notdef if (error == EXDEV) { - /* The idea would be to have a userspace handler like afsdb to - * run mv as the user, thus: - */ - printf("su %d -c /bin/mv /afs/.:mount/%d:%d:%d:%d/%s /afs/.:mount/%d:%d:%d:%d/%s\n", - afs_cr_uid(cn_cred(tcnp)), fvc->f.fid.Cell, fvc->f.fid.Fid.Volume, - fvc->f.fid.Fid.Vnode, fvc->f.fid.Fid.Unique, fname, - tvc->f.fid.Cell, tvc->f.fid.Fid.Volume, tvc->f.fid.Fid.Vnode, - tvc->f.fid.Fid.Unique, tname); + struct brequest *tb; + struct afs_uspc_param mvReq; + struct vcache *tvc; + struct vcache *fvc = VTOAFS(fdvp); + int code = 0; + struct afs_fakestat_state fakestate; + int fakestatdone = 0; + + tvc = VTOAFS(tdvp); + + /* unrewritten mount point? */ + if (tvc->mvstat == 1) { + if (tvc->mvid && (tvc->f.states & CMValid)) { + struct vrequest treq; + + afs_InitFakeStat(&fakestate); + code = afs_InitReq(&treq, vop_cred); + if (!code) { + fakestatdone = 1; + code = afs_EvalFakeStat(&tvc, &fakestate, &treq); + } else + afs_PutFakeStat(&fakestate); + } + } + + if (!code) { + /* at some point in the future we should allow other types */ + mvReq.reqtype = AFS_USPC_UMV; + mvReq.req.umv.id = afs_cr_uid(cn_cred(tcnp)); + mvReq.req.umv.idtype = IDTYPE_UID; + mvReq.req.umv.sCell = fvc->f.fid.Cell; + mvReq.req.umv.sVolume = fvc->f.fid.Fid.Volume; + mvReq.req.umv.sVnode = fvc->f.fid.Fid.Vnode; + mvReq.req.umv.sUnique = fvc->f.fid.Fid.Unique; + mvReq.req.umv.dCell = tvc->f.fid.Cell; + mvReq.req.umv.dVolume = tvc->f.fid.Fid.Volume; + mvReq.req.umv.dVnode = tvc->f.fid.Fid.Vnode; + mvReq.req.umv.dUnique = tvc->f.fid.Fid.Unique; + + /* + * su %d -c mv /afs/.:mount/%d:%d:%d:%d/%s + * /afs/.:mount/%d:%d:%d:%d/%s where: + * mvReq.req.umv.id, fvc->f.fid.Cell, fvc->f.fid.Fid.Volume, + * fvc->f.fid.Fid.Vnode, fvc->f.fid.Fid.Unique, fname, + * tvc->f.fid.Cell, tvc->f.fid.Fid.Volume, tvc->f.fid.Fid.Vnode, + * tvc->f.fid.Fid.Unique, tname + */ + + tb = afs_BQueue(BOP_MOVE, NULL, 0, 1, cn_cred(tcnp), + 0L, 0L, &mvReq, fname, tname); + /* wait to collect result */ + while ((tb->flags & BUVALID) == 0) { + tb->flags |= BUWAIT; + afs_osi_Sleep(tb); + } + /* if we succeeded, clear the error. otherwise, EXDEV */ + if (mvReq.retval == 0) + error = 0; + + afs_BRelease(tb); + } + + if (fakestatdone) + afs_PutFakeStat(&fakestate); } -#endif AFS_GUNLOCK(); cache_purge(fdvp); diff --git a/src/afs/VNOPS/afs_vnop_lookup.c b/src/afs/VNOPS/afs_vnop_lookup.c index f055d1fef..d93f5df78 100644 --- a/src/afs/VNOPS/afs_vnop_lookup.c +++ b/src/afs/VNOPS/afs_vnop_lookup.c @@ -51,26 +51,26 @@ int afs_fakestat_enable = 0; /* 1: fakestat-all, 2: fakestat-crosscell */ static int EvalMountData(char type, char *data, afs_uint32 states, afs_uint32 cellnum, struct volume **avolpp, register struct vrequest *areq, - afs_uint32 *acellidxp, afs_uint32 *avolnump, afs_uint32 *avnoidp) + afs_uint32 *acellidxp, afs_uint32 *avolnump, + afs_uint32 *avnoidp, afs_uint32 *auniqp) { struct volume *tvp = 0; struct VenusFid tfid; struct cell *tcell; - char *cpos, *volnamep, *x; - char *buf; + char *cpos, *volnamep; + char *buf, *endptr; afs_int32 prefetch; /* 1=>None 2=>RO 3=>BK */ afs_int32 mtptCell, assocCell = 0, hac = 0; afs_int32 samecell, roname, len; - afs_uint32 volid, cellidx, vnoid = 0; + afs_uint32 volid = 0, cellidx, vnoid = 0, uniq = 0; + /* Start by figuring out and finding the cell */ cpos = afs_strchr(data, ':'); /* if cell name present */ if (cpos) { - cellnum = 0; volnamep = cpos + 1; *cpos = 0; - for (x = data; *x >= '0' && *x <= '9'; x++) - cellnum = (cellnum * 10) + (*x - '0'); - if (cellnum && !*x) + if ((afs_strtoi_r(data, &endptr, &cellnum) == 0) && + (endptr == cpos)) tcell = afs_GetCell(cellnum, READ_LOCK); else { tcell = afs_GetCellByName(data, READ_LOCK); @@ -81,12 +81,11 @@ EvalMountData(char type, char *data, afs_uint32 states, afs_uint32 cellnum, volnamep = data; tcell = afs_GetCell(cellnum, READ_LOCK); } else { - /*printf("No cellname %s , or cellnum %d , returning ENODEV\n", - data, cellnum);*/ + /* No cellname or cellnum; return ENODEV */ return ENODEV; } if (!tcell) { - /*printf("Lookup failed, returning ENODEV\n");*/ + /* no cell found; return ENODEV */ return ENODEV; } @@ -98,22 +97,38 @@ EvalMountData(char type, char *data, afs_uint32 states, afs_uint32 cellnum, } afs_PutCell(tcell, READ_LOCK); - cpos = afs_strrchr(volnamep, ':'); /* if vno present */ - if (cpos) + /* If there's nothing to look up, we can't proceed */ + if (!*volnamep) + return ENODEV; + + /* cell found. figure out volume */ + cpos = afs_strchr(volnamep, ':'); + if (cpos) *cpos = 0; + /* Look for an all-numeric volume ID */ - volid = 0; - for (x = volnamep; *x >= '0' && *x <= '9'; x++) - volid = (volid * 10) + (*x - '0'); - if (cpos) { - *cpos = ':'; - vnoid = 0; - if (*x == *cpos) /* allow vno with numeric volid only */ - for (x = (cpos + 1); *x >= '0' && *x <= '9'; x++) - vnoid = (vnoid * 10) + (*x - '0'); - if (*x) - vnoid = 0; - } + if ((afs_strtoi_r(volnamep, &endptr, &volid) == 0) && + ((endptr == cpos) || (!*endptr))) + { + /* Ok. Is there a vnode and uniq? */ + if (cpos) { + char *vnodep = (char *)(cpos + 1); + char *uniqp = NULL; + if ((!*vnodep) /* no vnode after colon */ + || !(uniqp = afs_strchr(vnodep, ':')) /* no colon for uniq */ + || (!*(++uniqp)) /* no uniq after colon */ + || (afs_strtoi_r(vnodep, &endptr, &vnoid) != 0) /* bad vno */ + || (*endptr != ':') /* bad vnode field */ + || (afs_strtoi_r(uniqp, &endptr, &uniq) != 0) /* bad uniq */ + || (*endptr)) /* anything after uniq */ + { + *cpos = ':'; + /* sorry. vnode and uniq, or nothing */ + return ENODEV; + } + } + } else + volid = 0; /* * If the volume ID was all-numeric, and they didn't ask for a @@ -121,14 +136,10 @@ EvalMountData(char type, char *data, afs_uint32 states, afs_uint32 cellnum, * as-is. This is currently only used for handling name lookups * in the dynamic mount directory. */ - if (!*x && !avolpp) { - if (acellidxp) - *acellidxp = cellidx; - if (avolnump) - *avolnump = volid; - if (avnoidp) - *avnoidp = vnoid; - return 0; + if (volid && !avolpp) { + if (*cpos) + *cpos = ':'; + goto done; } /* @@ -137,14 +148,14 @@ EvalMountData(char type, char *data, afs_uint32 states, afs_uint32 cellnum, * and don't second-guess them by forcing use of a RW volume when * they gave the ID of something else. */ - if (!*x && type == '%') { + if (volid && type == '%') { tfid.Fid.Volume = volid; /* remember BK volume */ tfid.Cell = mtptCell; tvp = afs_GetVolume(&tfid, areq, WRITE_LOCK); /* get the new one */ - if (!tvp) { - /*printf("afs_GetVolume failed - returning ENODEV");*/ - return ENODEV; /* oops, can't do it */ - } + if (cpos) /* one way or another we're done */ + *cpos = ':'; + if (!tvp) + return ENODEV; /* afs_GetVolume failed; return ENODEV */ goto done; } @@ -180,11 +191,6 @@ EvalMountData(char type, char *data, afs_uint32 states, afs_uint32 cellnum, * The RO volume will be prefetched if requested (but not returned). * Set up to use volname first. */ - cpos = afs_strchr(volnamep, ':'); /* if vno present */ - if (cpos) - *cpos = 0; - - /*printf("Calling GetVolumeByName\n");*/ tvp = afs_GetVolumeByName(volnamep, mtptCell, prefetch, areq, WRITE_LOCK); /* If no volume was found in this cell, try the associated linked cell */ @@ -215,11 +221,8 @@ EvalMountData(char type, char *data, afs_uint32 states, afs_uint32 cellnum, /* done with volname */ if (cpos) *cpos = ':'; - - if (!tvp) { - /*printf("Couldn't find the volume\n");*/ + if (!tvp) return ENODEV; /* Couldn't find the volume */ - } /* Don't cross mountpoint from a BK to a BK volume */ if ((states & CBackup) && (tvp->states & VBackup)) { @@ -256,9 +259,11 @@ done: *avolnump = tvp->volume; if (avnoidp) *avnoidp = vnoid; + if (auniqp) + *auniqp = uniq; if (avolpp) *avolpp = tvp; - else + else if (tvp) afs_PutVolume(tvp, WRITE_LOCK); return 0; } @@ -268,7 +273,7 @@ EvalMountPoint(register struct vcache *avc, struct vcache *advc, struct volume **avolpp, register struct vrequest *areq) { afs_int32 code; - afs_uint32 avnoid; + afs_uint32 avnoid, auniq; AFS_STATCNT(EvalMountPoint); #ifdef notdef @@ -283,19 +288,22 @@ EvalMountPoint(register struct vcache *avc, struct vcache *advc, /* Determine which cell and volume the mointpoint goes to */ code = EvalMountData(avc->linkData[0], avc->linkData + 1, avc->f.states, avc->f.fid.Cell, avolpp, areq, 0, 0, - &avnoid); + &avnoid, &auniq); if (code) return code; if (!avnoid) avnoid = 1; + if (!auniq) + auniq = 1; + if (avc->mvid == 0) avc->mvid = (struct VenusFid *)osi_AllocSmallSpace(sizeof(struct VenusFid)); avc->mvid->Cell = (*avolpp)->cell; avc->mvid->Fid.Volume = (*avolpp)->volume; avc->mvid->Fid.Vnode = avnoid; - avc->mvid->Fid.Unique = 1; + avc->mvid->Fid.Unique = auniq; avc->f.states |= CMValid; /* Used to: if the mount point is stored within a backup volume, @@ -1425,15 +1433,26 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr */ if (afs_IsDynrootMount(adp)) { struct VenusFid tfid; - afs_uint32 cellidx, volid, vnoid; + afs_uint32 cellidx, volid, vnoid, uniq; - code = EvalMountData('%', aname, 0, 0, NULL, &treq, &cellidx, &volid, &vnoid); + code = EvalMountData('%', aname, 0, 0, NULL, &treq, &cellidx, &volid, &vnoid, &uniq); if (code) goto done; - afs_GetDynrootMountFid(&tfid); - tfid.Fid.Vnode = VNUM_FROM_TYPEID(VN_TYPE_MOUNT, cellidx << 2); - tfid.Fid.Unique = volid; + /* If a vnode was returned, it's not a real mount point */ + if (vnoid > 1) { + struct cell *tcell = afs_GetCellByIndex(cellidx, READ_LOCK); + tfid.Cell = tcell->cellNum; + afs_PutCell(tcell, READ_LOCK); + tfid.Fid.Vnode = vnoid; + tfid.Fid.Volume = volid; + tfid.Fid.Unique = uniq; + } else { + afs_GetDynrootMountFid(&tfid); + tfid.Fid.Vnode = VNUM_FROM_TYPEID(VN_TYPE_MOUNT, cellidx << 2); + tfid.Fid.Unique = volid; + } *avcp = tvc = afs_GetVCache(&tfid, &treq, NULL, NULL); + code = (tvc ? 0 : ENOENT); hit = 1; goto done; } diff --git a/src/afs/afs.h b/src/afs/afs.h index 8b6ff46e0..dcf1ce912 100644 --- a/src/afs/afs.h +++ b/src/afs/afs.h @@ -131,6 +131,9 @@ struct sysname_info { #if defined(AFS_CACHE_BYPASS) #define BOP_FETCH_NOCACHE 4 /* parms are: vnode ptr, offset, segment ptr, addr, cred ptr */ #endif +#ifdef AFS_DARWIN_ENV +#define BOP_MOVE 5 /* ptr1 afs_uspc_param ptr2 sname ptr3 dname */ +#endif #define B_DONTWAIT 1 /* On failure return; don't wait */ diff --git a/src/afs/afs_call.c b/src/afs/afs_call.c index 8ed5f484f..c01c4e3e4 100644 --- a/src/afs/afs_call.c +++ b/src/afs/afs_call.c @@ -161,16 +161,7 @@ afsd_thread(int *rock) thread_terminate(current_thread()); break; case AFSOP_START_BKG: - AFS_GLOCK(); - wakeup(arg); - while (afs_initState < AFSOP_START_BKG) - afs_osi_Sleep(&afs_initState); - if (afs_initState < AFSOP_GO) { - afs_initState = AFSOP_GO; - afs_osi_Wakeup(&afs_initState); - } - afs_BackgroundDaemon(); - AFS_GUNLOCK(); + printf("Install matching afsd! Old background daemons not supported.\n"); thread_terminate(current_thread()); break; case AFSOP_START_TRUNCDAEMON: @@ -533,6 +524,48 @@ afs_syscall_call(long parm, long parm2, long parm3, put_vfs_context(); #endif #if ((defined(AFS_LINUX24_ENV) && defined(COMPLETION_H_EXISTS)) || defined(AFS_DARWIN80_ENV)) && !defined(UKERNEL) +#if defined(AFS_DARWIN80_ENV) + if (parm == AFSOP_BKG_HANDLER) { + /* if afs_uspc_param grows this should be checked */ + struct afs_uspc_param *mvParam = osi_AllocSmallSpace(AFS_SMALLOCSIZ); + void *param2; + void *param1; + int namebufsz; + + AFS_COPYIN(AFSKPTR(parm2), (caddr_t)mvParam, + sizeof(struct afs_uspc_param), code); + namebufsz = mvParam->bufSz; + param1 = afs_osi_Alloc(namebufsz); + param2 = afs_osi_Alloc(namebufsz); + + while (afs_initState < AFSOP_START_BKG) + afs_osi_Sleep(&afs_initState); + if (afs_initState < AFSOP_GO) { + afs_initState = AFSOP_GO; + afs_osi_Wakeup(&afs_initState); + } + + code = afs_BackgroundDaemon(mvParam, param1, param2); + + if (!code) { + mvParam->retval = 0; + /* for reqs where pointers are strings: */ + if (mvParam->reqtype == AFS_USPC_UMV) { + /* don't copy out random kernel memory */ + AFS_COPYOUT(param2, AFSKPTR(parm4), + MIN(namebufsz, strlen((char *)param2)+1), code); + AFS_COPYOUT(param1, AFSKPTR(parm3), + MIN(namebufsz, strlen((char *)param1)+1), code); + } + AFS_COPYOUT((caddr_t)mvParam, AFSKPTR(parm2), + sizeof(struct afs_uspc_param), code); + } + + afs_osi_Free(param1, namebufsz); + afs_osi_Free(param2, namebufsz); + osi_FreeSmallSpace(mvParam); + } else +#endif /* DARWIN80 */ if (parm < AFSOP_ADDCELL || parm == AFSOP_RXEVENT_DAEMON || parm == AFSOP_RXLISTENER_DAEMON) { afs_DaemonOp(parm, parm2, parm3, parm4, parm5, parm6); @@ -618,6 +651,7 @@ afs_syscall_call(long parm, long parm2, long parm3, AFS_GUNLOCK(); exit(CLD_EXITED, 0); #endif /* AFS_SGI_ENV */ +#ifndef AFS_DARWIN80_ENV } else if (parm == AFSOP_START_BKG) { while (afs_initState < AFSOP_START_BKG) afs_osi_Sleep(&afs_initState); @@ -627,17 +661,18 @@ afs_syscall_call(long parm, long parm2, long parm3, } /* start the bkg daemon */ afs_osi_Invisible(); -#ifdef AFS_AIX32_ENV +# ifdef AFS_AIX32_ENV if (parm2) afs_BioDaemon(parm2); else -#endif /* AFS_AIX32_ENV */ +# endif /* AFS_AIX32_ENV */ afs_BackgroundDaemon(); afs_osi_Visible(); -#ifdef AFS_SGI_ENV +# ifdef AFS_SGI_ENV AFS_GUNLOCK(); exit(CLD_EXITED, 0); -#endif /* AFS_SGI_ENV */ +# endif /* AFS_SGI_ENV */ +#endif /* ! AFS_DARWIN80_ENV */ } else if (parm == AFSOP_START_TRUNCDAEMON) { while (afs_initState < AFSOP_GO) afs_osi_Sleep(&afs_initState); diff --git a/src/afs/afs_daemons.c b/src/afs/afs_daemons.c index 826011f1b..483584fe5 100644 --- a/src/afs/afs_daemons.c +++ b/src/afs/afs_daemons.c @@ -995,8 +995,13 @@ brequest_release(struct brequest *tb) afs_BRelease(tb); /* this grabs and releases afs_xbrs lock */ } +#ifdef AFS_DARWIN80_ENV +int +afs_BackgroundDaemon(struct afs_uspc_param *uspc, void *param1, void *param2) +#else void afs_BackgroundDaemon(void) +#endif { struct brequest *tb; int i, foundAny; @@ -1007,7 +1012,33 @@ afs_BackgroundDaemon(void) /* Irix with "short stack" exits */ afs_BackgroundDaemon_once(); - afs_nbrs++; +#ifdef AFS_DARWIN80_ENV + /* If it's a re-entering syscall, complete the request and release */ + if (uspc->ts > -1) { + tb = afs_brs; + for (i = 0; i < NBRS; i++, tb++) { + if (tb->ts == uspc->ts) { + /* copy the userspace status back in */ + ((struct afs_uspc_param *) tb->ptr_parm[0])->retval = + uspc->retval; + /* mark it valid and notify our caller */ + tb->flags |= BUVALID; + if (tb->flags & BUWAIT) { + tb->flags &= ~BUWAIT; + afs_osi_Wakeup(tb); + } + brequest_release(tb); + break; + } + } + } else { + afs_osi_MaskUserLoop(); +#endif + /* Otherwise it's a new one */ + afs_nbrs++; +#ifdef AFS_DARWIN80_ENV + } +#endif ObtainWriteLock(&afs_xbrs, 302); while (1) { @@ -1019,7 +1050,11 @@ afs_BackgroundDaemon(void) afs_termState = AFSOP_STOP_TRUNCDAEMON; ReleaseWriteLock(&afs_xbrs); afs_osi_Wakeup(&afs_termState); +#ifdef AFS_DARWIN80_ENV + return -2; +#else return; +#endif } /* find a request */ @@ -1052,6 +1087,19 @@ afs_BackgroundDaemon(void) BStore(tb); else if (tb->opcode == BOP_PATH) BPath(tb); +#ifdef AFS_DARWIN80_ENV + else if (tb->opcode == BOP_MOVE) { + memcpy(uspc, (struct afs_uspc_param *) tb->ptr_parm[0], + sizeof(struct afs_uspc_param)); + uspc->ts = tb->ts; + /* string lengths capped in move vop; copy NUL tho */ + memcpy(param1, (char *)tb->ptr_parm[1], + strlen(tb->ptr_parm[1])+1); + memcpy(param2, (char *)tb->ptr_parm[2], + strlen(tb->ptr_parm[2])+1); + return 0; + } +#endif else panic("background bop"); brequest_release(tb); @@ -1066,6 +1114,9 @@ afs_BackgroundDaemon(void) afs_brsDaemons--; } } +#ifdef AFS_DARWIN80_ENV + return -2; +#endif } diff --git a/src/afs/afs_prototypes.h b/src/afs/afs_prototypes.h index e43f895bd..4f3ac7db4 100644 --- a/src/afs/afs_prototypes.h +++ b/src/afs/afs_prototypes.h @@ -218,7 +218,11 @@ extern int afs_CheckRootVolume(void); extern void afs_BRelease(register struct brequest *ab); extern int afs_BBusy(void); extern int afs_BioDaemon(afs_int32 nbiods); +#ifdef AFS_DARWIN80_ENV +extern int afs_BackgroundDaemon(struct afs_uspc_param *uspc, void *param1, void *param2); +#else extern void afs_BackgroundDaemon(void); +#endif extern void shutdown_daemons(void); extern int afs_sgidaemon(void); @@ -931,6 +935,7 @@ extern void afs_SetPrimary(register struct unixuser *au, register int aflag); /* afs_util.c */ +extern afs_int32 afs_strtoi_r(const char *str, char **endptr, afs_uint32 *ret); extern afs_int32 afs_calc_inum (afs_int32 volume, afs_int32 vnode); #ifndef afs_cv2string extern char *afs_cv2string(char *ttp, afs_uint32 aval); diff --git a/src/afs/afs_util.c b/src/afs/afs_util.c index bd57d2fcf..8bf466748 100644 --- a/src/afs/afs_util.c +++ b/src/afs/afs_util.c @@ -79,6 +79,34 @@ afs_cv2string(char *ttp, afs_uint32 aval) } /*afs_cv2string */ #endif +/* not a generic strtoul replacement. for vol/vno/uniq, portable */ + +afs_int32 +afs_strtoi_r(const char *str, char **endptr, afs_uint32 *ret) +{ + char *x; + + *ret = 0; + *endptr = (char *)str; + + if (!str) + return ERANGE; + + for (x = (char *)str; *x >= '0' && *x <= '9'; x++) { + /* Check for impending overflow */ + if (*ret > 429496729) { /* ULONG_MAX/10 */ + *ret = 0; + *endptr = (char *)str; + return EINVAL; + } + + *ret = (*ret * 10) + (*x - '0'); + } + + *endptr = x; + return 0; +} + #ifndef afs_strcasecmp int afs_strcasecmp(char *s1, char *s2) diff --git a/src/afsd/afsd.c b/src/afsd/afsd.c index 0be921ef9..153567f55 100644 --- a/src/afsd/afsd.c +++ b/src/afsd/afsd.c @@ -999,7 +999,7 @@ doSweepAFSCache(int *vFilesFound, { if (afsd_debug) { printf("%s: Current directory entry:\n", rn); -#ifdef AFS_SGI62_ENV +#if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN90_ENV) printf("\tinode=%" AFS_INT64_FMT ", reclen=%d, name='%s'\n", currp->d_ino, currp->d_reclen, currp->d_name); #elif defined(AFS_DFBSD_ENV) @@ -1510,9 +1510,119 @@ AfsdbLookupHandler(void) exit(1); } -#ifdef mac2 -#include -#endif /* mac2 */ +#ifdef AFS_DARWIN_ENV +static void +BkgHandler(void) +{ + afs_int32 code; + struct afs_uspc_param *uspc; + char srcName[256]; + char dstName[256]; + + uspc = (struct afs_uspc_param *)malloc(sizeof(struct afs_uspc_param)); + memset(uspc, 0, sizeof(struct afs_uspc_param)); + memset(srcName, 0, sizeof(srcName)); + memset(dstName, 0, sizeof(dstName)); + + /* brscount starts at 0 */ + uspc->ts = -1; + + while (1) { + pid_t child = 0; + int status; + char srcpath[BUFSIZ]; + char dstpath[BUFSIZ]; + + /* pushing in a buffer this large */ + uspc->bufSz = 256; + + code = call_syscall(AFSOP_BKG_HANDLER, uspc, srcName, dstName); + if (code) { /* Something is wrong? */ + if (code == -2) /* shutting down */ + break; + + sleep(1); + uspc->retval = -1; + continue; + } + + switch (uspc->reqtype) { + case AFS_USPC_UMV: + snprintf(srcpath, BUFSIZ, "/afs/.:mount/%d:%d:%d:%d/%s", + uspc->req.umv.sCell, uspc->req.umv.sVolume, + uspc->req.umv.sVnode, uspc->req.umv.sUnique, srcName); + snprintf(dstpath, BUFSIZ, "/afs/.:mount/%d:%d:%d:%d/%s", + uspc->req.umv.dCell, uspc->req.umv.dVolume, + uspc->req.umv.dVnode, uspc->req.umv.dUnique, dstName); + if ((child = fork()) == 0) { + /* first child does cp; second, rm. mv would re-enter. */ + + switch (uspc->req.umv.idtype) { + case IDTYPE_UID: + if (setuid(uspc->req.umv.id) != 0) { + exit(-1); + } + break; + default: + exit(-1); + break; /* notreached */ + } + execl("/bin/cp", "(afsd EXDEV helper)", "-PRp", "--", srcpath, + dstpath, (char *) NULL); + } + if (child == (pid_t) -1) { + uspc->retval = -1; + continue; + } + + if (waitpid(child, &status, 0) == -1) + uspc->retval = EIO; + else if (WIFEXITED(status) != 0 && WEXITSTATUS(status) == 0) { + if ((child = fork()) == 0) { + switch (uspc->req.umv.idtype) { + case IDTYPE_UID: + if (setuid(uspc->req.umv.id) != 0) { + exit(-1); + } + break; + default: + exit(-1); + break; /* notreached */ + } + execl("/bin/rm", "(afsd EXDEV helper)", "-rf", "--", + srcpath, (char *) NULL); + } + if (child == (pid_t) -1) { + uspc->retval = -1; + continue; + } + if (waitpid(child, &status, 0) == -1) + uspc->retval = EIO; + else if (WIFEXITED(status) != 0) { + /* rm exit status */ + uspc->retval = WEXITSTATUS(status); + } else { + /* rm signal status */ + uspc->retval = -(WTERMSIG(status)); + } + } else { + /* error from cp: exit or signal status */ + uspc->retval = (WIFEXITED(status) != 0) ? + WEXITSTATUS(status) : -(WTERMSIG(status)); + } + memset(srcName, 0, sizeof(srcName)); + memset(dstName, 0, sizeof(dstName)); + break; + + default: + /* unknown req type */ + uspc->retval = -1; + break; + } + } + exit(1); +} +#endif #ifdef AFS_SGI65_ENV #define SET_RTPRI(P) { \ @@ -2262,8 +2372,17 @@ mainproc(struct cmd_syndesc *as, void *arock) for (i = 0; i < nDaemons; i++) { code = fork(); if (code == 0) { - /* Child */ -#ifdef AFS_AIX32_ENV +#ifdef AFS_DARWIN80_ENV + /* Since the background daemon runs as a user process, + * need to drop the controlling TTY, etc. + */ + if (daemon(0, 0) == -1) { + printf("Error starting background daemon: %s\n", + strerror(errno)); + exit(1); + } + BkgHandler(); +#elif defined(AFS_AIX32_ENV) call_syscall(AFSOP_START_BKG, 0); #else call_syscall(AFSOP_START_BKG); diff --git a/src/config/afs_args.h b/src/config/afs_args.h index 90368617b..6ccd65b38 100644 --- a/src/config/afs_args.h +++ b/src/config/afs_args.h @@ -49,6 +49,7 @@ #define AFSOP_SET_RXPCK 38 /* set rx_extraPackets*/ #define AFSOP_BUCKETPCT 39 /* bucket percentage */ #define AFSOP_SET_RXMAXMTU 40 /* set rx_MyMaxSendSize,rx_maxReceiveSizeUser,rx_maxReceiveSize */ +#define AFSOP_BKG_HANDLER 41 /* userspace-capable Bkg daemon */ /* The range 20-30 is reserved for AFS system offsets in the afs_syscall */ #define AFSCALL_PIOCTL 20 @@ -130,6 +131,34 @@ #endif /* arguments passed by afsd */ +#define IDTYPE_UID 0 + +/* We don't necessarily have VenusFid here */ +struct afs_umv_param { + afs_int32 id; + afs_int32 idtype; + afs_int32 sCell; + afs_int32 sVolume; + afs_int32 sVnode; + afs_int32 sUnique; + afs_int32 dCell; + afs_int32 dVolume; + afs_int32 dVnode; + afs_int32 dUnique; +}; + +#define AFS_USPC_UMV 1 + +struct afs_uspc_param { + afs_int32 retval; + afs_int32 ts; /* brequest ts - always unique */ + afs_int32 bufSz; + afs_int32 reqtype; + union { + struct afs_umv_param umv; + } req; +}; + struct afs_cacheParams { afs_int32 cacheScaches; afs_int32 cacheFiles; -- 2.39.5