diff options
| author | erdgeist <> | 2013-03-12 23:41:25 +0000 |
|---|---|---|
| committer | erdgeist <> | 2013-03-12 23:41:25 +0000 |
| commit | 84994f9fde1a1e88eeca2d9cb2cebd9160a71d55 (patch) | |
| tree | 48f496903c066892336d26aa7c056f3f635f8c46 | |
| parent | c889a028d58e3f2ad31f7382d5a066ed474a6f70 (diff) | |
tidy utility from daemon code
| -rw-r--r-- | jaildaemon.c | 160 |
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 |
| 24 | enum { IAM_DAEMON, IAM_CLIENT, IAM_FORKSLAVE }; | 26 | enum { IAM_DAEMON, IAM_CLIENT, IAM_FORKSLAVE }; |
| 27 | enum { TASK_RESPAWN }; | ||
| 25 | static int g_uds; | 28 | static int g_uds; |
| 26 | static int g_whoami = IAM_CLIENT; | 29 | static int g_whoami = IAM_CLIENT; |
| 27 | static struct | ||
| 28 | pidfh * g_pidfilehandle; | ||
| 29 | static int g_fork_slave_fd; | 30 | static int g_fork_slave_fd; |
| 30 | static char g_ipc_packet[IPC_PACKETSIZE]; | 31 | static char g_ipc_packet[IPC_PACKETSIZE]; |
| 31 | static int * const g_ipc_packet_int = (int*)g_ipc_packet; | 32 | static int * const g_ipc_packet_int = (int*)g_ipc_packet; |
| 33 | static 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 ); | |||
| 53 | static pid_t fork_and_jail( int jid, char * proctitle ); | 55 | static pid_t fork_and_jail( int jid, char * proctitle ); |
| 54 | static void fork_and_execve( int kq, daemon_task * task ); | 56 | static void fork_and_execve( int kq, daemon_task * task ); |
| 55 | static int fork_fork_slave( ); | 57 | static int fork_fork_slave( ); |
| 56 | static void exerr( char * message ); | 58 | static void exerr( char * message, ... ); |
| 57 | static void warn( char * message ); | ||
| 58 | static void usage( char * command ); | 59 | static 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. */ |
| 69 | static void exerr( char * message ) { | 70 | static 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 */ | ||
| 86 | static 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 | */ |
| 376 | int main( int argc, char **argv ) { | 385 | int 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 | ||
