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