]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/show-status.c
Merge pull request #10892 from mbiebl/revert-systemctl-runtime-unmask-breakage
[thirdparty/systemd.git] / src / core / show-status.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include "alloc-util.h"
4 #include "fd-util.h"
5 #include "io-util.h"
6 #include "parse-util.h"
7 #include "show-status.h"
8 #include "string-table.h"
9 #include "string-util.h"
10 #include "terminal-util.h"
11 #include "util.h"
12
13 static const char* const show_status_table[_SHOW_STATUS_MAX] = {
14 [SHOW_STATUS_NO] = "no",
15 [SHOW_STATUS_AUTO] = "auto",
16 [SHOW_STATUS_TEMPORARY] = "temporary",
17 [SHOW_STATUS_YES] = "yes",
18 };
19
20 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(show_status, ShowStatus, SHOW_STATUS_YES);
21
22 int parse_show_status(const char *v, ShowStatus *ret) {
23 ShowStatus s;
24
25 assert(ret);
26
27 s = show_status_from_string(v);
28 if (s < 0 || s == SHOW_STATUS_TEMPORARY)
29 return -EINVAL;
30
31 *ret = s;
32 return 0;
33 }
34
35 int status_vprintf(const char *status, ShowStatusFlags flags, const char *format, va_list ap) {
36 static const char status_indent[] = " "; /* "[" STATUS "] " */
37 _cleanup_free_ char *s = NULL;
38 _cleanup_close_ int fd = -1;
39 struct iovec iovec[7] = {};
40 int n = 0;
41 static bool prev_ephemeral;
42
43 assert(format);
44
45 /* This is independent of logging, as status messages are
46 * optional and go exclusively to the console. */
47
48 if (vasprintf(&s, format, ap) < 0)
49 return log_oom();
50
51 /* Before you ask: yes, on purpose we open/close the console for each status line we write individually. This
52 * is a good strategy to avoid PID 1 getting killed by the kernel's SAK concept (it doesn't fix this entirely,
53 * but minimizes the time window the kernel might end up killing PID 1 due to SAK). It also makes things easier
54 * for us so that we don't have to recover from hangups and suchlike triggered on the console. */
55
56 fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
57 if (fd < 0)
58 return fd;
59
60 if (FLAGS_SET(flags, SHOW_STATUS_ELLIPSIZE)) {
61 char *e;
62 size_t emax, sl;
63 int c;
64
65 c = fd_columns(fd);
66 if (c <= 0)
67 c = 80;
68
69 sl = status ? sizeof(status_indent)-1 : 0;
70
71 emax = c - sl - 1;
72 if (emax < 3)
73 emax = 3;
74
75 e = ellipsize(s, emax, 50);
76 if (e)
77 free_and_replace(s, e);
78 }
79
80 if (prev_ephemeral)
81 iovec[n++] = IOVEC_MAKE_STRING(ANSI_REVERSE_LINEFEED "\r" ANSI_ERASE_TO_END_OF_LINE);
82
83 if (status) {
84 if (!isempty(status)) {
85 iovec[n++] = IOVEC_MAKE_STRING("[");
86 iovec[n++] = IOVEC_MAKE_STRING(status);
87 iovec[n++] = IOVEC_MAKE_STRING("] ");
88 } else
89 iovec[n++] = IOVEC_MAKE_STRING(status_indent);
90 }
91
92 iovec[n++] = IOVEC_MAKE_STRING(s);
93 iovec[n++] = IOVEC_MAKE_STRING("\n");
94
95 if (prev_ephemeral && !FLAGS_SET(flags, SHOW_STATUS_EPHEMERAL))
96 iovec[n++] = IOVEC_MAKE_STRING(ANSI_ERASE_TO_END_OF_LINE);
97 prev_ephemeral = FLAGS_SET(flags, SHOW_STATUS_EPHEMERAL) ;
98
99 if (writev(fd, iovec, n) < 0)
100 return -errno;
101
102 return 0;
103 }
104
105 int status_printf(const char *status, ShowStatusFlags flags, const char *format, ...) {
106 va_list ap;
107 int r;
108
109 assert(format);
110
111 va_start(ap, format);
112 r = status_vprintf(status, flags, format, ap);
113 va_end(ap);
114
115 return r;
116 }