1 #include <unistd.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include "strerr.h"
5 #include "error.h"
6 #include "open.h"
7 #include "fmt.h"
8 #include "tai.h"
9 #include "buffer.h"
10 #include "sgetopt.h"
11 #include "svpath.h"
12 #include "svstatus.h"
13 
14 #define FATAL "svstat: fatal: "
15 #define WARNING "svstat: warning: "
16 
17 char bspace[1024];
18 buffer b = BUFFER_INIT(buffer_unixwrite,1,bspace,sizeof bspace);
19 
20 char strnum[FMT_ULONG];
21 
22 int check_log = -1;
23 
die_nomem(void)24 static void die_nomem(void)
25 {
26   strerr_die2sys(111,FATAL,"unable to allocate memory");
27 }
28 
die_usage(void)29 static void die_usage(void)
30 {
31   strerr_die1x(100,"svstat: usage: svstat [-L] [-l] dir [dir ...]");
32 }
33 
showstatus(const char status[19],int r,int normallyup)34 static void showstatus(const char status[19], int r, int normallyup)
35 {
36   const char *x;
37   struct tai when;
38   struct tai now;
39   unsigned long pid;
40   unsigned char want;
41   unsigned char paused;
42   enum svstatus statusflag;
43 
44   pid = (unsigned char) status[15];
45   pid <<= 8; pid += (unsigned char) status[14];
46   pid <<= 8; pid += (unsigned char) status[13];
47   pid <<= 8; pid += (unsigned char) status[12];
48 
49   paused = status[16];
50   want = status[17];
51   statusflag = status[18];
52 
53   tai_unpack(status,&when);
54   tai_now(&now);
55   if (tai_less(&now,&when)) when = now;
56   tai_sub(&when,&now,&when);
57 
58   if (pid) {
59     buffer_puts(&b,"up (pid ");
60     buffer_put(&b,strnum,fmt_ulong(strnum,pid));
61     buffer_puts(&b,") ");
62   }
63   else
64     buffer_puts(&b,"down ");
65 
66   buffer_put(&b,strnum,fmt_ulong(strnum,tai_approx(&when)));
67   buffer_puts(&b," seconds");
68 
69   if (pid && !normallyup)
70     buffer_puts(&b,", normally down");
71   if (!pid && normallyup)
72     buffer_puts(&b,", normally up");
73   if (pid && paused)
74     buffer_puts(&b,", paused");
75   if (!pid && (want == 'u'))
76     buffer_puts(&b,", want up");
77   if (pid && (want == 'd'))
78     buffer_puts(&b,", want down");
79   if (r > 18) {
80     switch (statusflag) {
81     case svstatus_stopped: x = ", stopped"; break;
82     case svstatus_starting: x = ", starting"; break;
83     case svstatus_started: x = ", started"; break;
84     case svstatus_running: x = ", running"; break;
85     case svstatus_stopping: x = ", stopping"; break;
86     case svstatus_failed: x=", failed"; break;
87     default: x = ", status unknown";
88     }
89     if (pid && (want == '\000'))
90       buffer_puts(&b,", once");
91     if (x)
92       buffer_puts(&b,x);
93   }
94 }
95 
doit(const char * dir)96 void doit(const char *dir)
97 {
98   struct stat st;
99   int r;
100   int fd;
101   const char *x;
102   const char *fntemp;
103   char status[40];
104   unsigned char normallyup;
105 
106   buffer_puts(&b,dir);
107 
108   if (chdir(dir) == -1) {
109     x = error_str(errno);
110     buffer_puts(&b,": unable to chdir: ");
111     buffer_puts(&b,x);
112     return;
113   }
114   if (!svpath_init()) {
115     strerr_warn4sys(WARNING,"unable to set up control path for ",dir,"");
116     return;
117   }
118 
119   normallyup = 0;
120   if (stat("down",&st) == -1) {
121     if (errno != error_noent) {
122       x = error_str(errno);
123       buffer_puts(&b,": unable to stat down: ");
124       buffer_puts(&b,x);
125       return;
126     }
127     normallyup = 1;
128   }
129 
130   if ((fntemp = svpath_make("/ok")) == 0) die_nomem();
131   fd = open_write(fntemp);
132   if (fd == -1) {
133     if (errno == error_nodevice) {
134       buffer_puts(&b,": supervise not running");
135       return;
136     }
137     x = error_str(errno);
138     buffer_puts(&b,": unable to open ");
139     buffer_puts(&b,fntemp);
140     buffer_puts(&b,": ");
141     buffer_puts(&b,x);
142     return;
143   }
144   close(fd);
145 
146   if ((fntemp = svpath_make("/status")) == 0) die_nomem();
147   fd = open_read(fntemp);
148   if (fd == -1) {
149     x = error_str(errno);
150     buffer_puts(&b,": unable to open ");
151     buffer_puts(&b,fntemp);
152     buffer_puts(&b,": ");
153     buffer_puts(&b,x);
154     return;
155   }
156   r = buffer_unixread(fd,status,sizeof status);
157   close(fd);
158   if (r < 18) {
159     if (r == -1)
160       x = error_str(errno);
161     else
162       x = "bad format";
163     buffer_puts(&b,": unable to read ");
164     buffer_puts(&b,fntemp);
165     buffer_puts(&b,": ");
166     buffer_puts(&b,x);
167     return;
168   }
169   if (check_log != 1) {
170     buffer_puts(&b,": ");
171     showstatus(status,r,normallyup);
172   }
173   if (check_log != 0) {
174     if (r >= 20+18) {
175       if (check_log < 0) {
176 	buffer_puts(&b,"\n");
177 	buffer_puts(&b,dir);
178       }
179       buffer_puts(&b," log: ");
180       showstatus(status+20,r-20,normallyup);
181     }
182     else if (check_log == 1)
183       buffer_puts(&b,": no log service");
184   }
185 }
186 
main(int argc,const char * const * argv)187 int main(int argc,const char *const *argv)
188 {
189   int fdorigdir;
190   const char *dir;
191   int opt;
192 
193   while ((opt = getopt(argc,argv,"lL")) != opteof) {
194     switch (opt) {
195     case 'L':
196       check_log = 1;
197       break;
198     case 'l':
199       check_log = 0;
200       break;
201     default:
202       die_usage();
203     }
204   }
205   argv += optind;
206 
207   if (!argv[0])
208     die_usage();
209 
210   fdorigdir = open_read(".");
211   if (fdorigdir == -1)
212     strerr_die2sys(111,FATAL,"unable to open current directory");
213 
214   while ((dir = *argv++) != 0) {
215     doit(dir);
216     buffer_puts(&b,"\n");
217     if (fchdir(fdorigdir) == -1)
218       strerr_die2sys(111,FATAL,"unable to set directory");
219   }
220 
221   buffer_flush(&b);
222 
223   _exit(0);
224 }
225