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