added lots of new code
[util-vserver.git] / util-vserver / vserver-start / main.c
1 // $Id$    --*- c -*--
2
3 // Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 //  
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; version 2 of the License.
8 //  
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //  
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18
19 #ifdef HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22
23 #include "vserver-start.h"
24 #include "vshelper.h"
25 #include "pathconfig.h"
26 #include "interface.h"
27 #include "configuration.h"
28 #include "mount.h"
29 #include "undo.h"
30
31 #include "lib_internal/util.h"
32 #include "lib_internal/errinfo.h"
33 #include "lib_internal/sys_clone.h"
34 #include "lib/vserver.h"
35 #include "lib/internal.h"
36
37 #include <sys/file.h>
38 #include <sched.h>
39 #include <signal.h>
40 #include <sys/socket.h>
41
42 #define ENSC_WRAPPERS_VSERVER   1
43 #define ENSC_WRAPPERS_SOCKET    1
44 #define ENSC_WRAPPERS_FCNTL     1
45 #define ENSC_WRAPPERS_STDLIB    1
46 #include <ensc_wrappers/wrappers.h>
47
48 struct Options                  opts;
49 struct Configuration            cfg;
50 int                             wrapper_exit_code;
51
52 static void
53 env2Str(char const **var, char const *env, bool req)
54 {
55   char const *          tmp = getenv(env);
56   if (req && tmp==0) {
57     WRITE_MSG(2, "vserver.start: required environment variable $");
58     WRITE_STR(2, env);
59     WRITE_STR(2, " not set; aborting...\n");
60     exit(1);
61   }
62
63   *var = tmp;
64   unsetenv(env);
65 }
66
67 static void
68 env2Bool(bool *var, char const *env, bool req)
69 {
70   char const *  tmp;
71   env2Str(&tmp, env, req);
72   *var = !(tmp==0 || atoi(tmp)==0);
73 }
74
75 static void
76 initGlobals()
77 {
78   env2Str (&opts.VSERVER_DIR,       "VSERVER_DIR",       true);
79   env2Str (&opts.VSERVER_NAME,      "VSERVER_NAME",      true);
80   env2Bool(&opts.OPTION_DEBUG,      "OPTION_DEBUG",      false);
81   env2Bool(&opts.OPTION_DEFAULTTTY, "OPTION_DEFAULTTTY", false);  
82 }
83
84 static void
85 initLock()
86 {
87   size_t                        l   = strlen(opts.VSERVER_DIR);
88   char                          tmp[sizeof(LOCKDIR "/vserver..startup") + l];
89   char *                        ptr = tmp;
90   struct ErrorInformation       err = { .app = 0 };
91   int                           fd;
92
93   ptr  = Xmemcpy(ptr, LOCKDIR "/vserver.", sizeof(LOCKDIR "/vserver.")-1);
94   ((char *)(Xmemcpy(ptr, opts.VSERVER_DIR, l)))[0] = '\0';
95   ptr += canonifyVserverName(ptr);
96   ptr  = Xmemcpy(ptr, ".startup",  sizeof(".startup"));
97   *ptr = '\0';
98
99   if (!lockfile(&fd, tmp, LOCK_EX, 30, &err)) {
100     WRITE_MSG(2, "vserver.start: failed to lock '");
101     WRITE_STR(2, tmp);
102     WRITE_MSG(2, "': ");
103     ErrInfo_writeErrno(&err);
104     exit(1);
105   }
106 }
107
108 static void
109 checkConstraints()
110 {
111   xid_t                 xid;
112   bool                  is_running;
113   struct vc_vx_info     info;
114
115   xid = vc_getVserverCtx(opts.VSERVER_DIR, vcCFG_RECENT_FULL,
116                          true, &is_running);
117
118   if (xid!=VC_NOCTX && vc_get_vx_info(xid, &info)!=-1) {
119     WRITE_MSG(2, "vserver.start: vserver '");
120     WRITE_STR(2, opts.VSERVER_NAME);
121     WRITE_MSG(2, "' already running; aborting...\n");
122     exit(1);
123   }
124
125   Vshelper_doSanityCheck();
126 }
127
128 int main(int argc, char *argv[])
129 {
130   Cfg_init(&cfg);
131   
132   initGlobals();
133   initLock();
134   checkConstraints();
135
136   int           sync_fd[2];
137   char          c;
138   xid_t         xid;
139   char          buf[sizeof(xid)*3 + 2];
140   PathInfo      cfgdir = { .d = opts.VSERVER_DIR, .l = strlen(opts.VSERVER_DIR) };
141
142   Esocketpair(AF_UNIX, SOCK_STREAM, 0, sync_fd);
143   Efcntl(sync_fd[0], F_SETFD, FD_CLOEXEC);
144   Efcntl(sync_fd[1], F_SETFD, FD_CLOEXEC);
145   
146   getConfiguration(&cfg, &cfgdir);
147   pid_t         pid    = sys_clone(CLONE_NEWNS|SIGCHLD, 0);
148   FatalErrnoError(pid==-1, "sys_clone()");
149   
150   switch (pid) {
151     case 0      :
152       Undo_init();
153       execScriptlets(&cfgdir, opts.VSERVER_NAME, "prepre-start");
154       activateInterfaces();
155       
156       xid = Evc_ctx_create(cfg.xid);
157       mountVserver(&cfg);
158         //      prepareInit(&cfg, &cfgdir);
159
160       Esend(sync_fd[0], &xid, sizeof xid, MSG_NOSIGNAL);
161       Erecv(sync_fd[0], &c, 1, 0);
162       execScriptlets(&cfgdir, opts.VSERVER_NAME, "pre-start");
163
164       Undo_detach();
165       break;
166
167     default     :
168       Erecv(sync_fd[1], &xid, sizeof xid, 0);
169       utilvserver_fmt_uint(buf, xid);
170       Esetenv("CHILD_XID", buf, 1);
171       
172       execScriptlets(&cfgdir, opts.VSERVER_NAME, "pre-start.parent");
173       Esend(sync_fd[1], ".", 1, MSG_NOSIGNAL);
174       
175       break;
176   }
177 }