]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/show-status.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / core / show-status.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
15bd9a28 2
b5efdb8a 3#include "alloc-util.h"
8b43440b 4#include "fd-util.h"
afc5dbf3 5#include "io-util.h"
6bedfcbb
LP
6#include "parse-util.h"
7#include "show-status.h"
7a293242 8#include "string-table.h"
07630cea 9#include "string-util.h"
8b43440b 10#include "terminal-util.h"
15bd9a28
LP
11#include "util.h"
12
bee38b5c 13static const char* const show_status_table[_SHOW_STATUS_MAX] = {
7a293242
YW
14 [SHOW_STATUS_NO] = "no",
15 [SHOW_STATUS_AUTO] = "auto",
16 [SHOW_STATUS_TEMPORARY] = "temporary",
17 [SHOW_STATUS_YES] = "yes",
18};
19
20DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(show_status, ShowStatus, SHOW_STATUS_YES);
21
15bd9a28 22int parse_show_status(const char *v, ShowStatus *ret) {
7a293242 23 ShowStatus s;
15bd9a28 24
15bd9a28
LP
25 assert(ret);
26
7a293242
YW
27 s = show_status_from_string(v);
28 if (s < 0 || s == SHOW_STATUS_TEMPORARY)
29 return -EINVAL;
15bd9a28 30
7a293242 31 *ret = s;
15bd9a28
LP
32 return 0;
33}
b8faf2ec 34
a885727a 35int status_vprintf(const char *status, ShowStatusFlags flags, const char *format, va_list ap) {
b8faf2ec
LP
36 static const char status_indent[] = " "; /* "[" STATUS "] " */
37 _cleanup_free_ char *s = NULL;
38 _cleanup_close_ int fd = -1;
82554307 39 struct iovec iovec[7] = {};
b8faf2ec
LP
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
8ae2c630
LP
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
b8faf2ec
LP
56 fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
57 if (fd < 0)
58 return fd;
59
a885727a 60 if (FLAGS_SET(flags, SHOW_STATUS_ELLIPSIZE)) {
b8faf2ec
LP
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);
ccfc08d4
LP
76 if (e)
77 free_and_replace(s, e);
b8faf2ec
LP
78 }
79
80 if (prev_ephemeral)
82554307 81 iovec[n++] = IOVEC_MAKE_STRING(ANSI_REVERSE_LINEFEED "\r" ANSI_ERASE_TO_END_OF_LINE);
b8faf2ec
LP
82
83 if (status) {
84 if (!isempty(status)) {
e6a7ec4b
LP
85 iovec[n++] = IOVEC_MAKE_STRING("[");
86 iovec[n++] = IOVEC_MAKE_STRING(status);
87 iovec[n++] = IOVEC_MAKE_STRING("] ");
b8faf2ec 88 } else
e6a7ec4b 89 iovec[n++] = IOVEC_MAKE_STRING(status_indent);
b8faf2ec
LP
90 }
91
e6a7ec4b 92 iovec[n++] = IOVEC_MAKE_STRING(s);
82554307
T
93 iovec[n++] = IOVEC_MAKE_STRING("\n");
94
a885727a 95 if (prev_ephemeral && !FLAGS_SET(flags, SHOW_STATUS_EPHEMERAL))
82554307 96 iovec[n++] = IOVEC_MAKE_STRING(ANSI_ERASE_TO_END_OF_LINE);
a885727a 97 prev_ephemeral = FLAGS_SET(flags, SHOW_STATUS_EPHEMERAL) ;
b8faf2ec
LP
98
99 if (writev(fd, iovec, n) < 0)
100 return -errno;
101
102 return 0;
103}
104
a885727a 105int status_printf(const char *status, ShowStatusFlags flags, const char *format, ...) {
b8faf2ec
LP
106 va_list ap;
107 int r;
108
109 assert(format);
110
111 va_start(ap, format);
a885727a 112 r = status_vprintf(status, flags, format, ap);
b8faf2ec
LP
113 va_end(ap);
114
115 return r;
116}