pretty-svstat

Pretty Printer for runit-services
Log | Files | Refs | README | LICENSE

psvstat.c (3642B)


      1 #include <fcntl.h>
      2 #include <limits.h>
      3 #include <stdint.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 #include <time.h>
      8 #include <unistd.h>
      9 
     10 struct service_serial {
     11 	uint8_t status_change[8];
     12 	uint8_t status_change_ms[4];
     13 	uint8_t pid[4];
     14 	uint8_t paused;
     15 	uint8_t wantsup;
     16 	uint8_t terminated;
     17 	uint8_t state;
     18 };
     19 
     20 void printstatus(const char* path, struct service_serial* buffer) {
     21 	const char* name;
     22 	if ((name = strrchr(path, '/'))) {
     23 		if (!strcmp(name, "/log")) {
     24 			while (--name > path) {
     25 				if (*name == '/')
     26 					break;
     27 			}
     28 			name++;
     29 		} else {
     30 			name++;
     31 		}
     32 	} else
     33 		name = path;
     34 
     35 	char* home   = getenv("HOME");
     36 	int   isuser = home != NULL && strncmp(home, path, strlen(home)) == 0;
     37 
     38 	if (isuser) {
     39 		printf("user  ");
     40 	} else {
     41 		printf("sys   ");
     42 	}
     43 
     44 	printf("%-20s ", name);
     45 
     46 	// wants up and is up
     47 	// wants down and is down
     48 	if ((buffer->wantsup == 'd') == (buffer->state == 0))
     49 		printf("= ");
     50 	// wants down and is up
     51 	else if (buffer->wantsup == 'd')
     52 		printf("v ");
     53 	// wants up and is down
     54 	else if (buffer->state == 0)
     55 		printf("^ ");
     56 
     57 	if (buffer->paused)
     58 		printf("paus  ");
     59 	else if (buffer->state == 0)
     60 		printf("down  ");
     61 	else if (buffer->state == 1)
     62 		printf("run   ");
     63 	else if (buffer->state == 2)
     64 		printf("fin   ");
     65 	else
     66 		printf("???   ");
     67 
     68 	uint64_t tai = ((uint64_t) buffer->status_change[0] << 56) |
     69 	               ((uint64_t) buffer->status_change[1] << 48) |
     70 	               ((uint64_t) buffer->status_change[2] << 40) |
     71 	               ((uint64_t) buffer->status_change[3] << 32) |
     72 	               ((uint64_t) buffer->status_change[4] << 24) |
     73 	               ((uint64_t) buffer->status_change[5] << 16) |
     74 	               ((uint64_t) buffer->status_change[6] << 8) |
     75 	               ((uint64_t) buffer->status_change[7] << 0);
     76 
     77 	time_t      timediff  = time(NULL) - tai + 4611686018427387914ULL;
     78 	const char* timediffu = timediff == 1 ? "second" : "seconds";
     79 	if (timediff >= 60) {
     80 		timediff /= 60;
     81 		timediffu = timediff == 1 ? "minute" : "minutes";
     82 		if (timediff >= 60) {
     83 			timediff /= 60;
     84 			timediffu = timediff == 1 ? "hour" : "hours";
     85 			if (timediff >= 24) {
     86 				timediff /= 24;
     87 				timediffu = timediff == 1 ? "day" : "days";
     88 			}
     89 		}
     90 	}
     91 	char timediffstr[20];
     92 	snprintf(timediffstr, sizeof timediffstr, "%ld %s", timediff, timediffu);
     93 
     94 	printf("%-11s ", timediffstr);
     95 
     96 	if (buffer->state == 1) {
     97 		pid_t pid = (buffer->pid[0] << 0) |
     98 		            (buffer->pid[1] << 8) |
     99 		            (buffer->pid[2] << 16) |
    100 		            (buffer->pid[3] << 24);
    101 
    102 		printf("%-5d  ", pid);
    103 
    104 		int  procfd;
    105 		char procpath[PATH_MAX];
    106 		char cmdline[1024];
    107 		int  nread;
    108 		snprintf(procpath, sizeof procpath, "/proc/%d/comm", pid);
    109 
    110 		if ((procfd = open(procpath, O_RDONLY)) != -1) {
    111 			nread = read(procfd, cmdline, sizeof cmdline);
    112 			if (nread < 0) nread = 0;
    113 			if (nread == sizeof cmdline) {
    114 				strcpy(&cmdline[sizeof cmdline - 4], "...");
    115 			} else {
    116 				nread--;
    117 				cmdline[nread] = '\0';
    118 			}
    119 			close(procfd);
    120 			printf("%s", cmdline);
    121 		} else {
    122 			printf("---");
    123 		}
    124 	} else {
    125 		printf("---    ---");
    126 	}
    127 	printf("\n");
    128 }
    129 
    130 int main(int argc, char** argv) {
    131 	char  path[PATH_MAX];
    132 	int   fd;
    133 	char* basename;
    134 
    135 	struct service_serial statusbuf;
    136 
    137 	for (int i = 1; i < argc; i++) {
    138 		snprintf(path, sizeof path, "%s/supervise/status", argv[i]);
    139 		if ((fd = open(path, O_RDONLY)) == -1) {
    140 			fprintf(stderr, "%s: unable to open supervise/status\n", argv[i]);
    141 			continue;
    142 		}
    143 		if (read(fd, &statusbuf, sizeof statusbuf) != sizeof statusbuf) {
    144 			fprintf(stderr, "%s: unable to read status\n", argv[i]);
    145 			continue;
    146 		}
    147 		close(fd);
    148 
    149 		printstatus(argv[i], &statusbuf);
    150 	}
    151 }