summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerdgeist <>2013-03-12 23:41:25 +0000
committererdgeist <>2013-03-12 23:41:25 +0000
commit84994f9fde1a1e88eeca2d9cb2cebd9160a71d55 (patch)
tree48f496903c066892336d26aa7c056f3f635f8c46
parentc889a028d58e3f2ad31f7382d5a066ed474a6f70 (diff)
tidy utility from daemon code
-rw-r--r--jaildaemon.c160
1 files 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 @@
10#include <sys/param.h> 10#include <sys/param.h>
11#include <sys/jail.h> 11#include <sys/jail.h>
12#include <sys/wait.h> 12#include <sys/wait.h>
13#include <err.h>
13#include <errno.h> 14#include <errno.h>
14#include <stdio.h> 15#include <stdio.h>
15#include <stdlib.h> 16#include <stdlib.h>
17#include <stdarg.h>
16#include <string.h> 18#include <string.h>
17#include <signal.h> 19#include <signal.h>
18#include <unistd.h> 20#include <unistd.h>
@@ -22,13 +24,13 @@
22#define IPC_PACKETSIZE 4096 24#define IPC_PACKETSIZE 4096
23#define MAGIC_EXIT_CODE 42 25#define MAGIC_EXIT_CODE 42
24enum { IAM_DAEMON, IAM_CLIENT, IAM_FORKSLAVE }; 26enum { IAM_DAEMON, IAM_CLIENT, IAM_FORKSLAVE };
27enum { TASK_RESPAWN };
25static int g_uds; 28static int g_uds;
26static int g_whoami = IAM_CLIENT; 29static int g_whoami = IAM_CLIENT;
27static struct
28 pidfh * g_pidfilehandle;
29static int g_fork_slave_fd; 30static int g_fork_slave_fd;
30static char g_ipc_packet[IPC_PACKETSIZE]; 31static char g_ipc_packet[IPC_PACKETSIZE];
31static int * const g_ipc_packet_int = (int*)g_ipc_packet; 32static int * const g_ipc_packet_int = (int*)g_ipc_packet;
33static struct pidfh * g_pidfilehandle;
32 34
33/* For house keeping a list of all processes we attach to jails (probes), with 35/* For house keeping a list of all processes we attach to jails (probes), with
34 an initial vector size of 128. The vector never shrinks. */ 36 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 );
53static pid_t fork_and_jail( int jid, char * proctitle ); 55static pid_t fork_and_jail( int jid, char * proctitle );
54static void fork_and_execve( int kq, daemon_task * task ); 56static void fork_and_execve( int kq, daemon_task * task );
55static int fork_fork_slave( ); 57static int fork_fork_slave( );
56static void exerr( char * message ); 58static void exerr( char * message, ... );
57static void warn( char * message );
58static void usage( char * command ); 59static void usage( char * command );
59 60
60/* This handler ensures that we clean up our probes if asked to terminate 61/* This handler ensures that we clean up our probes if asked to terminate
@@ -66,25 +67,25 @@ static void term_handler( int signal ) {
66 67
67/* Report error through the appropriate notification channel. 68/* Report error through the appropriate notification channel.
68 Currently this just writes to stderr, which hopefully still is there. */ 69 Currently this just writes to stderr, which hopefully still is there. */
69static void exerr( char * message ) { 70static void exerr( char * message, ... ) {
71 va_list args;
72 va_start(args, message);
73
70 switch( g_whoami ) { 74 switch( g_whoami ) {
71 case IAM_DAEMON: 75 case IAM_DAEMON:
72 syslog( LOG_ERR, "Error %s\n", message ); 76 vsyslog( LOG_ERR, message, args );
73 break; 77 break;
74 case IAM_CLIENT: 78 case IAM_CLIENT:
75 fprintf( stderr, "Error %s\n", message ); 79 verrx( 1, message, args );
80 /* Never returns */
76 break; 81 break;
77 case IAM_FORKSLAVE: 82 case IAM_FORKSLAVE:
78 /* TODO */ 83 /* TODO */
79 (void)message; 84 (void)message;
85 (void)args;
80 break; 86 break;
81 } 87 }
82 exit( 11 ); 88 exit( 1 );
83}
84
85/* Report a non-fatal situation */
86static void warn( char * message ) {
87 syslog( LOG_WARNING, "%s\n", message );
88} 89}
89 90
90/* Report syntax of command line arguments to the user */ 91/* Report syntax of command line arguments to the user */
@@ -138,18 +139,26 @@ static int fork_fork_slave( ) {
138 int sockets[2]; 139 int sockets[2];
139 140
140 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) 141 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0)
141 exerr("opening stream socket pair"); 142 exerr( "opening stream socket pair");
142 143
143 switch( fork() ) { 144 switch( fork() ) {
144 case -1: 145 case -1:
145 exerr("forking fork slave"); 146 pidfile_remove( g_pidfilehandle );
147 exerr( "forking fork slave");
146 break; 148 break;
147 case 0: 149 case 0:
148 /* I am child, close master's socket fd */ 150 /* I am child, close master's socket fd */
149 close( sockets[0] ); 151 close( sockets[0] );
150 g_whoami = IAM_FORKSLAVE; 152
153 /* Close IPC handle and wipe value */
154 close( g_uds );
155 g_uds = 0;
156
157 /* Close pid file and wipe value */
151 pidfile_close( g_pidfilehandle ); 158 pidfile_close( g_pidfilehandle );
152 g_pidfilehandle = NULL; 159 g_pidfilehandle = NULL;
160
161 g_whoami = IAM_FORKSLAVE;
153 fork_slave( sockets[1] ); /* Never returns */ 162 fork_slave( sockets[1] ); /* Never returns */
154 exit(0); 163 exit(0);
155 default: 164 default:
@@ -189,7 +198,7 @@ static pid_t fork_and_jail( int jid, char * proctitle ) {
189 198
190 /* Throw ourself into the jail */ 199 /* Throw ourself into the jail */
191 if( jail_attach( jid ) ) 200 if( jail_attach( jid ) )
192 exerr( "when attaching to jail" ); 201 exerr( "when attaching to jail %d", jid );
193 202
194 /* wait for SIGHUP */ 203 /* wait for SIGHUP */
195 sigemptyset(&sigset); 204 sigemptyset(&sigset);
@@ -215,7 +224,7 @@ static int copy_daemontask( daemon_task ** out, daemon_task * const in ) {
215 224
216 /* If all strings could be copied, return array */ 225 /* If all strings could be copied, return array */
217 if( ( !in->m_commandline || t->m_commandline ) && 226 if( ( !in->m_commandline || t->m_commandline ) &&
218 ( !in->m_proctitle || t->m_proctitle ) ) 227 ( !in->m_proctitle || t->m_proctitle ) )
219 return 0; 228 return 0;
220 229
221 free( t->m_commandline ); 230 free( t->m_commandline );
@@ -328,7 +337,7 @@ static int add_task_to_kqueue( int kq, daemon_task * t_in ) {
328 /* Expect reply from fork slave */ 337 /* Expect reply from fork slave */
329 pid = *(pid_t*)g_ipc_packet; 338 pid = *(pid_t*)g_ipc_packet;
330 339
331 /* Associate pid with command line to execute and add to our kqueue */ 340 /* Associate pid with command line to execute and add to our kqueue */
332 memset( &ke, 0, sizeof ke ); 341 memset( &ke, 0, sizeof ke );
333 EV_SET( &ke, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, t ); 342 EV_SET( &ke, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, t );
334 if( kevent( kq, &ke, 1, NULL, 0, NULL ) == 0 ) { 343 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 ) {
374/* jaildaemon -D <-ppidfile> <-fipcsockpath> -c command -j jid -t proctitle <-r> 383/* jaildaemon -D <-ppidfile> <-fipcsockpath> -c command -j jid -t proctitle <-r>
375 */ 384 */
376int main( int argc, char **argv ) { 385int main( int argc, char **argv ) {
386 pid_t second_pid;
377 int kq, i; 387 int kq, i;
378 int o_force_daemon = 0; 388 int o_force_daemon = 0;
379 int o_daemonize = 0, o_jid = -1, o_respawn = 0; 389 int o_daemonize = 0, o_jid = -1, o_respawn = 0;
@@ -382,7 +392,7 @@ int main( int argc, char **argv ) {
382 struct kevent ke; 392 struct kevent ke;
383 struct sockaddr_un addr; 393 struct sockaddr_un addr;
384 struct sigaction sa; 394 struct sigaction sa;
385 size_t ipc_bytes = IPC_PACKETSIZE; 395 size_t ipc_bytes = 2 * IPC_PACKETSIZE; /* init value for setsockopt */
386 396
387 /* If we are not started from root, there is not much we can do, 397 /* If we are not started from root, there is not much we can do,
388 neither access the unix domain socket.*/ 398 neither access the unix domain socket.*/
@@ -405,57 +415,25 @@ int main( int argc, char **argv ) {
405 } 415 }
406 } 416 }
407 417
408 /* Daemonize and start a fork slave while there is no file descriptors or 418 /* Need a command line, and jid if not a daemon */
409 initialized memory yet. Communicate with this slave via socketpair */ 419 if( !o_daemonize && ( !o_command || o_jid <= 0 ) )
410 if( o_daemonize ) { 420 usage( argv[0] );
411 pid_t second_pid;
412 g_pidfilehandle = pidfile_open(o_pidfile, 0600, &second_pid );
413
414 if (!g_pidfilehandle) {
415 if (errno == EEXIST)
416 exerr( "jaildaemon already running." );
417 /* If we cannot create pidfile from other reasons, only warn. */
418 warn( "Cannot open or create pidfile" );
419 }
420
421 if( daemon(1,0) == -1 ) {
422 pidfile_remove(g_pidfilehandle);
423 exerr( "daemonzing" );
424 }
425 pidfile_write(g_pidfilehandle);
426
427 g_fork_slave_fd = fork_fork_slave( );
428
429 atexit( remove_pidfile );
430 openlog( "jaildaemon", 0, LOG_DAEMON );
431 setlogmask(LOG_UPTO(LOG_INFO));
432 g_whoami = IAM_DAEMON;
433
434 } else {
435 /* Need a command line, and jid if not a daemon */
436 if( !o_command || o_jid <= 0 )
437 usage( argv[0] );
438 }
439 421
440 /* Setup unix domain socket descriptors */ 422 /* Setup unix domain socket descriptors */
441 g_uds = socket(AF_UNIX, SOCK_DGRAM, 0); 423 if( ( g_uds = socket( AF_UNIX, SOCK_DGRAM, 0 ) ) < 0 )
442 if( g_uds < 0 )
443 exerr( "Can not create control channel." ); 424 exerr( "Can not create control channel." );
444 425
445 if(1) { 426 /* Allow huge packets on our unix domain socket */
446 size_t packet_size = 2 * IPC_PACKETSIZE; 427 setsockopt( g_uds, SOL_SOCKET, SO_SNDBUF, &ipc_bytes, sizeof(ipc_bytes) );
447 socklen_t pss = sizeof(packet_size); 428 setsockopt( g_uds, SOL_SOCKET, SO_RCVBUF, &ipc_bytes, sizeof(ipc_bytes) );
448 /* Allow huge packets on our unix domain socket */ 429
449 setsockopt( g_uds, SOL_SOCKET, SO_SNDBUF, &packet_size, pss );
450 setsockopt( g_uds, SOL_SOCKET, SO_RCVBUF, &packet_size, pss );
451 }
452 memset(&addr, 0, sizeof(addr)); 430 memset(&addr, 0, sizeof(addr));
453 addr.sun_family = AF_UNIX; 431 addr.sun_family = AF_UNIX;
454 strncpy(addr.sun_path, o_uds_path, sizeof(addr.sun_path)-1); 432 strncpy(addr.sun_path, o_uds_path, sizeof(addr.sun_path)-1);
455 433
456 if( !o_daemonize ) { 434 if( !o_daemonize ) {
457 /* If we're not supposed to daemonize, just try to pipe the 435 /* In utility mode try to pipe the request to the daemon already running
458 request to the daemon already running and exit 436 and exit
459 437
460 Packed packet format: 438 Packed packet format:
461 int m_flags ( 0x01 respawn, 0x02 executing, to be respawned ) 439 int m_flags ( 0x01 respawn, 0x02 executing, to be respawned )
@@ -491,12 +469,23 @@ int main( int argc, char **argv ) {
491 exit(0); 469 exit(0);
492 } 470 }
493 471
472 /* This utility mode code finished with the exit(0) above. We're daemon. */
473
474 /* Daemonize and start a fork slave while there is no file descriptors or
475 initialized memory yet. Communicate with this slave via socketpair */
476 if( !( g_pidfilehandle = pidfile_open(o_pidfile, 0600, &second_pid ) ) ) {
477 if (errno == EEXIST)
478 exerr( "jaildaemon already running." );
479
480 /* If we cannot create pidfile from other reasons, only warn. */
481 warn( "Cannot open or create pidfile" );
482 }
483
494 /* Send test DGRAM through the unix domain socket. If this succeeds, there 484 /* Send test DGRAM through the unix domain socket. If this succeeds, there
495 likely is another daemon already listening. You have to force the daemon 485 likely is another daemon already listening. You have to force the daemon
496 to start in this case */ 486 to start in this case */
497 if( sendto( g_uds, g_ipc_packet, 0, 0, 487 if( sendto( g_uds, g_ipc_packet, 0, 0,
498 (struct sockaddr*)&addr, sizeof(addr) ) == 0 ) { 488 (struct sockaddr*)&addr, sizeof(addr) ) == 0 ) {
499
500 if( !o_force_daemon ) 489 if( !o_force_daemon )
501 exerr( "Found command channel. Refusing to overwrite a working one." 490 exerr( "Found command channel. Refusing to overwrite a working one."
502 " Another server may be running. Force with -F."); 491 " Another server may be running. Force with -F.");
@@ -504,7 +493,29 @@ int main( int argc, char **argv ) {
504 warn( "Forcing start of daemon despite working command channel." ); 493 warn( "Forcing start of daemon despite working command channel." );
505 } 494 }
506 495
507 /* Create the unix domain socket to receive commands on */ 496 if( daemon(1,0) == -1 ) {
497 pidfile_remove(g_pidfilehandle);
498 exerr( "daemonzing" );
499 }
500
501 pidfile_write(g_pidfilehandle);
502
503 /* Spawn fork slave */
504 g_fork_slave_fd = fork_fork_slave( );
505
506 /* Register pid file remover after fork() so that fork slave wont remove our
507 pid file*/
508 atexit( remove_pidfile );
509
510 /* Initialize syslog facilities */
511 openlog( "jaildaemon", 0, LOG_DAEMON );
512 setlogmask(LOG_UPTO(LOG_INFO));
513
514 /* From now we log through syslog */
515 g_whoami = IAM_DAEMON;
516
517 /* Create the unix domain socket to receive commands on, N.B. error goes to
518 syslog, now */
508 unlink(o_uds_path); 519 unlink(o_uds_path);
509 if (bind(g_uds, (struct sockaddr*)&addr, sizeof(addr)) == -1) 520 if (bind(g_uds, (struct sockaddr*)&addr, sizeof(addr)) == -1)
510 exerr( "binding to command channel. Maybe another daemon is running?" ); 521 exerr( "binding to command channel. Maybe another daemon is running?" );
@@ -549,19 +560,6 @@ int main( int argc, char **argv ) {
549 memset( g_probes, 0, sizeof(pid_t) * PROBES_VECTOR_SIZE ); 560 memset( g_probes, 0, sizeof(pid_t) * PROBES_VECTOR_SIZE );
550 atexit( kill_all_probes ); 561 atexit( kill_all_probes );
551 562
552 /* If daemon was started with some initial script, fire it now
553 -- this leaks some information in the command line to all jails and
554 thus is disabled
555 if( o_command ) {
556 daemon_task task;
557 task.m_jid = o_jid;
558 task.m_flags = o_respawn ? 0x01 : 0x00;
559 task.m_commandline = o_command;
560 task.m_proctitle = o_proctitle;
561 add_task_to_kqueue( kq, &task );
562 }
563 */
564
565 /* Main loop */ 563 /* Main loop */
566 while( 1 ) { 564 while( 1 ) {
567 memset( &ke, 0, sizeof(ke) ); 565 memset( &ke, 0, sizeof(ke) );
@@ -585,14 +583,14 @@ int main( int argc, char **argv ) {
585 if( !task ) 583 if( !task )
586 continue; 584 continue;
587 585
588 /* If this task was watched to respawn a daemon in the jail, 586 /* If this task was watched to respawn a daemon in the jail,
589 do it now */ 587 do it now */
590 if( task->m_flags & 0x02 ) { 588 if( task->m_flags & 0x02 ) {
591 task->m_flags &= ~0x02; 589 task->m_flags &= ~0x02;
592 add_task_to_kqueue( kq, task ); 590 add_task_to_kqueue( kq, task );
593 591
594 /* If the process exited with the correct magic code, 592 /* If the process exited with the correct magic code,
595 execute the associated command */ 593 execute the associated command */
596 } else if( WEXITSTATUS(ke.data) == MAGIC_EXIT_CODE ) 594 } else if( WEXITSTATUS(ke.data) == MAGIC_EXIT_CODE )
597 fork_and_execve( kq, task ); 595 fork_and_execve( kq, task );
598 596