031bae4b4d60129cf2a168871f197c118d27eb03
[util-vserver.git] / src / vwait.c
1 // $Id: vwait.c,v 1.1 2005/05/05 09:22:03 ensc Exp $    --*- c -*--
2
3 // Copyright (C) 2005 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 "lib/vserver.h"
24 #include "lib/internal.h"
25 #include "linuxvirtual.h"
26 #include "util.h"
27
28 #include <getopt.h>
29 #include <signal.h>
30 #include <time.h>
31 #include <errno.h>
32 #include <libgen.h>
33
34 #define ENSC_WRAPPERS_PREFIX    "vwait: "
35 #define ENSC_WRAPPERS_STDLIB    1
36 #define ENSC_WRAPPERS_UNISTD    1
37 #define ENSC_WRAPPERS_VSERVER   1
38 #include <wrappers.h>
39
40 #define CMD_HELP        0x8000
41 #define CMD_VERSION     0x8001
42
43 #define CMD_TIMEOUT     0x4000
44 #define CMD_TERMINATE   0x4001
45 #define CMD_STATUS_FD   0x4002
46
47 static struct option const
48 CMDLINE_OPTIONS[] = {
49   { "help",       no_argument,        0, CMD_HELP },
50   { "version",    no_argument,        0, CMD_VERSION },
51   { "timeout",    required_argument,  0, CMD_TIMEOUT },
52   { "terminate",  no_argument,        0, CMD_TERMINATE },
53   { "status-fd",  required_argument,  0, CMD_STATUS_FD },
54   { 0,0,0,0 }
55 };
56
57 int                     wrapper_exit_code = 1;
58 static sig_atomic_t     aborted = 0;
59
60 struct StatusType {
61     enum {stERROR, stFINISHED, stKILLED,
62           stTIMEOUT}                            status;
63     int                                         rc;
64 };
65
66 struct Arguments
67 {
68     xid_t               xid;
69     int                 timeout;
70     int                 status_fd;
71     bool                do_terminate;
72 };
73
74 static void
75 showHelp(char const *cmd)
76 {
77   VSERVER_DECLARE_CMD(cmd);
78
79   WRITE_MSG(1, "Usage:  ");
80   WRITE_STR(1, cmd);
81   WRITE_STR(1,
82             " [--timeout <timeout>] [--terminate] [--status-fd <fd>] [--] <xid>\n"
83             "\n"
84             "Please report bugs to " PACKAGE_BUGREPORT "\n");
85   exit(0);
86 }
87
88 static void
89 showVersion()
90 {
91   WRITE_MSG(1,
92             "vwait " VERSION " -- waits for a context to finish\n"
93             "This program is part of " PACKAGE_STRING "\n\n"
94             "Copyright (C) 2005 Enrico Scholz\n"
95             VERSION_COPYRIGHT_DISCLAIMER);
96   exit(0);
97 }
98
99 static void
100 handler(int UNUSED num)
101 {
102   aborted = 1;
103 }
104
105 static struct StatusType
106 doit(struct Arguments const *args)
107 {
108   time_t                        end_time = 0;
109   struct StatusType             res;
110   
111   if (args->timeout>0) {
112     end_time = time(0) + args->timeout;
113     signal(SIGALRM, handler);
114     alarm(args->timeout);
115   }
116
117   for (;;) {
118     res.rc = vc_wait_exit(args->xid);
119     
120     if      (res.rc==-1 && errno!=EAGAIN && errno!=EINTR) {
121       res.rc     = errno;
122       res.status = stERROR;
123       perror(ENSC_WRAPPERS_PREFIX "vc_wait_exit()");
124     }
125     else if (res.rc==-1 && args->timeout>0 && time(0)>=end_time) {
126       if (!args->do_terminate)
127         res.status = stTIMEOUT;
128       else {
129         vc_ctx_kill(args->xid, 1, 9);
130         vc_ctx_kill(args->xid, 0, 9);
131         res.status = stKILLED;
132       }
133     }
134     else if (res.rc==-1)
135       continue;         // signal
136     else
137       res.status = stFINISHED;
138
139     break;
140   }
141
142   alarm(0);
143   return res;
144 }
145
146 static void
147 writeStatus(int fd, char const *str, int const *rc, int exit_code)
148 {
149   if (fd==-1) exit(exit_code);
150
151   WRITE_STR(fd, str);
152   if (rc) {
153     char                buf[sizeof(*rc)*3 + 2];
154     size_t              len = utilvserver_fmt_long(buf, *rc);
155     WRITE_MSG(fd, " ");
156     Vwrite   (fd, buf, len);
157   }
158   WRITE_MSG(fd, "\n");
159   
160   exit(exit_code);
161 }
162
163 int main(int argc, char *argv[])
164 {
165   struct StatusType     res;
166   struct Arguments      args = {
167     .xid          = VC_NOCTX,
168     .timeout      = -1,
169     .status_fd    = -1,
170     .do_terminate = false,
171   };
172
173   while (1) {
174     int         c = getopt_long(argc, argv, "c:", CMDLINE_OPTIONS, 0);
175     if (c==-1) break;
176
177     switch (c) {
178       case CMD_HELP             :  showHelp(argv[0]);
179       case CMD_VERSION          :  showVersion();
180       case CMD_TERMINATE        :  args.do_terminate = true;         break;
181       case CMD_TIMEOUT          :  args.timeout      = atoi(optarg); break;
182       case CMD_STATUS_FD        :  args.status_fd    = atoi(optarg); break;
183       default           :
184         WRITE_MSG(2, "Try '");
185         WRITE_STR(2, argv[0]);
186         WRITE_MSG(2, " --help\" for more information.\n");
187         return EXIT_FAILURE;
188         break;
189     }
190   }
191
192   if (optind+1 > argc) {
193     WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "no context specified; try '--help' for more information\n");
194     exit(wrapper_exit_code);
195   }
196
197   if (optind+1 < argc) {
198     WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "can not wait for more than one context; try '--help' for more information\n");
199     exit(wrapper_exit_code);
200   }
201   
202   args.xid = Evc_xidopt2xid(argv[optind], true);
203
204   if (args.xid==VC_NOCTX) {
205     WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "invalid context specified; try '--help' for more information\n");
206     exit(wrapper_exit_code);
207   }
208
209   res = doit(&args);
210
211   switch (res.status) {
212     case stERROR        :  writeStatus(args.status_fd, "ERROR",    &res.rc, 127);
213     case stFINISHED     :  writeStatus(args.status_fd, "FINISHED", &res.rc,   0);
214     case stKILLED       :  writeStatus(args.status_fd, "KILLED",         0,   1);
215     case stTIMEOUT      :  writeStatus(args.status_fd, "TIMEOUT",        0,   2);
216     default             :  writeStatus(args.status_fd, "???",      &res.rc, 126);
217   }
218 }