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