BOP_MOVE and userspace move EXDEV helper
authorDerrick Brashear <shadow@dementia.org>
Sat, 27 Feb 2010 20:30:06 +0000 (15:30 -0500)
committerDerrick Brashear <shadow@dementia.org>
Tue, 2 Mar 2010 10:35:28 +0000 (02:35 -0800)
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 <shadow@dementia.org>
Reviewed-by: Simon Wilkinson <sxw@inf.ed.ac.uk>
Reviewed-by: Derrick Brashear <shadow@dementia.org>

src/afs/DARWIN/osi_vnodeops.c
src/afs/VNOPS/afs_vnop_lookup.c
src/afs/afs.h
src/afs/afs_call.c
src/afs/afs_daemons.c
src/afs/afs_prototypes.h
src/afs/afs_util.c
src/afsd/afsd.c
src/config/afs_args.h

index f40a6df..8fe2a50 100644 (file)
@@ -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);
index f055d1f..d93f5df 100644 (file)
@@ -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;
     }
index 8b6ff46..dcf1ce9 100644 (file)
@@ -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 */
 
index 8ed5f48..c01c4e3 100644 (file)
@@ -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);
index 826011f..483584f 100644 (file)
@@ -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
 }
 
 
index e43f895..4f3ac7d 100644 (file)
@@ -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);
index bd57d2f..8bf4667 100644 (file)
@@ -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)
index 0be921e..153567f 100644 (file)
@@ -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 <sys/ioctl.h>
-#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);
index 9036861..6ccd65b 100644 (file)
@@ -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
 #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;