--- a/ext/bsdjail.c Fri Aug 15 16:23:03 2008 +0000
+++ b/ext/bsdjail.c Thu Oct 16 02:43:08 2008 +0000
@@ -29,6 +29,32 @@
/*
+ * Debug logging function
+ */
+void
+#ifdef HAVE_STDARG_PROTOTYPES
+rlink_debug(const char *fmt, ...)
+#else
+rlink_debug( const char *fmt, va_dcl )
+#endif
+{
+ char buf[BUFSIZ], buf2[BUFSIZ];
+ va_list args;
+
+ if ( !RTEST(ruby_debug) ) return;
+
+ snprintf( buf, BUFSIZ, "Jail Debug>>> %s", fmt );
+
+ va_init_list( args, fmt );
+ vsnprintf( buf2, BUFSIZ, buf, args );
+ fputs( buf2, stderr );
+ fputs( "\n", stderr );
+ fflush( stderr );
+ va_end( args );
+}
+
+
+/*
struct jail {
u_int32_t version;
char *path;
@@ -41,8 +67,7 @@
* Allocation function
*/
static jail *
-rbjail_jail_alloc()
-{
+rbjail_jail_alloc() {
jail *ptr = ALLOC( jail );
ptr->version = 0;
@@ -59,17 +84,19 @@
* GC Free function
*/
static void
-rbjail_jail_gc_free( ptr )
- jail *ptr;
-{
+rbjail_gc_free( jail *ptr ) {
if ( ptr ) {
+ if ( ptr->path ) xfree( ptr->path );
+ if ( ptr->hostname ) xfree( ptr->hostname );
+
ptr->path = NULL;
ptr->hostname = NULL;
+
xfree( ptr );
}
else {
- debugMsg(( "Not freeing an uninitialized rlink_SENTENCE" ));
+ debugMsg(( "Not freeing an uninitialized jail" ));
}
}
@@ -77,15 +104,13 @@
/*
* Object validity checker. Returns the data pointer.
*/
-static rlink_SENTENCE *
-check_sentence( self )
- VALUE self;
-{
- debugMsg(( "Checking a LinkParser::Sentence object (%d).", self ));
+static jail *
+rbjail_check_jail( VALUE self ) {
+ debugMsg(( "Checking a BSD::Jail object (%d).", self ));
Check_Type( self, T_DATA );
- if ( !IsSentence(self) ) {
- rb_raise( rb_eTypeError, "wrong argument type %s (expected LinkParser::Sentence)",
+ if ( !rb_obj_is_kind_of(self, rbjail_cBSDJail) ) {
+ rb_raise( rb_eTypeError, "wrong argument type %s (expected BSD::Jail)",
rb_class2name(CLASS_OF( self )) );
}
@@ -96,13 +121,11 @@
/*
* Fetch the data pointer and check it for sanity.
*/
-static rlink_SENTENCE *
-get_sentence( self )
- VALUE self;
-{
- rlink_SENTENCE *ptr = check_sentence( self );
+static jail *
+rbjail_get_jail( VALUE self ) {
+ jail *ptr = check_sentence( self );
- debugMsg(( "Fetching a Sentence (%p).", ptr ));
+ debugMsg(( "Fetching a Jail (%p).", ptr ));
if ( !ptr )
rb_raise( rb_eRuntimeError, "uninitialized Sentence" );
@@ -110,21 +133,13 @@
}
+/* --------------------------------------------------------------
+ * Jail utility functions
+ * -------------------------------------------------------------- */
+
/*
- * Publicly-usable sentence-fetcher
+ * Try to jail_attach() to the specified +jid+, raising an exception if it fails.
*/
-rlink_SENTENCE *
-rlink_get_sentence( self )
- VALUE self;
-{
- return get_sentence( self );
-}
-
-
-
-
-
-
static void
rbjail_do_jail_attach( int jid )
{
@@ -132,7 +147,10 @@
rb_sys_fail( "jail_attach" );
}
-/* Mostly ripped off from Ruby's process.c */
+
+/*
+ * Fork + Block function for rbjail_attach(). Mostly stolen from Ruby's process.c.
+ */
static VALUE
rbjail_attach_block( int jid )
{
@@ -140,8 +158,8 @@
rb_secure(2);
- fflush(stdout);
- fflush(stderr);
+ fflush( stdout );
+ fflush( stderr );
switch ( pid = fork() ) {
case 0:
@@ -164,9 +182,132 @@
}
}
+
+/* --------------------------------------------------------------
+ * Class methods
+ * -------------------------------------------------------------- */
+
+/*
+ * call-seq:
+ * BSD::Jail.allocate -> bsdjail
+ *
+ * Allocate a new BSD::Jail object.
+ *
+ */
static VALUE
-rbjail_attach( int argc, VALUE *argv, VALUE self )
-{
+rbjail_jail_s_allocate( VALUE klass ) {
+ return Data_Wrap_Struct( klass, 0, rbjail_gc_free, 0 );
+}
+
+
+/*
+ * call-seq:
+ * BSD::Jail.list -> array
+ *
+ * Return an Array of all the running jails on the host.
+ *
+ */
+static VALUE
+rbjail_jail_s_list( VALUE klass ) {
+ VALUE rval = rb_ary_new();
+ struct xprison *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( xprison, 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 );
+ for ( i = 0; i < len; i++ ) {
+ VALUE jail, args[3];
+
+ /* Hostname */
+ args[0] = rb_str_new2( xp->pr_host );
+
+ /* IP */
+ in.s_addr = ntohl( xp->pr_ip );
+ args[1] = rb_str_new2( inet_ntoa(in) );
+
+ /* Path */
+ args[2] = rb_str_new2( xp->pr_path );
+
+ jail = rb_class_new_instance( 3, args, klass );
+ rb_ary_push( rval, jail );
+
+ xp++;
+ }
+
+ return rval;
+}
+
+
+
+
+/* --------------------------------------------------------------
+ * Instance methods
+ * -------------------------------------------------------------- */
+
+/*
+ * call-seq:
+ * BSD::Jail.new( hostname, ip, path ) -> new_jail
+ *
+ * Create a new jail for the given +hostname+, +ip+, and +path+.
+ */
+static VALUE
+rbjail_jail_initialize( VALUE self, VALUE hostname, VALUE ip, VALUE path ) {
+ if ( !rbjail_check_jail(self) ) {
+ struct jail *ptr = rbjail_jail_alloc();
+ char *pathstr = NULL, *hostnamestr = NULL;
+
+ Check_Type( hostname, T_STRING );
+ Check_Type( ip, T_STRING );
+
+ pathstr = ALLOC_N( char, RSTRING(path)->len );
+ strncpy( pathstr, RSTRING(path)->ptr, RSTRING(path)->len );
+
+ hostnamestr = ALLOC_N( char, RSTRING(hostname)->len );
+ strncpy( hostnamestr, RSTRING(hostname)->ptr, RSTRING(hostname)->len );
+
+ /*
+ struct jail {
+ u_int32_t version;
+ char *path;
+ char *hostname;
+ u_int32_t ip_number;
+ };
+ */
+ ptr->version = 0; /* Per the manpage's recommendation */
+ ptr->ip_number = inet_addr( StringValuePtr(ip) );
+ ptr->path = path;
+ ptr->hostname = hostname;
+ }
+}
+
+
+/*
+ * call-seq:
+ * jail.attach -> true or false
+ * jail.attach { block } -> pid
+ *
+ * Attach to the given jail. In the non-block form, attach the current process to the
+ * jail and return +true+ if it succeeds. This is a one-way operation, and requires root
+ * privileges.
+ *
+ * In the block form, the process will be forked, and the block will be attached to the jail and
+ * run by the child. The parent process will receive the process ID of the child.
+ */
+static VALUE
+rbjail_attach( int argc, VALUE *argv, VALUE self ) {
VALUE jidnum, rval;
int jid;
@@ -185,49 +326,27 @@
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);
-
-}
-
+/*
+ * I can't remember how the hell you document a class, but that will go here.
+ */
void
-Init_bsdjail( 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, )
+ /* Class methods */
+ rb_define_alloc_function( rbjail_cBSDJail, rbjail_jail_s_allocate );
+ rb_define_singleton_method( rbjail_cBSDJail, "jail", rbjail_jail_s_jail, 0 );
+ rb_define_singleton_method( rbjail_cBSDJail, "list", rbjail_jail_s_list, 0 );
- rb_define_method( rbjail_cBSDJail, "attach", rbjail_attach, -1 );
+ /* Instance methods */
+ rb_define_method( rbjail_cBSDJail, "initialize", rbjail_jail_initialize, 3 );
+ rb_define_method( rbjail_cBSDJail, "attach", rbjail_jail_attach, -1 );
+ rb_define_method( rbjail_cBSDJail, "hostname", rbjail_jail_hostname, 0 );
+ rb_define_method( rbjail_cBSDJail, "path", rbjail_jail_path, 0 );
+ rb_define_method( rbjail_cBSDJail, "ip", rbjail_jail_ip, 0 );
+ rb_define_method( rbjail_cBSDJail, "jid", rbjail_jail_jid, 0 );
}