+// $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;
+ }
+}