vwait.c (5988B)
1 // $Id$ --*- 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 "util.h" 26 27 #include <getopt.h> 28 #include <signal.h> 29 #include <time.h> 30 #include <errno.h> 31 #include <libgen.h> 32 #include <assert.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, now = 0; 109 struct StatusType res; 110 111 if (args->timeout>0) { 112 end_time = time(0) + args->timeout; 113 siginterrupt(SIGALRM, 1); 114 signal(SIGALRM, handler); 115 alarm(args->timeout); 116 } 117 118 for (;;) { 119 res.rc = vc_wait_exit(args->xid); 120 121 if (res.rc==-1 && errno!=EAGAIN && errno!=EINTR) { 122 // the error-case 123 res.rc = errno; 124 res.status = stERROR; 125 perror(ENSC_WRAPPERS_PREFIX "vc_wait_exit()"); 126 } 127 else if (res.rc==-1 && args->timeout>0 && (now=time(0))>=end_time) { 128 // an EINTR or EAGAIN signal was delivered, a timeout was set and 129 // reached 130 if (!args->do_terminate) 131 res.status = stTIMEOUT; 132 else { 133 vc_ctx_kill(args->xid, 1, 9); 134 vc_ctx_kill(args->xid, 0, 9); 135 res.status = stKILLED; 136 } 137 } 138 else if (res.rc==-1) { 139 // an EINTR or EAGAIN signal was delivered but the timeout not set or 140 // not reached yet 141 142 // we are here, when args->timeout==0 or 'now' was initialized (and 143 // compared with 'end_time'). So, 'now' can be used below. 144 assert(args->timeout<=0 || (now < end_time)); 145 146 if (args->timeout>0) // (re)set the alarm-clock 147 alarm(end_time-now); 148 149 continue; 150 } 151 else 152 // vc_wait_exit(2) finished successfully 153 res.status = stFINISHED; 154 155 break; 156 } 157 158 alarm(0); 159 return res; 160 } 161 162 static void 163 writeStatus(int fd, char const *str, int const *rc, int exit_code) 164 { 165 if (fd==-1) exit(exit_code); 166 167 WRITE_STR(fd, str); 168 if (rc) { 169 char buf[sizeof(*rc)*3 + 2]; 170 size_t len = utilvserver_fmt_long(buf, *rc); 171 WRITE_MSG(fd, " "); 172 Vwrite (fd, buf, len); 173 } 174 WRITE_MSG(fd, "\n"); 175 176 exit(exit_code); 177 } 178 179 int main(int argc, char *argv[]) 180 { 181 struct StatusType res; 182 struct Arguments args = { 183 .xid = VC_NOCTX, 184 .timeout = -1, 185 .status_fd = -1, 186 .do_terminate = false, 187 }; 188 189 while (1) { 190 int c = getopt_long(argc, argv, "c:", CMDLINE_OPTIONS, 0); 191 if (c==-1) break; 192 193 switch (c) { 194 case CMD_HELP : showHelp(argv[0]); 195 case CMD_VERSION : showVersion(); 196 case CMD_TERMINATE : args.do_terminate = true; break; 197 case CMD_TIMEOUT : args.timeout = atoi(optarg); break; 198 case CMD_STATUS_FD : args.status_fd = atoi(optarg); break; 199 default : 200 WRITE_MSG(2, "Try '"); 201 WRITE_STR(2, argv[0]); 202 WRITE_MSG(2, " --help' for more information.\n"); 203 return EXIT_FAILURE; 204 break; 205 } 206 } 207 208 if (optind+1 > argc) { 209 WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "no context specified; try '--help' for more information\n"); 210 exit(wrapper_exit_code); 211 } 212 213 if (optind+1 < argc) { 214 WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "can not wait for more than one context; try '--help' for more information\n"); 215 exit(wrapper_exit_code); 216 } 217 218 args.xid = Evc_xidopt2xid(argv[optind], true); 219 220 if (args.xid==VC_NOCTX) { 221 WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "invalid context specified; try '--help' for more information\n"); 222 exit(wrapper_exit_code); 223 } 224 225 res = doit(&args); 226 227 switch (res.status) { 228 case stERROR : writeStatus(args.status_fd, "ERROR", &res.rc, 127); 229 case stFINISHED : writeStatus(args.status_fd, "FINISHED", &res.rc, 0); 230 case stKILLED : writeStatus(args.status_fd, "KILLED", 0, 1); 231 case stTIMEOUT : writeStatus(args.status_fd, "TIMEOUT", 0, 2); 232 default : writeStatus(args.status_fd, "???", &res.rc, 126); 233 } 234 }