/*
 *  call-seq:
 *     Process::GID.switch              => fixnum
 *     Process::GID.switch {|| block}   => object
 *
 *  Switch the effective and real group IDs of the current process. If
 *  a <em>block</em> is given, the group IDs will be switched back
 *  after the block is executed. Returns the new effective group ID if
 *  called without a block, and the return value of the block if one
 *  is given.
 *
 */

static VALUE
p_gid_switch(obj)
    VALUE obj;
{
    int gid, egid;

    check_gid_switch();

    gid = getgid();
    egid = getegid();

    if (gid != egid) {
        proc_setegid(obj, INT2FIX(gid));
        if (rb_block_given_p()) {
            under_gid_switch = 1;
            return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, SAVED_GROUP_ID);
        } else {
            return INT2FIX(egid);
        }
    } else if (egid != SAVED_GROUP_ID) {
        proc_setegid(obj, INT2FIX(SAVED_GROUP_ID));
        if (rb_block_given_p()) {
            under_gid_switch = 1;
            return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, egid);
        } else {
            return INT2FIX(gid);
        }
    } else {
        errno = EPERM;
        rb_sys_fail(0);
    }
#else
static VALUE
p_gid_sw_ensure(obj)
    VALUE obj;
{
    under_gid_switch = 0;
    return p_gid_exchange(obj);
}