6da6b2744f3601e068dbfd7d29b8e8ddb9f279e1
[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_UNISTD    1
45 #define ENSC_WRAPPERS_FCNTL     1
46 #define ENSC_WRAPPERS_STDLIB    1
47 #include <ensc_wrappers/wrappers.h>
48
49 struct Options                  opts;
50 struct Configuration            cfg;
51 int                             wrapper_exit_code;
52
53 static void
54 env2Str(char const **var, char const *env, bool req)
55 {
56   char const *          tmp = getenv(env);
57   if (req && tmp==0) {
58     WRITE_MSG(2, "vserver.start: required environment variable $");
59     WRITE_STR(2, env);
60     WRITE_STR(2, " not set; aborting...\n");
61     exit(1);
62   }
63
64   *var = tmp;
65   unsetenv(env);
66 }
67
68 static void
69 env2Bool(bool *var, char const *env, bool req)
70 {
71   char const *  tmp;
72   env2Str(&tmp, env, req);
73   *var = !(tmp==0 || atoi(tmp)==0);
74 }
75
76 static void
77 initGlobals()
78 {
79   env2Str (&opts.VSERVER_DIR,       "VSERVER_DIR",       true);
80   env2Str (&opts.VSERVER_NAME,      "VSERVER_NAME",      true);
81   env2Bool(&opts.OPTION_DEBUG,      "OPTION_DEBUG",      false);
82   env2Bool(&opts.OPTION_DEFAULTTTY, "OPTION_DEFAULTTTY", false);  
83 }
84
85 static void
86 initLock()
87 {
88   size_t                        l   = strlen(opts.VSERVER_DIR);
89   char                          tmp[sizeof(LOCKDIR "/vserver..startup") + l];
90   char *                        ptr = tmp;
91   struct ErrorInformation       err = { .app = 0 };
92   int                           fd;
93
94   ptr  = Xmemcpy(ptr, LOCKDIR "/vserver.", sizeof(LOCKDIR "/vserver.")-1);
95   ((char *)(Xmemcpy(ptr, opts.VSERVER_DIR, l)))[0] = '\0';
96   ptr += canonifyVserverName(ptr);
97   ptr  = Xmemcpy(ptr, ".startup",  sizeof(".startup"));
98   *ptr = '\0';
99
100   if (!lockfile(&fd, tmp, LOCK_EX, 30, &err)) {
101     WRITE_MSG(2, "vserver.start: failed to lock '");
102     WRITE_STR(2, tmp);
103     WRITE_MSG(2, "': ");
104     ErrInfo_writeErrno(&err);
105     exit(1);
106   }
107 }
108
109 static void
110 checkConstraints()
111 {
112   xid_t                 xid;
113   bool                  is_running;
114   struct vc_vx_info     info;
115
116   xid = vc_getVserverCtx(opts.VSERVER_DIR, vcCFG_RECENT_FULL,
117                          true, &is_running);
118
119   if (xid!=VC_NOCTX && vc_get_vx_info(xid, &info)!=-1) {
120     WRITE_MSG(2, "vserver.start: vserver '");
121     WRITE_STR(2, opts.VSERVER_NAME);
122     WRITE_MSG(2, "' already running; aborting...\n");
123     exit(1);
124   }
125
126   Vshelper_doSanityCheck();
127 }
128
129 static void
130 setCFlag(xid_t xid, uint_least64_t value)
131 {
132   struct vc_ctx_flags   flags = {
133     .flagword = value,
134     .mask     = value
135   };
136
137   Evc_set_cflags(xid, &flags);
138 }
139
140 int main(int argc, char *argv[])
141 {
142   Cfg_init(&cfg);
143   
144   initGlobals();
145   initLock();
146   checkConstraints();
147
148   int           sync_fd[2];
149   char          c;
150   xid_t         xid;
151   char          buf[sizeof(xid)*3 + 2];
152   PathInfo      cfgdir = { .d = opts.VSERVER_DIR, .l = strlen(opts.VSERVER_DIR) };
153
154   Esocketpair(AF_UNIX, SOCK_STREAM, 0, sync_fd);
155   Efcntl(sync_fd[0], F_SETFD, FD_CLOEXEC);
156   Efcntl(sync_fd[1], F_SETFD, FD_CLOEXEC);
157   
158   getConfiguration(&cfg, &cfgdir);
159   pid_t         pid    = sys_clone(CLONE_NEWNS|SIGCHLD, 0);
160   FatalErrnoError(pid==-1, "sys_clone()");
161   
162   switch (pid) {
163     case 0      :
164       Undo_init();
165       execScriptlets(&cfgdir, opts.VSERVER_NAME, "prepre-start");
166       activateInterfaces(&cfg.interfaces);
167       
168       xid = Evc_ctx_create(cfg.xid);
169       setCFlag(xid, VC_VXF_INFO_NAMESPACE);
170       
171       mountVserver(&cfg);
172         //      prepareInit(&cfg, &cfgdir);
173
174       Esend(sync_fd[0], &xid, sizeof xid, MSG_NOSIGNAL);
175         // 'pre-start.parent' will be executed now in the parent-context
176       Erecv(sync_fd[0], &c, 1, 0);
177       execScriptlets(&cfgdir, opts.VSERVER_NAME, "pre-start");
178
179       if (cfg.nice)
180         Enice(atoi(cfg.nice));
181       if (opts.OPTION_DEFAULTTTY)
182         setDefaultTTY(&cfgdir, 0);
183
184       
185
186       Undo_detach();
187       break;
188
189     default     :
190       Erecv(sync_fd[1], &xid, sizeof xid, 0);
191       utilvserver_fmt_uint(buf, xid);
192       Esetenv("CHILD_XID", buf, 1);
193       
194       execScriptlets(&cfgdir, opts.VSERVER_NAME, "pre-start.parent");
195       Esend(sync_fd[1], ".", 1, MSG_NOSIGNAL);
196       
197       break;
198   }
199 }