summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libfshelp/fetch-root.c201
1 files changed, 106 insertions, 95 deletions
diff --git a/libfshelp/fetch-root.c b/libfshelp/fetch-root.c
index d69493ba..327bbe35 100644
--- a/libfshelp/fetch-root.c
+++ b/libfshelp/fetch-root.c
@@ -36,113 +36,124 @@ fshelp_fetch_root (struct transbox *box, void *cookie,
error_t err;
mach_port_t control;
- do
+ start_over:
+
+ if (box->active != MACH_PORT_NULL)
+ assert (box->flags & TRANSBOX_STARTING == 0);
+ else
{
- if (box->active == MACH_PORT_NULL)
- do
+ mach_port_t underlying;
+ uid_t uid, gid;
+ char *argz;
+ int argz_len;
+ error_t err;
+ mach_port_t ports[INIT_PORT_MAX];
+ int ints[INIT_INT_MAX];
+ mach_port_t fds[STDERR_FILENO + 1];
+ auth_t ourauth, newauth;
+ int uidarray[2], gidarray[2];
+
+ mach_port_t
+ reauth (mach_port_t port)
{
- mach_port_t underlying;
- uid_t uid, gid;
- char *argz;
- int argz_len;
+ mach_port_t rend, ret;
error_t err;
- mach_port_t ports[INIT_PORT_MAX];
- int ints[INIT_INT_MAX];
- mach_port_t fds[STDERR_FILENO + 1];
- auth_t ourauth, newauth;
- int uidarray[2], gidarray[2];
-
- mach_port_t
- reauth (mach_port_t port)
- {
- mach_port_t rend, ret;
- error_t err;
- rend = mach_reply_port ();
- err = io_reauthenticate (port, rend,
- MACH_MSG_TYPE_MAKE_SEND);
- assert_perror (err);
-
- err = auth_user_authenticate (newauth, port, rend,
- MACH_MSG_TYPE_MAKE_SEND,
- &ret);
- if (err)
- ret = MACH_PORT_NULL;
-
- mach_port_destroy (mach_task_self (), rend);
- mach_port_deallocate (mach_task_self (), port);
- return ret;
- }
-
- err = (*callback) (box->cookie, cookie, &underlying, &uid,
- &gid, &argz, &argz_len);
- if (err)
- return err;
-
- mutex_lock (&box->innerlock); /* cancellation point XXX */
- mutex_unlock (box->lock);
-
- ourauth = getauth ();
- uidarray[0] = uidarray[1] = uid;
- gidarray[0] = gidarray[1] = gid;
- err = auth_makeauth (ourauth, MACH_PORT_NULL, 0,
- MACH_MSG_TYPE_MAKE_SEND,
- uidarray, 1, uidarray, 2,
- gidarray, 1, gidarray, 2, &newauth);
+ rend = mach_reply_port ();
+ err = io_reauthenticate (port, rend,
+ MACH_MSG_TYPE_MAKE_SEND);
assert_perror (err);
-
- bzero (ports, INIT_PORT_MAX * sizeof (mach_port_t));
- bzero (fds, (STDERR_FILENO + 1) * sizeof (mach_port_t));
- bzero (ints, INIT_INT_MAX * sizeof (int));
-
- ports[INIT_PORT_CWDIR] = reauth (getcwdir ());
- ports[INIT_PORT_CRDIR] = reauth (getcrdir ());
- ports[INIT_PORT_AUTH] = newauth;
-
- fds[STDERR_FILENO] = reauth (getdport (STDERR_FILENO));
-
- err = fshelp_start_translator_long (reauth (underlying),
- MACH_MSG_TYPE_MOVE_SEND,
- argz, argz, argz_len,
- fds, STDERR_FILENO + 1,
- MACH_MSG_TYPE_MOVE_SEND,
- ports, INIT_PORT_MAX,
- MACH_MSG_TYPE_MOVE_SEND,
- ints, INIT_INT_MAX,
- 0, &box->active);
- mutex_unlock (&box->innerlock);
-
- free (argz);
+ err = auth_user_authenticate (newauth, port, rend,
+ MACH_MSG_TYPE_MAKE_SEND,
+ &ret);
if (err)
- return err;
-
- mutex_lock (box->lock);
-
- /* The loop here is because between the interlock unlock and
- the reacquire of the node lock, someone might have deallocated
- the port we just added. */
+ ret = MACH_PORT_NULL;
+
+ mach_port_destroy (mach_task_self (), rend);
+ mach_port_deallocate (mach_task_self (), port);
+ return ret;
}
- while (box->active == MACH_PORT_NULL);
-
- control = box->active;
- mach_port_mod_refs (mach_task_self (), control,
- MACH_PORT_RIGHT_SEND, 1);
+
+ if (box->flags & TRANSBOX_STARTING)
+ {
+ box->flags |= TRANSBOX_WANTED;
+ condition_wait (&box->wakeup, box->lock);
+ goto start_over;
+ }
+ box->flags |= TRANSBOX_STARTING;
mutex_unlock (box->lock);
-
- /* Cancellation point XXX */
- err = fsys_getroot (control, dotdot, MACH_MSG_TYPE_COPY_SEND,
- uids, uids_len, gids, gids_len, flags,
- retry, retryname, root);
+
+ err = (*callback) (box->cookie, cookie, &underlying, &uid,
+ &gid, &argz, &argz_len);
+ if (err)
+ return err;
+
+ ourauth = getauth ();
+ uidarray[0] = uidarray[1] = uid;
+ gidarray[0] = gidarray[1] = gid;
+ err = auth_makeauth (ourauth, MACH_PORT_NULL, 0,
+ MACH_MSG_TYPE_MAKE_SEND,
+ uidarray, 1, uidarray, 2,
+ gidarray, 1, gidarray, 2, &newauth);
+ assert_perror (err);
+
+ bzero (ports, INIT_PORT_MAX * sizeof (mach_port_t));
+ bzero (fds, (STDERR_FILENO + 1) * sizeof (mach_port_t));
+ bzero (ints, INIT_INT_MAX * sizeof (int));
+
+ ports[INIT_PORT_CWDIR] = reauth (getcwdir ());
+ ports[INIT_PORT_CRDIR] = reauth (getcrdir ());
+ ports[INIT_PORT_AUTH] = newauth;
+
+ fds[STDERR_FILENO] = reauth (getdport (STDERR_FILENO));
+
+ err = fshelp_start_translator_long (reauth (underlying),
+ MACH_MSG_TYPE_MOVE_SEND,
+ argz, argz, argz_len,
+ fds, STDERR_FILENO + 1,
+ MACH_MSG_TYPE_MOVE_SEND,
+ ports, INIT_PORT_MAX,
+ MACH_MSG_TYPE_MOVE_SEND,
+ ints, INIT_INT_MAX,
+ 0, &control);
mutex_lock (box->lock);
-
- if ((err == MACH_SEND_INVALID_DEST || err == MIG_SERVER_DIED)
- && control == box->active)
- fshelp_set_active (box, MACH_PORT_NULL);
- mach_port_deallocate (mach_task_self (), control);
+
+ free (argz);
+
+ if (err)
+ return err;
+
+ box->active = control;
+
+ box->flags &= ~TRANSBOX_STARTING;
+ if (box->flags & TRANSBOX_WANTED)
+ {
+ box->flags &= ~TRANSBOX_WANTED;
+ condition_broadcast (&box->wakeup);
+ }
}
- while (err == MACH_SEND_INVALID_DEST || err == MIG_SERVER_DIED);
+
+ control = box->active;
+ mach_port_mod_refs (mach_task_self (), control,
+ MACH_PORT_RIGHT_SEND, 1);
+ mutex_unlock (box->lock);
+
+ /* Cancellation point XXX */
+ err = fsys_getroot (control, dotdot, MACH_MSG_TYPE_COPY_SEND,
+ uids, uids_len, gids, gids_len, flags,
+ retry, retryname, root);
+
+ mutex_lock (box->lock);
+
+ if ((err == MACH_SEND_INVALID_DEST || err == MIG_SERVER_DIED)
+ && control == box->active)
+ fshelp_set_active (box, MACH_PORT_NULL);
+ mach_port_deallocate (mach_task_self (), control);
+
+ if (err == MACH_SEND_INVALID_DEST || err == MIG_SERVER_DIED)
+ goto start_over;
return err;
}