console: colorized status output and startup banner

5 files changed +94 −9

  • + src/includes/dinit-colors.h
  • • src/dinit-log.cc
  • • src/dinit.cc
  • • src/includes/dinit-log.h
  • • src/shutdown.cc
1diff --git a/src/dinit-log.cc b/src/dinit-log.cc
2index a83c3e3..c54f193 100644
3--- a/src/dinit-log.cc
4+++ b/src/dinit-log.cc
5@@ -9,6 +9,7 @@
6
7 #include "service.h"
8 #include "dinit-log.h"
9+#include "dinit-colors.h"
10 #include "cpbuffer.h"
11
12 // Dinit logging subsystem.
13@@ -286,6 +287,8 @@ void buffered_log_stream::watch_removed() noexcept
14 // Potentially throws std::bad_alloc or std::system_error
15 void init_log(bool syslog_format)
16 {
17+ dinit_colors::set_color_enabled(dinit_colors::use_color(STDOUT_FILENO));
18+
19 log_stream[DLOG_CONS].add_watch(event_loop, STDOUT_FILENO, dasynq::OUT_EVENTS, false);
20 enable_console_log(true);
21
22@@ -552,21 +555,28 @@ void log_msg_end(const char *msg) noexcept
23 }
24 }
25
26+void log_startup_banner(const char *version) noexcept
27+{
28+ do_log_cons(loglevel_t::NOTICE, "\n", dinit_colors::brand(), " ", version, " is starting up\n\n");
29+ do_log_main(loglevel_t::NOTICE, "dinit: version ", version, " starting up.\n");
30+}
31+
32 void log_service_started(const char *service_name) noexcept
33 {
34- do_log_cons(loglevel_t::NOTICE, "[ OK ] ", service_name, "\n");
35+ do_log_cons(loglevel_t::NOTICE, dinit_colors::mark_ok(), service_name, "\n");
36 do_log_main(loglevel_t::NOTICE, "dinit: service ", service_name, " started.\n");
37 }
38
39 void log_service_failed(const char *service_name, bool dep_failed) noexcept
40 {
41 loglevel_t cons_lvl = dep_failed ? loglevel_t::WARN : loglevel_t::ERROR;
42- do_log_cons(cons_lvl, "[FAILED] ", service_name, "\n");
43+ do_log_cons(cons_lvl, dinit_colors::mark_failed(), service_name,
44+ dinit_colors::failed_suffix(), "\n");
45 do_log_main(loglevel_t::ERROR, "dinit: service ", service_name, " failed to start.\n");
46 }
47
48 void log_service_stopped(const char *service_name) noexcept
49 {
50- do_log_cons(loglevel_t::NOTICE, "[STOPPD] ", service_name, "\n");
51+ do_log_cons(loglevel_t::NOTICE, dinit_colors::mark_stopped(), service_name, "\n");
52 do_log_main(loglevel_t::NOTICE, "dinit: service ", service_name, " stopped.\n");
53 }
54diff --git a/src/dinit.cc b/src/dinit.cc
55index aa19b9e..e3c7ec3 100644
56--- a/src/dinit.cc
57+++ b/src/dinit.cc
58@@ -595,6 +595,7 @@ int dinit_main(int argc, char **argv)
59 }
60
61 init_log(log_is_syslog);
62+ log_startup_banner(DINIT_VERSION);
63 log_flush_timer.add_timer(event_loop, dasynq::clock_type::MONOTONIC);
64
65 #if SUPPORT_CGROUPS
66diff --git a/src/includes/dinit-colors.h b/src/includes/dinit-colors.h
67new file mode 100644
68index 0000000..ccb376f
69--- /dev/null
70+++ b/src/includes/dinit-colors.h
71@@ -0,0 +1,63 @@
72+#ifndef DINIT_COLORS_H_INCLUDED
73+#define DINIT_COLORS_H_INCLUDED 1
74+
75+#include <cstdlib>
76+#include <cstring>
77+
78+#include <unistd.h>
79+
80+namespace dinit_colors {
81+
82+inline bool use_color(int fd) noexcept
83+{
84+ const char *no_color = getenv("NO_COLOR");
85+ if (no_color != nullptr && no_color[0] != '\0') return false;
86+ const char *term = getenv("TERM");
87+ if (term != nullptr && strcmp(term, "dumb") == 0) return false;
88+ return isatty(fd) == 1;
89+}
90+
91+inline bool &color_enabled() noexcept
92+{
93+ static bool enabled = false;
94+ return enabled;
95+}
96+
97+inline void set_color_enabled(bool enable) noexcept
98+{
99+ color_enabled() = enable;
100+}
101+
102+inline const char *mark_ok() noexcept
103+{
104+ return color_enabled() ? " \033[1;32m*\033[0m " : " [+] ";
105+}
106+
107+inline const char *mark_stopped() noexcept
108+{
109+ return color_enabled() ? " \033[1;31m*\033[0m " : " [-] ";
110+}
111+
112+inline const char *mark_failed() noexcept
113+{
114+ return color_enabled() ? " \033[1;31m*\033[0m " : " [!] ";
115+}
116+
117+inline const char *mark_info() noexcept
118+{
119+ return color_enabled() ? " \033[1;31m*\033[0m " : " [*] ";
120+}
121+
122+inline const char *failed_suffix() noexcept
123+{
124+ return color_enabled() ? "\033[1;31m failed\033[0m" : " failed";
125+}
126+
127+inline const char *brand() noexcept
128+{
129+ return color_enabled() ? "\033[1;92mdinit-ferdios\033[0m" : "dinit-ferdios";
130+}
131+
132+} // namespace dinit_colors
133+
134+#endif
135diff --git a/src/includes/dinit-log.h b/src/includes/dinit-log.h
136index ace3605..4351600 100644
137--- a/src/includes/dinit-log.h
138+++ b/src/includes/dinit-log.h
139@@ -78,6 +78,8 @@ void log_msg_begin(loglevel_t lvl, const char *msg) noexcept;
140 void log_msg_part(const char *msg) noexcept;
141 void log_msg_end(const char *msg) noexcept;
142
143+void log_startup_banner(const char *version) noexcept;
144+
145 void log_service_started(const char *service_name) noexcept;
146 void log_service_failed(const char *service_name, bool dep_failed) noexcept;
147 void log_service_stopped(const char *service_name) noexcept;
148diff --git a/src/shutdown.cc b/src/shutdown.cc
149index fa13169..d159e72 100644
150--- a/src/shutdown.cc
151+++ b/src/shutdown.cc
152@@ -25,6 +25,7 @@
153 #include "dinit-util.h"
154 #include "mconfig.h"
155 #include "control-datatypes.h"
156+#include "dinit-colors.h"
157
158 #include "dasynq.h"
159
160@@ -299,6 +300,8 @@ static bool reboot_cmd_unsupported(const shutdown_type_t type)
161 int main(int argc, char **argv)
162 {
163 using namespace std;
164+
165+ dinit_colors::set_color_enabled(dinit_colors::use_color(STDOUT_FILENO));
166
167 bool show_help = false;
168 bool sys_shutdown = false;
169@@ -446,7 +449,7 @@ int main(int argc, char **argv)
170 buf[0] = (dinit_cptypes::cp_cmd_t)cp_cmd::SHUTDOWN;
171 buf[1] = static_cast<char>(shutdown_type);
172
173- cout << "Issuing shutdown command..." << endl;
174+ cout << dinit_colors::mark_info() << "issuing shutdown command" << endl;
175
176 write_all_x(socknum, buf, bufsize);
177
178@@ -548,12 +551,14 @@ void do_system_shutdown(shutdown_type_t shutdown_type)
179 int consfd = open("/dev/console", O_WRONLY);
180 if (consfd != STDOUT_FILENO && consfd != -1) {
181 dup2(consfd, STDOUT_FILENO);
182+ dinit_colors::set_color_enabled(dinit_colors::use_color(STDOUT_FILENO));
183 }
184
185 loop_t loop;
186 subproc_buffer sub_buf {loop, STDOUT_FILENO};
187
188- sub_buf.append("Sending TERM/KILL to all processes...\n");
189+ sub_buf.append(dinit_colors::mark_info());
190+ sub_buf.append("sending TERM/KILL to all processes\n");
191
192 // Send TERM/KILL to all (remaining) processes
193 kill(-1, SIGTERM);
194@@ -589,7 +594,8 @@ void do_system_shutdown(shutdown_type_t shutdown_type)
195 for (size_t i = 0; i < sizeof(hook_paths) / sizeof(hook_paths[0]); ++i) {
196 int stat_r = lstat(hook_paths[i], &statbuf);
197 if (stat_r == 0 && (statbuf.st_mode & execmask) != 0) {
198- sub_buf.append("Executing shutdown hook...\n");
199+ sub_buf.append(dinit_colors::mark_info());
200+ sub_buf.append("executing shutdown hook\n");
201 const char *prog_args[] = { hook_paths[i], shutdown_type_arg, nullptr };
202 try {
203 auto r = run_process(prog_args, loop, sub_buf);
204@@ -608,9 +614,11 @@ void do_system_shutdown(shutdown_type_t shutdown_type)
205
206 // perform shutdown
207 if (do_unmount_ourself) {
208- sub_buf.append("Turning off swap...\n");
209+ sub_buf.append(dinit_colors::mark_info());
210+ sub_buf.append("turning off swap\n");
211 swap_off(loop, sub_buf);
212- sub_buf.append("Unmounting disks...\n");
213+ sub_buf.append(dinit_colors::mark_info());
214+ sub_buf.append("unmounting disks\n");
215 unmount_disks(loop, sub_buf);
216 }
217
218@@ -621,7 +629,8 @@ void do_system_shutdown(shutdown_type_t shutdown_type)
219 exit(0);
220 }
221
222- sub_buf.append("Issuing shutdown via kernel...\n");
223+ sub_buf.append(dinit_colors::mark_info());
224+ sub_buf.append("issuing shutdown via kernel\n");
225 loop.poll(); // give message a chance to get to console
226 #ifdef __NetBSD__
227 reboot(reboot_type, NULL);