ext/bsdjail.c
author Mahlon E. Smith <mahlon@martini.nu>
Tue, 14 Oct 2008 16:11:19 +0000
branchmahlon-misc
changeset 9 4c51ebe6e9b6
parent 0 92d00ff32c56
child 11 e908d309e7ec
permissions -rw-r--r--
* Add a mkrf monkeypatch so BSD build flags are generated correctly. * Fix typos!

/*
 *  bsdjail.c - Ruby jparallel
 *  $Id$
 *  
 *  Authors:
 *    * Michael Granger <ged@FaerieMUD.org>
 *    * Mahlon E. Smith <mahlon@martini.nu>
 *  
 *  Copyright (c) 2006 The FaerieMUD Consortium.
 *  
 *  This work is licensed under the Creative Commons Attribution License. To
 *  view a copy of this license, visit
 *  http://creativecommons.org/licenses/by/1.0 or send a letter to Creative
 *  Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
 *  
 */

#include <ruby.h>
#include <intern.h>

#include <stdio.h>
#include <sys/param.h>
#include <sys/jail.h>
#include <sys/types.h>
#include <unistd.h>


VALUE rbjail_mBSD;
VALUE rbjail_cBSDJail;


/*
struct jail {
	u_int32_t       version;
	char            *path;
	char            *hostname;
	u_int32_t       ip_number;
};
*/

/*
 * Allocation function
 */
static jail *
rbjail_jail_alloc()
{
	jail *ptr = ALLOC( jail );
	
	ptr->version	= 0;
	ptr->path		= NULL;
	ptr->hostname	= NULL;
	ptr->ip_number	= 0;
	
	debugMsg(( "Initialized a jail pointer <%p>", ptr ));
	return ptr;
}


/*
 * GC Free function
 */
static void
rbjail_jail_gc_free( ptr )
	jail *ptr;
{
	if ( ptr ) {
		ptr->path		= NULL;
		ptr->hostname	= NULL;
		xfree( ptr );
	}
	
	else {
		debugMsg(( "Not freeing an uninitialized rlink_SENTENCE" ));
	}
}


/*
 * Object validity checker. Returns the data pointer.
 */
static rlink_SENTENCE *
check_sentence( self )
	 VALUE	self;
{
	debugMsg(( "Checking a LinkParser::Sentence object (%d).", self ));
	Check_Type( self, T_DATA );

    if ( !IsSentence(self) ) {
		rb_raise( rb_eTypeError, "wrong argument type %s (expected LinkParser::Sentence)",
				  rb_class2name(CLASS_OF( self )) );
    }
	
	return DATA_PTR( self );
}


/*
 * Fetch the data pointer and check it for sanity.
 */
static rlink_SENTENCE *
get_sentence( self )
	 VALUE self;
{
	rlink_SENTENCE *ptr = check_sentence( self );

	debugMsg(( "Fetching a Sentence (%p).", ptr ));
	if ( !ptr )
		rb_raise( rb_eRuntimeError, "uninitialized Sentence" );

	return ptr;
}


/*
 * Publicly-usable sentence-fetcher
 */
rlink_SENTENCE *
rlink_get_sentence( self )
	VALUE self;
{
	return get_sentence( self );
}






static void
rbjail_do_jail_attach( int jid )
{
	if ( jail_attach(jid) == -1 )
		rb_sys_fail( "jail_attach" );
}

/* Mostly ripped off from Ruby's process.c */
static VALUE
rbjail_attach_block( int jid )
{
    int pid;

    rb_secure(2);

    fflush(stdout);
    fflush(stderr);

	switch ( pid = fork() ) {
		case 0:
			rb_thread_atfork();
			if ( rb_block_given_p() ) {
				int status;

				rbjail_do_jail_attach( jid );
				rb_protect( rb_yield, Qundef, &status );
				ruby_stop( status );
			}
			return Qnil;

		case -1:
			rb_sys_fail( "fork(2)" );
			return Qnil;

		default:
			return INT2FIX( pid );
	}
}

static VALUE
rbjail_attach( int argc, VALUE *argv, VALUE self )
{
	VALUE jidnum, rval;
	int jid;
	
	rb_scan_args( argc, argv, "1", &jidnum );
	jid = NUM2INT( jidnum );

	if ( rb_block_given_p() ) {
		rval = rbjail_attach_block( jid );
	}
	
	else {
		rbjail_do_jail_attach( jid );
		rval = Qtrue;
	}
	
	return rval;
}

static VALUE
	rbjail_list( VALUE self )
{
	struct kinfo_prison *sxp, *xp;
	struct in_addr in;
	size_t i, len;

	if (sysctlbyname("jail.list", NULL, &len, NULL, 0) == -1)
		rb_sys_fail("sysctlbyname(): jail.list");

	xp = ALLOCA_N( kinfo_prison, 1 );

	if (sysctlbyname("jail.list", xp, &len, NULL, 0) == -1) {
		rb_sys_fail("sysctlbyname(): jail.list");
	}

	if (len < sizeof(*xp) || len % sizeof(*xp) ||
		xp->pr_version != KINFO_PRISON_VERSION)
		rb_fatal("Kernel and userland out of sync");

	len /= sizeof(*xp);
	printf("   JID  IP Address      Hostname                      Path\n");
	for (i = 0; i < len; i++) {
		in.s_addr = ntohl(xp->pr_ip);
		printf("%6d  %-15.15s %-29.29s %.74s\n",
			xp->pr_id, inet_ntoa(in), xp->pr_host, xp->pr_path);
		xp++;
	}
	free(sxp);
	exit(0);

}

void
Init_bsdjail( void )
{
	rbjail_mBSD = rb_define_module( "BSD" );
	rbjail_cBSDJail = rb_define_class_under( rbjail_mBSD, "Jail" );

	rb_define_singleton_method( rbjail_cBSDJail, "list", rbjail_list, 0 );
	rb_define_alloc_function( rbjail_cBSDJail, )
	
	rb_define_method( rbjail_cBSDJail, "attach", rbjail_attach, -1 );
	
}