1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <unistd.h>
4 #include "strerr.h"
5 #include "error.h"
6 #include "sgetopt.h"
7 #include "open.h"
8 #include "buffer.h"
9 #include "tai.h"
10 #include "fmt.h"
11 
12 #define USAGE " [ -l ] service ..."
13 
14 
15 #define FATAL "runsvstat: fatal: "
16 #define WARNING "runsvstat: warning: "
17 
18 const char *progname;
19 unsigned int rc =0;
20 struct stat s;
21 int showlog =0;
22 
usage()23 void usage() { strerr_die4x(1, "usage: ", progname, USAGE, "\n"); }
24 
fatal(char * m1)25 void fatal(char *m1) { strerr_die3sys(111, FATAL, m1, ": "); }
warn(char * m1,char * m2)26 void warn(char *m1, char *m2) {
27   rc++;
28   strerr_warn5(WARNING, m1, ": ", m2, ": ", &strerr_sys);
29 }
warnx(char * m1,char * m2)30 void warnx(char *m1, char *m2) {
31   rc++;
32   strerr_warn4(WARNING, m1, ": ", m2, 0);
33 }
34 
show_status(char * name)35 int show_status(char *name) {
36   char status[20];
37   int pid;
38   int fd;
39   int normallyup =0;
40   char sulong[FMT_ULONG];
41   struct tai when;
42   struct tai now;
43 
44   if (stat("down", &s) == -1) {
45     if (errno != error_noent) {
46       warn(name, "unable to stat down");
47       return(-1);
48     }
49     normallyup = 1;
50   }
51   if ((fd =open_write("supervise/ok")) == -1) {
52     if (errno == error_nodevice)
53       warnx(name, "runsv not running.");
54     else
55       warn(name, "unable to open supervise/ok");
56     return(-1);
57   }
58   close(fd);
59   if ((fd =open_read("supervise/status")) == -1) {
60     warn(name, "unable to open supervise/status");
61     return(-1);
62   }
63   switch(read(fd, status, 20)) {
64   case 20: break;
65   case -1:
66     warn(name, "unable to read supervise/status");
67     return(-1);
68   default:
69     warnx(name, "unable to read supervise/status: bad format.");
70     return(-1);
71   }
72   pid =(unsigned char) status[15];
73   pid <<=8; pid +=(unsigned char)status[14];
74   pid <<=8; pid +=(unsigned char)status[13];
75   pid <<=8; pid +=(unsigned char)status[12];
76 
77   tai_unpack(status,&when);
78   tai_now(&now);
79   if (tai_less(&now,&when)) when =now;
80   tai_sub(&when,&now,&when);
81 
82   buffer_puts(buffer_1, name);
83   buffer_puts(buffer_1, ": ");
84   if (pid) {
85     switch (status[19]) {
86     case 1: buffer_puts(buffer_1, "run "); break;
87     case 2: buffer_puts(buffer_1, "finish "); break;
88     }
89     buffer_puts(buffer_1, "(pid ");
90     buffer_put(buffer_1, sulong, fmt_ulong(sulong, pid));
91     buffer_puts(buffer_1, ") ");
92   }
93   else
94     buffer_puts(buffer_1, "down ");
95   buffer_put(buffer_1, sulong, fmt_ulong(sulong, tai_approx(&when)));
96   buffer_puts(buffer_1, " seconds");
97   if (pid && !normallyup) buffer_puts(buffer_1,", normally down");
98   if (!pid && normallyup) buffer_puts(buffer_1,", normally up");
99   if (pid && status[16]) buffer_puts(buffer_1,", paused");
100   if (!pid && (status[17] == 'u')) buffer_puts(buffer_1,", want up");
101   if (pid && (status[17] == 'd')) buffer_puts(buffer_1,", want down");
102   if (pid && status[18]) buffer_puts(buffer_1, ", got TERM");
103   /* buffer_putsflush(buffer_1, "\n"); */
104   return(1);
105 }
106 
main(int argc,char ** argv)107 int main(int argc, char **argv) {
108   int opt;
109   int curdir;
110   char **dir;
111 
112   progname =*argv;
113 
114   while ((opt =getopt(argc, (const char * const *)argv, "l")) != opteof) {
115     switch(opt) {
116     case 'l':
117       showlog =1;
118       break;
119     case '?':
120       usage();
121     }
122   }
123   argv +=optind;
124 
125   dir =argv;
126   if (! dir || ! *dir) usage();
127 
128   if ((curdir =open_read(".")) == -1) {
129     rc =100;
130     fatal("unable to open current directory");
131   }
132   for (; dir && *dir; dir++) {
133     if (chdir(*dir) == -1) {
134       warn(*dir, "unable to change directory");
135       continue;
136     }
137     if (show_status(*dir) == 1) {
138       if (showlog) {
139         if (stat("log", &s) == -1) {
140           if (errno != error_noent)
141             warn("unable to stat()", "./log");
142         }
143         else {
144           if (! S_ISDIR(s.st_mode))
145             warnx("./log", "not a directory.");
146           else {
147             if (chdir("log") == -1) {
148               warn(*dir, "unable to change directory");
149               continue;
150             }
151             show_status("\n  log");
152           }
153         }
154       }
155       buffer_puts(buffer_1, "\n"); buffer_flush(buffer_1);
156     }
157     if (fchdir(curdir) == -1) {
158       rc =100;
159       fatal("unable to change directory");
160     }
161   }
162   if (rc > 100) rc =100;
163   _exit(rc);
164 }
165