Skip to content

Commit 18eb369

Browse files
author
Bogdan Boyadzhiev
committed
implemented basic curses support
1 parent 80b030f commit 18eb369

File tree

2 files changed

+87
-17
lines changed

2 files changed

+87
-17
lines changed

Makefile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ CFLAGS += -Wall -Wextra
77
CFLAGS += -g -O0
88
LDFLAGS += -g
99

10-
LDADD+= -ljail
11-
DPADD+= ${LIBUTIL} ${LIBPROCSTAT} ${LIBKVM}
10+
LDADD+= -ljail -lcurses
1211

1312
.include <bsd.prog.mk>

jruls.c

Lines changed: 86 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
#include <sys/types.h>
2+
#include <curses.h>
23
#include <err.h>
34
#include <errno.h>
45
#include <inttypes.h>
6+
#include <locale.h>
57
#include <stdio.h>
68
#include <stdlib.h>
79
#include <string.h>
@@ -17,6 +19,8 @@
1719
static int cw_jid = 3, cw_name = 20, cw_pct = 4, cw_mem = 6;
1820
static int cw_iops = 5, cw_iovol = 6, cw_cnt = 5;
1921

22+
static int smart_terminal = 1;
23+
2024
static void print_n(uint64_t v, int colwidth);
2125
static void print_nmp(uint64_t v, int colwidth);
2226

@@ -45,6 +49,16 @@ static const size_t tot_metrics =
4549
sizeof (all_metrics) / sizeof (all_metrics[0]);
4650
static const struct metric *metrics[30];
4751

52+
/* Rudimentary I/O abstraction to support smart and dump terminals */
53+
struct iofuncs {
54+
/* x-prefix is a work-around as clear, attron... are macros */
55+
int (*xclear)(void);
56+
int (*xattron)(int attrs);
57+
int (*xattroff)(int attrs);
58+
int (*xprint)(const char *fmt, ...);
59+
int (*xrefresh)(void);
60+
} io = { 0 };
61+
4862
static const struct metric*
4963
find_metric(const char *name)
5064
{
@@ -77,7 +91,7 @@ findval(const char *list,
7791
static void
7892
print_n(uint64_t v, int colwidth)
7993
{
80-
printf("%*"PRIu64, colwidth, v);
94+
io.xprint("%*"PRIu64, colwidth, v);
8195
}
8296

8397
static void
@@ -92,26 +106,29 @@ print_nmp(uint64_t v, int colwidth)
92106
v / (1024 * 1024 * 1024.0));
93107
else if (v > 9999 * 1024)
94108
snprintf(buf, sizeof buf, "%.1fM",
95-
v / (1024 * 1024.0));
109+
v / (1024 * 1024.0));
96110
else /* if (v > 9999) */
97111
snprintf(buf, sizeof buf, "%.0fK",
98-
v / 1024.0);
112+
v / 1024.0);
99113
}
100-
printf("%*s", colwidth, buf);
114+
io.xprint("%*s", colwidth, buf);
101115
}
102116

103117

104118
static void
105119
print_headers(void)
106120
{
107-
printf("%*s %-*s",
108-
cw_jid, "jid",
109-
cw_name, "name");
121+
io.xclear();
122+
io.xattron(A_BOLD);
123+
io.xprint("%*s %-*s",
124+
cw_jid, "jid",
125+
cw_name, "name");
110126
const struct metric **it = metrics;
111127
for (; *it; ++it) {
112-
printf(" %*s", *(*it)->colwidth, (*it)->label);
128+
io.xprint(" %*s", *(*it)->colwidth, (*it)->label);
113129
}
114-
puts("");
130+
io.xprint("\n");
131+
io.xattroff(A_BOLD);
115132
}
116133

117134

@@ -120,9 +137,9 @@ print_jail(int jid,
120137
const char *name)
121138
{
122139
char q[MAXHOSTNAMELEN + 20], buf[4096];
123-
printf("%*d %-*s",
124-
cw_jid, jid,
125-
cw_name, name);
140+
io.xprint("%*d %-*s",
141+
cw_jid, jid,
142+
cw_name, name);
126143

127144
snprintf(q, sizeof q, "jail:%s:cputime", name);
128145
int rv = rctl_get_racct(q, strlen(q) + 1,
@@ -132,16 +149,63 @@ print_jail(int jid,
132149
* pairs: cputime=##,datasize=##,... */
133150
const struct metric **it = metrics;
134151
for (; *it; ++it) {
135-
printf(" ");
152+
io.xprint(" ");
136153
(*it)->print(findval(buf, (*it)->name),
137154
*(*it)->colwidth);
138155
}
139156
} else {
140157
if (errno == ENOSYS)
141158
err(EX_OSERR, "rctl_get_racct");
142-
printf(": %s", strerror(errno));
159+
io.xprint(": %s", strerror(errno));
160+
}
161+
io.xprint("\n");
162+
}
163+
164+
165+
static int
166+
no_clear(void)
167+
{
168+
return 0;
169+
}
170+
static int
171+
no_refresh(void)
172+
{
173+
printf("\n");
174+
fflush(stdout);
175+
return 0;
176+
}
177+
static int
178+
no_attrtoggle(int attrs)
179+
{
180+
(void)attrs;
181+
return 0;
182+
}
183+
184+
static void
185+
init_io(void)
186+
{
187+
smart_terminal = getenv("TERM") != 0;
188+
if (smart_terminal) {
189+
smart_terminal = isatty(1);
190+
}
191+
192+
if (smart_terminal) {
193+
/* Initialize curses library */
194+
setlocale(LC_ALL, "");
195+
initscr();
196+
197+
io.xclear = &clear;
198+
io.xattron = &attron;
199+
io.xattroff = &attroff;
200+
io.xprint = &printw;
201+
io.xrefresh = &refresh;
202+
} else { /* dump terminal */
203+
io.xclear = &no_clear;
204+
io.xattron = &no_attrtoggle;
205+
io.xattroff = &no_attrtoggle;
206+
io.xprint = &printf;
207+
io.xrefresh = &no_refresh;
143208
}
144-
puts("");
145209
}
146210

147211

@@ -212,6 +276,12 @@ main(int argc, char *argv[])
212276
jailparam_import_raw(&param[2], name, sizeof name) == -1)
213277
errx(EX_OSERR, "jailparam_import_raw: %s", jail_errmsg);
214278

279+
init_io();
280+
281+
if (count == INT_MAX && !smart_terminal) {
282+
count = 1;
283+
}
284+
215285
do {
216286
int jflags = 0, rv, n;
217287
lastjid = n = 0;
@@ -230,6 +300,7 @@ main(int argc, char *argv[])
230300
if (!n)
231301
errx(EX_UNAVAILABLE, "no jails found");
232302

303+
io.xrefresh();
233304
if (count > 1) {
234305
sleep(sleep_itv);
235306
puts("");

0 commit comments

Comments
 (0)