From 84994f9fde1a1e88eeca2d9cb2cebd9160a71d55 Mon Sep 17 00:00:00 2001 From: erdgeist <> Date: Tue, 12 Mar 2013 23:41:25 +0000 Subject: tidy utility from daemon code --- jaildaemon.c | 160 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 79 insertions(+), 81 deletions(-) diff --git a/jaildaemon.c b/jaildaemon.c index ef37ed8..b903fb2 100644 --- a/jaildaemon.c +++ b/jaildaemon.c @@ -10,9 +10,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -22,13 +24,13 @@ #define IPC_PACKETSIZE 4096 #define MAGIC_EXIT_CODE 42 enum { IAM_DAEMON, IAM_CLIENT, IAM_FORKSLAVE }; +enum { TASK_RESPAWN }; static int g_uds; static int g_whoami = IAM_CLIENT; -static struct - pidfh * g_pidfilehandle; static int g_fork_slave_fd; static char g_ipc_packet[IPC_PACKETSIZE]; static int * const g_ipc_packet_int = (int*)g_ipc_packet; +static struct pidfh * g_pidfilehandle; /* For house keeping a list of all processes we attach to jails (probes), with an initial vector size of 128. The vector never shrinks. */ @@ -53,8 +55,7 @@ static int add_task_to_kqueue( int kq, daemon_task * task_in ); static pid_t fork_and_jail( int jid, char * proctitle ); static void fork_and_execve( int kq, daemon_task * task ); static int fork_fork_slave( ); -static void exerr( char * message ); -static void warn( char * message ); +static void exerr( char * message, ... ); static void usage( char * command ); /* This handler ensures that we clean up our probes if asked to terminate @@ -66,25 +67,25 @@ static void term_handler( int signal ) { /* Report error through the appropriate notification channel. Currently this just writes to stderr, which hopefully still is there. */ -static void exerr( char * message ) { +static void exerr( char * message, ... ) { + va_list args; + va_start(args, message); + switch( g_whoami ) { case IAM_DAEMON: - syslog( LOG_ERR, "Error %s\n", message ); + vsyslog( LOG_ERR, message, args ); break; case IAM_CLIENT: - fprintf( stderr, "Error %s\n", message ); + verrx( 1, message, args ); + /* Never returns */ break; case IAM_FORKSLAVE: /* TODO */ (void)message; + (void)args; break; } - exit( 11 ); -} - -/* Report a non-fatal situation */ -static void warn( char * message ) { - syslog( LOG_WARNING, "%s\n", message ); + exit( 1 ); } /* Report syntax of command line arguments to the user */ @@ -138,18 +139,26 @@ static int fork_fork_slave( ) { int sockets[2]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) - exerr("opening stream socket pair"); + exerr( "opening stream socket pair"); switch( fork() ) { case -1: - exerr("forking fork slave"); + pidfile_remove( g_pidfilehandle ); + exerr( "forking fork slave"); break; case 0: /* I am child, close master's socket fd */ close( sockets[0] ); - g_whoami = IAM_FORKSLAVE; + + /* Close IPC handle and wipe value */ + close( g_uds ); + g_uds = 0; + + /* Close pid file and wipe value */ pidfile_close( g_pidfilehandle ); g_pidfilehandle = NULL; + + g_whoami = IAM_FORKSLAVE; fork_slave( sockets[1] ); /* Never returns */ exit(0); default: @@ -189,7 +198,7 @@ static pid_t fork_and_jail( int jid, char * proctitle ) { /* Throw ourself into the jail */ if( jail_attach( jid ) ) - exerr( "when attaching to jail" ); + exerr( "when attaching to jail %d", jid ); /* wait for SIGHUP */ sigemptyset(&sigset); @@ -215,7 +224,7 @@ static int copy_daemontask( daemon_task ** out, daemon_task * const in ) { /* If all strings could be copied, return array */ if( ( !in->m_commandline || t->m_commandline ) && - ( !in->m_proctitle || t->m_proctitle ) ) + ( !in->m_proctitle || t->m_proctitle ) ) return 0; free( t->m_commandline ); @@ -328,7 +337,7 @@ static int add_task_to_kqueue( int kq, daemon_task * t_in ) { /* Expect reply from fork slave */ pid = *(pid_t*)g_ipc_packet; - /* Associate pid with command line to execute and add to our kqueue */ + /* Associate pid with command line to execute and add to our kqueue */ memset( &ke, 0, sizeof ke ); EV_SET( &ke, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, t ); if( kevent( kq, &ke, 1, NULL, 0, NULL ) == 0 ) { @@ -374,6 +383,7 @@ static int add_task_to_kqueue( int kq, daemon_task * t_in ) { /* jaildaemon -D <-ppidfile> <-fipcsockpath> -c command -j jid -t proctitle <-r> */ int main( int argc, char **argv ) { + pid_t second_pid; int kq, i; int o_force_daemon = 0; int o_daemonize = 0, o_jid = -1, o_respawn = 0; @@ -382,7 +392,7 @@ int main( int argc, char **argv ) { struct kevent ke; struct sockaddr_un addr; struct sigaction sa; - size_t ipc_bytes = IPC_PACKETSIZE; + size_t ipc_bytes = 2 * IPC_PACKETSIZE; /* init value for setsockopt */ /* If we are not started from root, there is not much we can do, neither access the unix domain socket.*/ @@ -405,57 +415,25 @@ int main( int argc, char **argv ) { } } - /* Daemonize and start a fork slave while there is no file descriptors or - initialized memory yet. Communicate with this slave via socketpair */ - if( o_daemonize ) { - pid_t second_pid; - g_pidfilehandle = pidfile_open(o_pidfile, 0600, &second_pid ); - - if (!g_pidfilehandle) { - if (errno == EEXIST) - exerr( "jaildaemon already running." ); - /* If we cannot create pidfile from other reasons, only warn. */ - warn( "Cannot open or create pidfile" ); - } - - if( daemon(1,0) == -1 ) { - pidfile_remove(g_pidfilehandle); - exerr( "daemonzing" ); - } - pidfile_write(g_pidfilehandle); - - g_fork_slave_fd = fork_fork_slave( ); - - atexit( remove_pidfile ); - openlog( "jaildaemon", 0, LOG_DAEMON ); - setlogmask(LOG_UPTO(LOG_INFO)); - g_whoami = IAM_DAEMON; - - } else { - /* Need a command line, and jid if not a daemon */ - if( !o_command || o_jid <= 0 ) - usage( argv[0] ); - } + /* Need a command line, and jid if not a daemon */ + if( !o_daemonize && ( !o_command || o_jid <= 0 ) ) + usage( argv[0] ); - /* Setup unix domain socket descriptors */ - g_uds = socket(AF_UNIX, SOCK_DGRAM, 0); - if( g_uds < 0 ) + /* Setup unix domain socket descriptors */ + if( ( g_uds = socket( AF_UNIX, SOCK_DGRAM, 0 ) ) < 0 ) exerr( "Can not create control channel." ); - if(1) { - size_t packet_size = 2 * IPC_PACKETSIZE; - socklen_t pss = sizeof(packet_size); - /* Allow huge packets on our unix domain socket */ - setsockopt( g_uds, SOL_SOCKET, SO_SNDBUF, &packet_size, pss ); - setsockopt( g_uds, SOL_SOCKET, SO_RCVBUF, &packet_size, pss ); - } + /* Allow huge packets on our unix domain socket */ + setsockopt( g_uds, SOL_SOCKET, SO_SNDBUF, &ipc_bytes, sizeof(ipc_bytes) ); + setsockopt( g_uds, SOL_SOCKET, SO_RCVBUF, &ipc_bytes, sizeof(ipc_bytes) ); + memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, o_uds_path, sizeof(addr.sun_path)-1); if( !o_daemonize ) { - /* If we're not supposed to daemonize, just try to pipe the - request to the daemon already running and exit + /* In utility mode try to pipe the request to the daemon already running + and exit Packed packet format: int m_flags ( 0x01 respawn, 0x02 executing, to be respawned ) @@ -491,12 +469,23 @@ int main( int argc, char **argv ) { exit(0); } + /* This utility mode code finished with the exit(0) above. We're daemon. */ + + /* Daemonize and start a fork slave while there is no file descriptors or + initialized memory yet. Communicate with this slave via socketpair */ + if( !( g_pidfilehandle = pidfile_open(o_pidfile, 0600, &second_pid ) ) ) { + if (errno == EEXIST) + exerr( "jaildaemon already running." ); + + /* If we cannot create pidfile from other reasons, only warn. */ + warn( "Cannot open or create pidfile" ); + } + /* Send test DGRAM through the unix domain socket. If this succeeds, there likely is another daemon already listening. You have to force the daemon to start in this case */ if( sendto( g_uds, g_ipc_packet, 0, 0, (struct sockaddr*)&addr, sizeof(addr) ) == 0 ) { - if( !o_force_daemon ) exerr( "Found command channel. Refusing to overwrite a working one." " Another server may be running. Force with -F."); @@ -504,7 +493,29 @@ int main( int argc, char **argv ) { warn( "Forcing start of daemon despite working command channel." ); } - /* Create the unix domain socket to receive commands on */ + if( daemon(1,0) == -1 ) { + pidfile_remove(g_pidfilehandle); + exerr( "daemonzing" ); + } + + pidfile_write(g_pidfilehandle); + + /* Spawn fork slave */ + g_fork_slave_fd = fork_fork_slave( ); + + /* Register pid file remover after fork() so that fork slave wont remove our + pid file*/ + atexit( remove_pidfile ); + + /* Initialize syslog facilities */ + openlog( "jaildaemon", 0, LOG_DAEMON ); + setlogmask(LOG_UPTO(LOG_INFO)); + + /* From now we log through syslog */ + g_whoami = IAM_DAEMON; + + /* Create the unix domain socket to receive commands on, N.B. error goes to + syslog, now */ unlink(o_uds_path); if (bind(g_uds, (struct sockaddr*)&addr, sizeof(addr)) == -1) exerr( "binding to command channel. Maybe another daemon is running?" ); @@ -549,19 +560,6 @@ int main( int argc, char **argv ) { memset( g_probes, 0, sizeof(pid_t) * PROBES_VECTOR_SIZE ); atexit( kill_all_probes ); - /* If daemon was started with some initial script, fire it now - -- this leaks some information in the command line to all jails and - thus is disabled - if( o_command ) { - daemon_task task; - task.m_jid = o_jid; - task.m_flags = o_respawn ? 0x01 : 0x00; - task.m_commandline = o_command; - task.m_proctitle = o_proctitle; - add_task_to_kqueue( kq, &task ); - } - */ - /* Main loop */ while( 1 ) { memset( &ke, 0, sizeof(ke) ); @@ -585,14 +583,14 @@ int main( int argc, char **argv ) { if( !task ) continue; - /* If this task was watched to respawn a daemon in the jail, + /* If this task was watched to respawn a daemon in the jail, do it now */ if( task->m_flags & 0x02 ) { task->m_flags &= ~0x02; add_task_to_kqueue( kq, task ); - /* If the process exited with the correct magic code, - execute the associated command */ + /* If the process exited with the correct magic code, + execute the associated command */ } else if( WEXITSTATUS(ke.data) == MAGIC_EXIT_CODE ) fork_and_execve( kq, task ); -- cgit v1.2.3