1 #include <unistd.h>
2 #include "strerr.h"
3 #include "error.h"
4 #include "sgetopt.h"
5 #include "scan.h"
6 #include "open.h"
7 #include "tai.h"
8 #include "buffer.h"
9 
10 #define FATAL "svwaitdown: fatal: "
11 #define WARN "svwaitdown: warning: "
12 #define INFO "svwaitdown: "
13 #define USAGE " [-v] [-t 1..6000] service ..."
14 
15 
16 const char *progname;
17 const char * const *dir;
18 unsigned int rc =0;
19 
fatal(const char * m)20 void fatal(const char *m) { strerr_die3sys(111, FATAL, m, ": "); }
warn(const char * s1,const char * s2,struct strerr * e)21 void warn(const char *s1, const char *s2, struct strerr *e) {
22   dir++; rc++;
23   strerr_warn3(WARN, s1, s2, e);
24 }
usage()25 void usage() { strerr_die4x(1, "usage: ", progname, USAGE, "\n"); }
26 
main(int argc,const char * const * argv)27 int main(int argc, const char * const *argv) {
28   int opt;
29   unsigned long sec =600;
30   int verbose =0;
31   int doexit =0;
32   int dokill =0;
33   int wdir;
34   int fd;
35   char status[20];
36   int r;
37   unsigned long pid;
38   struct tai start;
39   struct tai now;
40 
41   progname =*argv;
42 
43   while ((opt =getopt(argc, argv, "t:xkv")) != opteof) {
44     switch(opt) {
45     case 't':
46       scan_ulong(optarg, &sec);
47       if ((sec < 1) || (sec > 6000)) usage();
48       break;
49     case 'x':
50       doexit =1;
51       break;
52     case 'k':
53       dokill =1;
54       break;
55     case 'v':
56       verbose =1;
57       break;
58     case '?':
59       usage();
60     }
61   }
62   argv +=optind;
63   if (! argv || ! *argv) usage();
64 
65   if ((wdir =open_read(".")) == -1)
66     fatal("unable to open current working directory");
67 
68   for (dir =argv; *dir; ++dir) {
69     if (dir != argv)
70       if (fchdir(wdir) == -1) fatal("unable to switch to starting directory");
71     if (chdir(*dir) == -1) continue; /* bummer */
72     if ((fd =open_write("supervise/control")) == -1) continue; /* bummer */
73     if (write(fd, "dx", 1 +doexit) != (1 +doexit)) {
74       close(fd); continue; /* bummer */
75     }
76     close(fd);
77   }
78   dir =argv;
79 
80   tai_now(&start);
81   while (*dir) {
82     if (fchdir(wdir) == -1) fatal("unable to switch to starting directory");
83     if (chdir(*dir) == -1) {
84       warn(*dir, ": unable to change directory: ", &strerr_sys);
85       continue;
86     }
87     if ((fd =open_write("supervise/ok")) == -1) {
88       if (errno == error_nodevice) {
89         if (verbose) strerr_warn3(INFO, *dir, ": runsv not running.", 0);
90         dir++;
91       }
92       else
93         warn(*dir, ": unable to open supervise/ok: ", &strerr_sys);
94       continue;
95     }
96     close(fd);
97 
98     if ((fd =open_read("supervise/status")) == -1) {
99       warn(*dir, "unable to open supervise/status: ", &strerr_sys);
100       continue;
101     }
102     r =buffer_unixread(fd, status, 20);
103     close(fd);
104     if ((r < 18) || (r == 19)) { /* supervise compatibility */
105       if (r == -1)
106         warn(*dir, "unable to read supervise/status: ", &strerr_sys);
107       else
108         warn(*dir, ": unable to read supervise/status: bad format.", 0);
109       continue;
110     }
111     pid =(unsigned char)status[15];
112     pid <<=8; pid +=(unsigned char)status[14];
113     pid <<=8; pid +=(unsigned char)status[13];
114     pid <<=8; pid +=(unsigned char)status[12];
115 
116     if (! doexit && ! pid) {
117       /* ok, service is down */
118       if (verbose) strerr_warn3(INFO, *dir, ": down.", 0);
119       dir++;
120       continue;
121     }
122 
123     if (status[17] != 'd') { /* catch previous failures */
124       if ((fd =open_write("supervise/control")) == -1) {
125         warn(*dir, ": unable to open supervise/control: ", &strerr_sys);
126         continue;
127       }
128       if (write(fd, "dx", 1 +doexit) != (1 +doexit)) {
129         warn(*dir, ": unable to write to supervise/control: ", &strerr_sys);
130         close(fd);
131         continue;
132       }
133       close(fd);
134     }
135 
136     tai_now(&now);
137     tai_sub(&now, &now, &start);
138     if (tai_approx(&now) >= sec) {
139       /* timeout */
140       if (verbose) strerr_warn2(INFO, "timeout.", 0);
141       if (dokill) {
142         if (chdir(*dir) == -1) {
143           warn(*dir, ": unable to change directory: ", &strerr_sys);
144           continue;
145         }
146         if ((fd =open_write("supervise/control")) == -1) {
147           if (errno == error_nodevice) {
148             if (verbose)
149               strerr_warn3(INFO, *dir, ": runsv not running.", 0);
150             dir++;
151           }
152           else
153             warn(*argv, ": unable to open supervise/control: ", &strerr_sys);
154           continue;
155         }
156         if (write(fd, "k", 1) != 1)
157           warn(*argv, ": unable to write to supervise/control: ", &strerr_sys);
158         else
159           strerr_warn3(INFO, *dir, ": killed.", 0);
160         close(fd);
161         dir++;
162         if (! *dir) _exit(111);
163         continue;
164       }
165       _exit(111);
166     }
167     sleep(1);
168   }
169   if (fchdir(wdir) == -1)
170     strerr_warn2(WARN, "unable to switch to starting directory: ", &strerr_sys);
171   close(wdir);
172   if (rc > 100) rc =100;
173   _exit(rc);
174 }
175