]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/show-status.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / core / show-status.c
index 9509b21ccbd44eb592b55271ae24ff470afc86c1..40658a2e168cf903e5783756846c3ce37a3bed2f 100644 (file)
@@ -1,5 +1,4 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
+/* SPDX-License-Identifier: LGPL-2.1+ */
 /***
   This file is part of systemd.
 
@@ -19,7 +18,9 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "fd-util.h"
+#include "io-util.h"
 #include "parse-util.h"
 #include "show-status.h"
 #include "string-util.h"
@@ -44,3 +45,86 @@ int parse_show_status(const char *v, ShowStatus *ret) {
         *ret = r ? SHOW_STATUS_YES : SHOW_STATUS_NO;
         return 0;
 }
+
+int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) {
+        static const char status_indent[] = "         "; /* "[" STATUS "] " */
+        _cleanup_free_ char *s = NULL;
+        _cleanup_close_ int fd = -1;
+        struct iovec iovec[6] = {};
+        int n = 0;
+        static bool prev_ephemeral;
+
+        assert(format);
+
+        /* This is independent of logging, as status messages are
+         * optional and go exclusively to the console. */
+
+        if (vasprintf(&s, format, ap) < 0)
+                return log_oom();
+
+        /* Before you ask: yes, on purpose we open/close the console for each status line we write individually. This
+         * is a good strategy to avoid PID 1 getting killed by the kernel's SAK concept (it doesn't fix this entirely,
+         * but minimizes the time window the kernel might end up killing PID 1 due to SAK). It also makes things easier
+         * for us so that we don't have to recover from hangups and suchlike triggered on the console. */
+
+        fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
+        if (fd < 0)
+                return fd;
+
+        if (ellipse) {
+                char *e;
+                size_t emax, sl;
+                int c;
+
+                c = fd_columns(fd);
+                if (c <= 0)
+                        c = 80;
+
+                sl = status ? sizeof(status_indent)-1 : 0;
+
+                emax = c - sl - 1;
+                if (emax < 3)
+                        emax = 3;
+
+                e = ellipsize(s, emax, 50);
+                if (e) {
+                        free(s);
+                        s = e;
+                }
+        }
+
+        if (prev_ephemeral)
+                iovec[n++] = IOVEC_MAKE_STRING("\r" ANSI_ERASE_TO_END_OF_LINE);
+        prev_ephemeral = ephemeral;
+
+        if (status) {
+                if (!isempty(status)) {
+                        iovec[n++] = IOVEC_MAKE_STRING("[");
+                        iovec[n++] = IOVEC_MAKE_STRING(status);
+                        iovec[n++] = IOVEC_MAKE_STRING("] ");
+                } else
+                        iovec[n++] = IOVEC_MAKE_STRING(status_indent);
+        }
+
+        iovec[n++] = IOVEC_MAKE_STRING(s);
+        if (!ephemeral)
+                iovec[n++] = IOVEC_MAKE_STRING("\n");
+
+        if (writev(fd, iovec, n) < 0)
+                return -errno;
+
+        return 0;
+}
+
+int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) {
+        va_list ap;
+        int r;
+
+        assert(format);
+
+        va_start(ap, format);
+        r = status_vprintf(status, ellipse, ephemeral, format, ap);
+        va_end(ap);
+
+        return r;
+}