1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include "alloc-util.h"
10 #include "parse-util.h"
11 #include "show-status.h"
12 #include "string-table.h"
13 #include "string-util.h"
14 #include "terminal-util.h"
17 static const char* const show_status_table
[_SHOW_STATUS_MAX
] = {
18 [SHOW_STATUS_NO
] = "no",
19 [SHOW_STATUS_ERROR
] = "error",
20 [SHOW_STATUS_AUTO
] = "auto",
21 [SHOW_STATUS_TEMPORARY
] = "temporary",
22 [SHOW_STATUS_YES
] = "yes",
25 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(show_status
, ShowStatus
, SHOW_STATUS_YES
);
27 int parse_show_status(const char *v
, ShowStatus
*ret
) {
32 s
= show_status_from_string(v
);
33 if (s
< 0 || s
== SHOW_STATUS_TEMPORARY
)
40 int status_vprintf(const char *status
, ShowStatusFlags flags
, const char *format
, va_list ap
) {
41 static const char status_indent
[] = " "; /* "[" STATUS "] " */
42 _cleanup_free_
char *s
= NULL
;
43 _cleanup_close_
int fd
= -1;
44 struct iovec iovec
[7] = {};
46 static bool prev_ephemeral
;
50 /* This is independent of logging, as status messages are
51 * optional and go exclusively to the console. */
53 if (vasprintf(&s
, format
, ap
) < 0)
56 /* Before you ask: yes, on purpose we open/close the console for each status line we write individually. This
57 * is a good strategy to avoid PID 1 getting killed by the kernel's SAK concept (it doesn't fix this entirely,
58 * but minimizes the time window the kernel might end up killing PID 1 due to SAK). It also makes things easier
59 * for us so that we don't have to recover from hangups and suchlike triggered on the console. */
61 fd
= open_terminal("/dev/console", O_WRONLY
|O_NOCTTY
|O_CLOEXEC
);
65 if (FLAGS_SET(flags
, SHOW_STATUS_ELLIPSIZE
)) {
74 sl
= status
? sizeof(status_indent
)-1 : 0;
80 e
= ellipsize(s
, emax
, 50);
82 free_and_replace(s
, e
);
86 iovec
[n
++] = IOVEC_MAKE_STRING(ANSI_REVERSE_LINEFEED
"\r" ANSI_ERASE_TO_END_OF_LINE
);
89 if (!isempty(status
)) {
90 iovec
[n
++] = IOVEC_MAKE_STRING("[");
91 iovec
[n
++] = IOVEC_MAKE_STRING(status
);
92 iovec
[n
++] = IOVEC_MAKE_STRING("] ");
94 iovec
[n
++] = IOVEC_MAKE_STRING(status_indent
);
97 iovec
[n
++] = IOVEC_MAKE_STRING(s
);
98 iovec
[n
++] = IOVEC_MAKE_STRING("\n");
100 if (prev_ephemeral
&& !FLAGS_SET(flags
, SHOW_STATUS_EPHEMERAL
))
101 iovec
[n
++] = IOVEC_MAKE_STRING(ANSI_ERASE_TO_END_OF_LINE
);
102 prev_ephemeral
= FLAGS_SET(flags
, SHOW_STATUS_EPHEMERAL
) ;
104 if (writev(fd
, iovec
, n
) < 0)
110 int status_printf(const char *status
, ShowStatusFlags flags
, const char *format
, ...) {
116 va_start(ap
, format
);
117 r
= status_vprintf(status
, flags
, format
, ap
);
123 static const char* const status_unit_format_table
[_STATUS_UNIT_FORMAT_MAX
] = {
124 [STATUS_UNIT_FORMAT_NAME
] = "name",
125 [STATUS_UNIT_FORMAT_DESCRIPTION
] = "description",
128 DEFINE_STRING_TABLE_LOOKUP(status_unit_format
, StatusUnitFormat
);