util-vserver-0.30.208
[util-vserver.git] / vserver-start / main.c
diff --git a/vserver-start/main.c b/vserver-start/main.c
new file mode 100644 (file)
index 0000000..ab7c0fb
--- /dev/null
@@ -0,0 +1,200 @@
+// $Id: main.c,v 1.5 2005/03/19 02:07:40 ensc Exp $    --*- c -*--
+
+// Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//  
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//  
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "vserver-start.h"
+#include "vshelper.h"
+#include "pathconfig.h"
+#include "interface.h"
+#include "configuration.h"
+#include "mount.h"
+#include "undo.h"
+
+#include "lib_internal/util.h"
+#include "lib_internal/errinfo.h"
+#include "lib_internal/sys_clone.h"
+#include "lib/vserver.h"
+#include "lib/internal.h"
+
+#include <sys/file.h>
+#include <sched.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#define ENSC_WRAPPERS_VSERVER  1
+#define ENSC_WRAPPERS_SOCKET   1
+#define ENSC_WRAPPERS_UNISTD   1
+#define ENSC_WRAPPERS_FCNTL    1
+#define ENSC_WRAPPERS_STDLIB   1
+#include <ensc_wrappers/wrappers.h>
+
+struct Options                 opts;
+struct Configuration           cfg;
+int                            wrapper_exit_code;
+
+static void
+env2Str(char const **var, char const *env, bool req)
+{
+  char const *         tmp = getenv(env);
+  if (req && tmp==0) {
+    WRITE_MSG(2, "vserver.start: required environment variable $");
+    WRITE_STR(2, env);
+    WRITE_STR(2, " not set; aborting...\n");
+    exit(1);
+  }
+
+  *var = tmp;
+  unsetenv(env);
+}
+
+static void
+env2Bool(bool *var, char const *env, bool req)
+{
+  char const * tmp;
+  env2Str(&tmp, env, req);
+  *var = !(tmp==0 || atoi(tmp)==0);
+}
+
+static void
+initGlobals()
+{
+  env2Str (&opts.VSERVER_DIR,       "VSERVER_DIR",       true);
+  env2Str (&opts.VSERVER_NAME,      "VSERVER_NAME",      true);
+  env2Bool(&opts.OPTION_DEBUG,      "OPTION_DEBUG",      false);
+  env2Bool(&opts.OPTION_DEFAULTTTY, "OPTION_DEFAULTTTY", false);  
+}
+
+static void
+initLock()
+{
+  size_t                       l   = strlen(opts.VSERVER_DIR);
+  char                                 tmp[sizeof(LOCKDIR "/vserver..startup") + l];
+  char *                       ptr = tmp;
+  struct ErrorInformation      err = { .app = 0 };
+  int                          fd;
+
+  ptr  = Xmemcpy(ptr, LOCKDIR "/vserver.", sizeof(LOCKDIR "/vserver.")-1);
+  ((char *)(Xmemcpy(ptr, opts.VSERVER_DIR, l)))[0] = '\0';
+  ptr += canonifyVserverName(ptr);
+  ptr  = Xmemcpy(ptr, ".startup",  sizeof(".startup"));
+  *ptr = '\0';
+
+  if (!lockfile(&fd, tmp, LOCK_EX, 30, &err)) {
+    WRITE_MSG(2, "vserver.start: failed to lock '");
+    WRITE_STR(2, tmp);
+    WRITE_MSG(2, "': ");
+    ErrInfo_writeErrno(&err);
+    exit(1);
+  }
+}
+
+static void
+checkConstraints()
+{
+  xid_t                        xid;
+  bool                 is_running;
+  struct vc_vx_info    info;
+
+  xid = vc_getVserverCtx(opts.VSERVER_DIR, vcCFG_RECENT_FULL,
+                        true, &is_running);
+
+  if (xid!=VC_NOCTX && vc_get_vx_info(xid, &info)!=-1) {
+    WRITE_MSG(2, "vserver.start: vserver '");
+    WRITE_STR(2, opts.VSERVER_NAME);
+    WRITE_MSG(2, "' already running; aborting...\n");
+    exit(1);
+  }
+
+  Vshelper_doSanityCheck();
+}
+
+static void
+setCFlag(xid_t xid, uint_least64_t value)
+{
+  struct vc_ctx_flags  flags = {
+    .flagword = value,
+    .mask     = value
+  };
+
+  Evc_set_cflags(xid, &flags);
+}
+
+int main(int UNUSED argc, char UNUSED *argv[])
+{
+  Cfg_init(&cfg);
+  
+  initGlobals();
+  initLock();
+  checkConstraints();
+
+  int          sync_fd[2];
+  char         c;
+  xid_t                xid;
+  char         buf[sizeof(xid)*3 + 2];
+  PathInfo     cfgdir = { .d = opts.VSERVER_DIR, .l = strlen(opts.VSERVER_DIR) };
+
+  Esocketpair(AF_UNIX, SOCK_STREAM, 0, sync_fd);
+  Efcntl(sync_fd[0], F_SETFD, FD_CLOEXEC);
+  Efcntl(sync_fd[1], F_SETFD, FD_CLOEXEC);
+  
+  getConfiguration(&cfg, &cfgdir);
+  pid_t                pid    = sys_clone(CLONE_NEWNS|SIGCHLD, 0);
+  FatalErrnoError(pid==-1, "sys_clone()");
+  
+  switch (pid) {
+    case 0     :
+      Undo_init();
+      execScriptlets(&cfgdir, opts.VSERVER_NAME, "prepre-start");
+      activateInterfaces(&cfg.interfaces);
+      
+      xid = Evc_ctx_create(cfg.xid);
+      setCFlag(xid, VC_VXF_INFO_NAMESPACE);
+      
+      mountVserver(&cfg);
+       //      prepareInit(&cfg, &cfgdir);
+
+      Esend(sync_fd[0], &xid, sizeof xid, MSG_NOSIGNAL);
+       // 'pre-start.parent' will be executed now in the parent-context
+      Erecv(sync_fd[0], &c, 1, 0);
+      execScriptlets(&cfgdir, opts.VSERVER_NAME, "pre-start");
+
+      if (cfg.nice)
+       Enice(atoi(cfg.nice));
+      if (opts.OPTION_DEFAULTTTY)
+       setDefaultTTY(&cfgdir, 0);
+
+      
+
+      Undo_detach();
+      break;
+
+    default    :
+      Erecv(sync_fd[1], &xid, sizeof xid, 0);
+      utilvserver_fmt_uint(buf, xid);
+      Esetenv("CHILD_XID", buf, 1);
+      
+      execScriptlets(&cfgdir, opts.VSERVER_NAME, "pre-start.parent");
+      Esend(sync_fd[1], ".", 1, MSG_NOSIGNAL);
+      
+      break;
+  }
+}