diff options
Diffstat (limited to 'libfshelp/fetch-root.c')
-rw-r--r-- | libfshelp/fetch-root.c | 201 |
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; } |