core-extra/netns/vnoded_main.c

227 lines
4.5 KiB
C

/*
* CORE
* Copyright (c)2010-2012 the Boeing Company.
* See the LICENSE file included in this distribution.
*
* author: Tom Goff <thomas.goff@boeing.com>
*
* vnoded_main.c
*
* vnoded daemon runs as PID 1 in the Linux namespace container and receives
* and executes commands via a control channel.
*
*/
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#include <sys/wait.h>
#include "version.h"
#include "vnode_server.h"
#include "myerr.h"
int verbose;
static vnode_server_t *vnodeserver;
struct option longopts[] =
{
{"version", no_argument, NULL, 'V'},
{"help", no_argument, NULL, 'h'},
{ 0 }
};
static void usage(int status, char *fmt, ...)
{
extern const char *__progname;
va_list ap;
FILE *output;
va_start(ap, fmt);
output = status ? stderr : stdout;
fprintf(output, "\n");
if (fmt != NULL)
{
vfprintf(output, fmt, ap);
fprintf(output, "\n\n");
}
fprintf(output,
"Usage: %s [-h|-V] [-v] [-n] [-C <chdir>] [-l <logfile>] "
"[-p <pidfile>] -c <control channel>\n\n"
"Linux namespace container server daemon runs as PID 1 in the "
"container. \nNormally this process is launched automatically by the "
"CORE daemon.\n\nOptions:\n"
" -h, --help show this help message and exit\n"
" -V, --version show version number and exit\n"
" -v enable verbose logging\n"
" -n do not create and run daemon within a new network namespace "
"(for debug)\n"
" -C change to the specified <chdir> directory\n"
" -l log output to the specified <logfile> file\n"
" -p write process id to the specified <pidfile> file\n"
" -c establish the specified <control channel> for receiving "
"control commands\n",
__progname);
va_end(ap);
exit(0);
}
static void sigexit(int signum)
{
WARNX("exiting due to signal: %d", signum);
exit(0);
return;
}
static void cleanup_sigchld(int signum)
{
/* nothing */
}
static void cleanup()
{
static int incleanup = 0;
if (incleanup)
return;
incleanup = 1;
if (vnodeserver)
{
struct ev_loop *loop = vnodeserver->loop;
vnode_delserver(vnodeserver);
if (loop)
ev_unloop(loop, EVUNLOOP_ALL);
}
/* don't use SIG_IGN here because receiving SIGCHLD is needed to
* interrupt the sleep below in order to avoid long delays
*/
if (signal(SIGCHLD, cleanup_sigchld) == SIG_ERR)
WARN("signal() failed");
if (getpid() == 1)
{
struct timespec delay = {
.tv_sec = 2,
.tv_nsec = 0,
};
/* try to gracefully terminate all processes in this namespace
* first
*/
kill(-1, SIGTERM);
/* wait for child processes to terminate */
for (;;)
{
pid_t pid;
int err;
struct timespec rem;
pid = waitpid(-1, NULL, WNOHANG);
if (pid == -1)
break; /* an error occurred */
if (pid != 0)
continue; /* a child was reaped */
err = nanosleep(&delay, &rem);
if (err == -1 && errno == EINTR)
{
delay = rem;
continue;
}
/* force termination after delay */
kill(-1, SIGKILL);
break;
}
}
return;
}
int main(int argc, char *argv[])
{
int newnetns = 1;
char *ctrlchnlname = NULL, *logfilename = NULL, *chdirname = NULL;
char *pidfilename = NULL;
extern const char *__progname;
for (;;)
{
int opt;
if ((opt = getopt_long(argc, argv, "c:C:l:nvVhp:", longopts, NULL)) == -1)
break;
switch (opt)
{
case 'c':
ctrlchnlname = optarg;
break;
case 'C':
chdirname = optarg;
break;
case 'l':
logfilename = optarg;
break;
case 'n':
newnetns = 0;
break;
case 'p':
pidfilename = optarg;
break;
case 'v':
verbose++;
break;
case 'V':
printf("%s version %s\n", __progname, CORE_VERSION);
exit(0);
case 'h':
/* pass through */
default:
usage(0, NULL);
}
}
argc -= optind;
argv += optind;
if (ctrlchnlname == NULL)
usage(1, "no control channel given");
for (; argc; argc--, argv++)
WARNX("ignoring command line argument: '%s'", *argv);
if (atexit(cleanup))
ERR(1, "atexit() failed");
if (signal(SIGTERM, sigexit) == SIG_ERR)
ERR(1, "signal() failed");
if (signal(SIGINT, sigexit) == SIG_ERR)
ERR(1, "signal() failed");
/* XXX others? */
vnodeserver = vnoded(newnetns, ctrlchnlname, logfilename, pidfilename,
chdirname);
if (vnodeserver == NULL)
ERRX(1, "vnoded() failed");
ev_loop(vnodeserver->loop, 0);
exit(0);
}