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