]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/lxc_start.c
use pivot_root instead of chroot
[mirror_lxc.git] / src / lxc / lxc_start.c
index a60d1491d791c73e76581378451527857fa72f26..fdd3b156872da133ebc8d4940a59da7ea65c6db4 100644 (file)
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
+#define _GNU_SOURCE
 #include <stdio.h>
+#undef _GNU_SOURCE
 #include <libgen.h>
+#include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 #include <termios.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
 #include <sys/param.h>
 #include <sys/utsname.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 #include <arpa/inet.h>
 #include <netinet/in.h>
 #include <net/if.h>
 
-#include <lxc/lxc.h>
-#include <lxc/log.h>
+#include "log.h"
+#include "lxc.h"
+#include "conf.h"
+#include "utils.h"
+#include "config.h"
+#include "confile.h"
+#include "arguments.h"
 
 lxc_log_define(lxc_start, lxc);
 
-void usage(char *cmd)
+static int my_parser(struct lxc_arguments* args, int c, char* arg)
 {
-       fprintf(stderr, "%s <command>\n", basename(cmd));
-       fprintf(stderr, "\t -n <name>   : name of the container\n");
-       fprintf(stderr, "\t[-o <logfile>]    : path of the log file\n");
-       fprintf(stderr, "\t[-l <logpriority>]: log level priority\n");
-       _exit(1);
+       switch (c) {
+       case 'd': args->daemonize = 1; break;
+       case 'f': args->rcfile = arg; break;
+       }
+       return 0;
+}
+
+static const struct option my_longopts[] = {
+       {"daemon", no_argument, 0, 'd'},
+       {"rcfile", required_argument, 0, 'f'},
+       LXC_COMMON_OPTIONS
+};
+
+static struct lxc_arguments my_args = {
+       .progname = "lxc-start",
+       .help     = "\
+--name=NAME -- COMMAND\n\
+\n\
+lxc-start start COMMAND in specified container NAME\n\
+\n\
+Options :\n\
+  -n, --name=NAME      NAME for name of the container\n\
+  -d, --daemon         daemonize the container\n\
+  -f, --rcfile=FILE    Load configuration file FILE\n",
+       .options   = my_longopts,
+       .parser    = my_parser,
+       .checker   = NULL,
+       .daemonize = 0,
+};
+
+static int save_tty(struct termios *tios)
+{
+       if (!isatty(0))
+               return 0;
+
+       if (tcgetattr(0, tios))
+               WARN("failed to get current terminal settings : %s",
+                    strerror(errno));
+
+       return 0;
+}
+
+static int restore_tty(struct termios *tios)
+{
+       struct termios current_tios;
+       void (*oldhandler)(int);
+       int ret;
+
+       if (!isatty(0))
+               return 0;
+
+       if (tcgetattr(0, &current_tios)) {
+               ERROR("failed to get current terminal settings : %s",
+                     strerror(errno));
+               return -1;
+       }
+
+       if (!memcmp(tios, &current_tios, sizeof(*tios)))
+               return 0;
+
+       oldhandler = signal(SIGTTOU, SIG_IGN);
+       ret = tcsetattr(0, TCSADRAIN, tios);
+       if (ret)
+               ERROR("failed to restore terminal attributes");
+       signal(SIGTTOU, oldhandler);
+
+       return ret;
 }
 
 int main(int argc, char *argv[])
 {
-       char *name = NULL;
-       const char *log_file = NULL, *log_priority = NULL;
-       char **args;
-       int opt, err = LXC_ERROR_INTERNAL, nbargs = 0;
+       char *const *args;
+       int err = -1;
        struct termios tios;
 
-       char *default_args[] = {
+       char *const default_args[] = {
                "/sbin/init",
                '\0',
        };
 
-       while ((opt = getopt(argc, argv, "n:o:l:")) != -1) {
-               switch (opt) {
-               case 'n':
-                       name = optarg;
-                       break;
-               case 'o':
-                       log_file = optarg;
-                       break;
-               case 'l':
-                       log_priority = optarg;
-                       break;
-               }
+       char *rcfile = NULL;
+       struct lxc_conf *conf;
 
-               nbargs++;
-       }
+       if (lxc_arguments_parse(&my_args, argc, argv))
+               return err;
 
-       if (!argv[optind] || !strlen(argv[optind]))
+       if (!my_args.argc)
                args = default_args; 
+       else
+               args = my_args.argv;
+
+       if (lxc_log_init(my_args.log_file, my_args.log_priority,
+                        my_args.progname, my_args.quiet))
+               return err;
+
+       /* rcfile is specified in the cli option */
+       if (my_args.rcfile)
+               rcfile = (char *)my_args.rcfile;
        else {
-               args = &argv[optind];
-               argc -= nbargs;
+               if (!asprintf(&rcfile, LXCPATH "/%s/config", my_args.name)) {
+                       SYSERROR("failed to allocate memory");
+                       return err;
+               }
+
+               /* container configuration does not exist */
+               if (access(rcfile, F_OK)) {
+                       free(rcfile);
+                       rcfile = NULL;
+               }
        }
 
-       if (!name)
-               usage(argv[0]);
+       conf = lxc_conf_init();
+       if (!conf) {
+               ERROR("failed to initialize configuration");
+               return err;
+       }
 
-       if (lxc_log_init(log_file, log_priority, basename(argv[0])))
-               return 1;
+       if (rcfile && lxc_config_read(rcfile, conf)) {
+               ERROR("failed to read configuration file");
+               return err;
+       }
 
-       if (tcgetattr(0, &tios)) {
-               ERROR("failed to get current terminal settings : %s",
-                     strerror(errno));
-               return 1;
+       if (!rcfile && !strcmp("/sbin/init", args[0])) {
+               ERROR("no configuration file for '/sbin/init' (may crash the host)");
+               return err;
        }
 
-       err = lxc_start(name, args);
-       if (err) {
-               ERROR("failed to start : %s\n", lxc_strerror(err));
-               err = 1;
+       if (my_args.daemonize) {
+
+                /* do not chdir as we want to open the log file,
+                * change the directory right after.
+                * do not close 0, 1, 2, we want to do that
+                * ourself because we don't want /dev/null
+                * being reopened.
+                */
+               if (daemon(1, 1)) {
+                       SYSERROR("failed to daemonize '%s'", my_args.name);
+                       return err;
+               }
+
+               lxc_close_inherited_fd(0);
+               lxc_close_inherited_fd(1);
+               lxc_close_inherited_fd(2);
+
+               if (my_args.log_file) {
+                       open(my_args.log_file, O_WRONLY | O_CLOEXEC);
+                       open(my_args.log_file, O_RDONLY | O_CLOEXEC);
+                       open(my_args.log_file, O_RDONLY | O_CLOEXEC);
+               }
        }
 
-       if (tcsetattr(0, TCSAFLUSH, &tios))
-               ERROR("failed to restore terminal settings : %s",
-                     strerror(errno));
+       save_tty(&tios);
+
+       err = lxc_start(my_args.name, args, conf);
+
+       restore_tty(&tios);
 
        return err;
 }