diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2018-11-20 15:42:57 +0100 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2018-11-20 18:40:02 +0100 |
commit | 294bf0c34a53caa25709b794bfeee6a00a2b6ecd (patch) | |
tree | a429db1ca92924ac73959a0ed9954161e22612dd /src/basic | |
parent | 0166c42868813d5d96b500277f6f819eef498b95 (diff) | |
download | systemd-294bf0c34a53caa25709b794bfeee6a00a2b6ecd.tar.gz |
Split out pretty-print.c and move pager.c and main-func.h to shared/
This is high-level functionality, and fits better in shared/ (which is for
our executables), than in basic/ (which is also for libraries).
Diffstat (limited to 'src/basic')
-rw-r--r-- | src/basic/conf-files.c | 33 | ||||
-rw-r--r-- | src/basic/conf-files.h | 1 | ||||
-rw-r--r-- | src/basic/main-func.h | 27 | ||||
-rw-r--r-- | src/basic/meson.build | 2 | ||||
-rw-r--r-- | src/basic/pager.c | 270 | ||||
-rw-r--r-- | src/basic/pager.h | 17 | ||||
-rw-r--r-- | src/basic/terminal-util.c | 182 | ||||
-rw-r--r-- | src/basic/terminal-util.h | 12 |
8 files changed, 0 insertions, 544 deletions
diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c index d03366077d..7b44ae277d 100644 --- a/src/basic/conf-files.c +++ b/src/basic/conf-files.c @@ -328,36 +328,3 @@ int conf_files_list_with_replacement( *replace_file = TAKE_PTR(p); return 0; } - -int conf_files_cat(const char *root, const char *name) { - _cleanup_strv_free_ char **dirs = NULL, **files = NULL; - _cleanup_free_ char *path = NULL; - const char *dir; - char **t; - int r; - - NULSTR_FOREACH(dir, CONF_PATHS_NULSTR("")) { - assert(endswith(dir, "/")); - r = strv_extendf(&dirs, "%s%s.d", dir, name); - if (r < 0) - return log_error_errno(r, "Failed to build directory list: %m"); - } - - r = conf_files_list_strv(&files, ".conf", root, 0, (const char* const*) dirs); - if (r < 0) - return log_error_errno(r, "Failed to query file list: %m"); - - path = path_join(root, "/etc", name); - if (!path) - return log_oom(); - - if (DEBUG_LOGGING) { - log_debug("Looking for configuration in:"); - log_debug(" %s", path); - STRV_FOREACH(t, dirs) - log_debug(" %s/*.conf", *t); - } - - /* show */ - return cat_files(path, files, CAT_FLAGS_MAIN_FILE_OPTIONAL); -} diff --git a/src/basic/conf-files.h b/src/basic/conf-files.h index 81ebcd46b6..f31f17de9d 100644 --- a/src/basic/conf-files.h +++ b/src/basic/conf-files.h @@ -22,4 +22,3 @@ int conf_files_list_with_replacement( const char *replacement, char ***files, char **replace_file); -int conf_files_cat(const char *root, const char *name); diff --git a/src/basic/main-func.h b/src/basic/main-func.h deleted file mode 100644 index 24bf6c99bf..0000000000 --- a/src/basic/main-func.h +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -#pragma once - -#include <stdlib.h> - -#include "pager.h" -#include "static-destruct.h" - -#define _DEFINE_MAIN_FUNCTION(impl, ret) \ - int main(int argc, char *argv[]) { \ - int r; \ - r = impl(argc, argv); \ - static_destruct(); \ - pager_close(); \ - return ret; \ - } - -/* Negative return values from impl are mapped to EXIT_FAILURE, and - * everything else means success! */ -#define DEFINE_MAIN_FUNCTION(impl) \ - _DEFINE_MAIN_FUNCTION(impl, r < 0 ? EXIT_FAILURE : EXIT_SUCCESS) - -/* Zero is mapped to EXIT_SUCCESS, negative values are mapped to EXIT_FAILURE, - * and postive values are propagated. - * Note: "true" means failure! */ -#define DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(impl) \ - _DEFINE_MAIN_FUNCTION(impl, r < 0 ? EXIT_FAILURE : r) diff --git a/src/basic/meson.build b/src/basic/meson.build index abd54db8cc..0b27ffda7d 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -99,8 +99,6 @@ basic_sources = files(''' nss-util.h ordered-set.c ordered-set.h - pager.c - pager.h parse-util.c parse-util.h path-util.c diff --git a/src/basic/pager.c b/src/basic/pager.c deleted file mode 100644 index 88d9ef349e..0000000000 --- a/src/basic/pager.c +++ /dev/null @@ -1,270 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ - -#include <errno.h> -#include <signal.h> -#include <stddef.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/prctl.h> -#include <unistd.h> - -#include "copy.h" -#include "fd-util.h" -#include "fileio.h" -#include "io-util.h" -#include "locale-util.h" -#include "log.h" -#include "macro.h" -#include "pager.h" -#include "process-util.h" -#include "signal-util.h" -#include "string-util.h" -#include "strv.h" -#include "terminal-util.h" - -static pid_t pager_pid = 0; - -static int stored_stdout = -1; -static int stored_stderr = -1; -static bool stdout_redirected = false; -static bool stderr_redirected = false; - -_noreturn_ static void pager_fallback(void) { - int r; - - r = copy_bytes(STDIN_FILENO, STDOUT_FILENO, (uint64_t) -1, 0); - if (r < 0) { - log_error_errno(r, "Internal pager failed: %m"); - _exit(EXIT_FAILURE); - } - - _exit(EXIT_SUCCESS); -} - -static int no_quit_on_interrupt(int exe_name_fd, const char *less_opts) { - _cleanup_fclose_ FILE *file = NULL; - _cleanup_free_ char *line = NULL; - int r; - - assert(exe_name_fd >= 0); - assert(less_opts); - - /* This takes ownership of exe_name_fd */ - file = fdopen(exe_name_fd, "r"); - if (!file) { - safe_close(exe_name_fd); - return log_debug_errno(errno, "Failed to create FILE object: %m"); - } - - /* Find the last line */ - for (;;) { - _cleanup_free_ char *t = NULL; - - r = read_line(file, LONG_LINE_MAX, &t); - if (r < 0) - return r; - if (r == 0) - break; - - free_and_replace(line, t); - } - - /* We only treat "less" specially. - * Return true whenever option K is *not* set. */ - r = streq_ptr(line, "less") && !strchr(less_opts, 'K'); - - log_debug("Pager executable is \"%s\", options \"%s\", quit_on_interrupt: %s", - strnull(line), less_opts, yes_no(!r)); - return r; -} - -int pager_open(PagerFlags flags) { - _cleanup_close_pair_ int fd[2] = { -1, -1 }, exe_name_pipe[2] = { -1, -1 }; - _cleanup_strv_free_ char **pager_args = NULL; - const char *pager, *less_opts; - int r; - - if (flags & PAGER_DISABLE) - return 0; - - if (pager_pid > 0) - return 1; - - if (terminal_is_dumb()) - return 0; - - if (!is_main_thread()) - return -EPERM; - - pager = getenv("SYSTEMD_PAGER"); - if (!pager) - pager = getenv("PAGER"); - - if (pager) { - pager_args = strv_split(pager, WHITESPACE); - if (!pager_args) - return -ENOMEM; - - /* If the pager is explicitly turned off, honour it */ - if (strv_isempty(pager_args) || strv_equal(pager_args, STRV_MAKE("cat"))) - return 0; - } - - /* Determine and cache number of columns/lines before we spawn the pager so that we get the value from the - * actual tty */ - (void) columns(); - (void) lines(); - - if (pipe2(fd, O_CLOEXEC) < 0) - return log_error_errno(errno, "Failed to create pager pipe: %m"); - - /* This is a pipe to feed the name of the executed pager binary into the parent */ - if (pipe2(exe_name_pipe, O_CLOEXEC) < 0) - return log_error_errno(errno, "Failed to create exe_name pipe: %m"); - - /* Initialize a good set of less options */ - less_opts = getenv("SYSTEMD_LESS"); - if (!less_opts) - less_opts = "FRSXMK"; - if (flags & PAGER_JUMP_TO_END) - less_opts = strjoina(less_opts, " +G"); - - r = safe_fork("(pager)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pager_pid); - if (r < 0) - return r; - if (r == 0) { - const char *less_charset, *exe; - - /* In the child start the pager */ - - (void) dup2(fd[0], STDIN_FILENO); - safe_close_pair(fd); - - if (setenv("LESS", less_opts, 1) < 0) - _exit(EXIT_FAILURE); - - /* Initialize a good charset for less. This is - * particularly important if we output UTF-8 - * characters. */ - less_charset = getenv("SYSTEMD_LESSCHARSET"); - if (!less_charset && is_locale_utf8()) - less_charset = "utf-8"; - if (less_charset && - setenv("LESSCHARSET", less_charset, 1) < 0) - _exit(EXIT_FAILURE); - - if (pager_args) { - if (loop_write(exe_name_pipe[1], pager_args[0], strlen(pager_args[0]) + 1, false) < 0) - _exit(EXIT_FAILURE); - - execvp(pager_args[0], pager_args); - } - - /* Debian's alternatives command for pagers is - * called 'pager'. Note that we do not call - * sensible-pagers here, since that is just a - * shell script that implements a logic that - * is similar to this one anyway, but is - * Debian-specific. */ - FOREACH_STRING(exe, "pager", "less", "more") { - if (loop_write(exe_name_pipe[1], exe, strlen(exe) + 1, false) < 0) - _exit(EXIT_FAILURE); - execlp(exe, exe, NULL); - } - - if (loop_write(exe_name_pipe[1], "(built-in)", strlen("(built-in") + 1, false) < 0) - _exit(EXIT_FAILURE); - pager_fallback(); - /* not reached */ - } - - /* Return in the parent */ - stored_stdout = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 3); - if (dup2(fd[1], STDOUT_FILENO) < 0) { - stored_stdout = safe_close(stored_stdout); - return log_error_errno(errno, "Failed to duplicate pager pipe: %m"); - } - stdout_redirected = true; - - stored_stderr = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 3); - if (dup2(fd[1], STDERR_FILENO) < 0) { - stored_stderr = safe_close(stored_stderr); - return log_error_errno(errno, "Failed to duplicate pager pipe: %m"); - } - stderr_redirected = true; - - exe_name_pipe[1] = safe_close(exe_name_pipe[1]); - - r = no_quit_on_interrupt(TAKE_FD(exe_name_pipe[0]), less_opts); - if (r < 0) - return r; - if (r > 0) - (void) ignore_signals(SIGINT, -1); - - return 1; -} - -void pager_close(void) { - - if (pager_pid <= 0) - return; - - /* Inform pager that we are done */ - (void) fflush(stdout); - if (stdout_redirected) - if (stored_stdout < 0 || dup2(stored_stdout, STDOUT_FILENO) < 0) - (void) close(STDOUT_FILENO); - stored_stdout = safe_close(stored_stdout); - (void) fflush(stderr); - if (stderr_redirected) - if (stored_stderr < 0 || dup2(stored_stderr, STDERR_FILENO) < 0) - (void) close(STDERR_FILENO); - stored_stderr = safe_close(stored_stderr); - stdout_redirected = stderr_redirected = false; - - (void) kill(pager_pid, SIGCONT); - (void) wait_for_terminate(pager_pid, NULL); - pager_pid = 0; -} - -bool pager_have(void) { - return pager_pid > 0; -} - -int show_man_page(const char *desc, bool null_stdio) { - const char *args[4] = { "man", NULL, NULL, NULL }; - char *e = NULL; - pid_t pid; - size_t k; - int r; - - k = strlen(desc); - - if (desc[k-1] == ')') - e = strrchr(desc, '('); - - if (e) { - char *page = NULL, *section = NULL; - - page = strndupa(desc, e - desc); - section = strndupa(e + 1, desc + k - e - 2); - - args[1] = section; - args[2] = page; - } else - args[1] = desc; - - r = safe_fork("(man)", FORK_RESET_SIGNALS|FORK_DEATHSIG|(null_stdio ? FORK_NULL_STDIO : 0)|FORK_LOG, &pid); - if (r < 0) - return r; - if (r == 0) { - /* Child */ - execvp(args[0], (char**) args); - log_error_errno(errno, "Failed to execute man: %m"); - _exit(EXIT_FAILURE); - } - - return wait_for_terminate_and_check(NULL, pid, 0); -} diff --git a/src/basic/pager.h b/src/basic/pager.h deleted file mode 100644 index 8299e23856..0000000000 --- a/src/basic/pager.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -#pragma once - -#include <stdbool.h> - -#include "macro.h" - -typedef enum PagerFlags { - PAGER_DISABLE = 1 << 0, - PAGER_JUMP_TO_END = 1 << 1, -} PagerFlags; - -int pager_open(PagerFlags flags); -void pager_close(void); -bool pager_have(void) _pure_; - -int show_man_page(const char *page, bool null_stdio); diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index 41789598f7..2c7b4508ce 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -32,7 +32,6 @@ #include "io-util.h" #include "log.h" #include "macro.h" -#include "pager.h" #include "parse-util.h" #include "path-util.h" #include "proc-cmdline.h" @@ -1272,184 +1271,3 @@ int vt_reset_keyboard(int fd) { return 0; } - -static bool urlify_enabled(void) { - static int cached_urlify_enabled = -1; - - /* Unfortunately 'less' doesn't support links like this yet 😭, hence let's disable this as long as there's a - * pager in effect. Let's drop this check as soon as less got fixed a and enough time passed so that it's safe - * to assume that a link-enabled 'less' version has hit most installations. */ - - if (cached_urlify_enabled < 0) { - int val; - - val = getenv_bool("SYSTEMD_URLIFY"); - if (val >= 0) - cached_urlify_enabled = val; - else - cached_urlify_enabled = colors_enabled() && !pager_have(); - } - - return cached_urlify_enabled; -} - -int terminal_urlify(const char *url, const char *text, char **ret) { - char *n; - - assert(url); - - /* Takes an URL and a pretty string and formats it as clickable link for the terminal. See - * https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda for details. */ - - if (isempty(text)) - text = url; - - if (urlify_enabled()) - n = strjoin("\x1B]8;;", url, "\a", text, "\x1B]8;;\a"); - else - n = strdup(text); - if (!n) - return -ENOMEM; - - *ret = n; - return 0; -} - -int terminal_urlify_path(const char *path, const char *text, char **ret) { - _cleanup_free_ char *absolute = NULL; - struct utsname u; - const char *url; - int r; - - assert(path); - - /* Much like terminal_urlify() above, but takes a file system path as input - * and turns it into a proper file:// URL first. */ - - if (isempty(path)) - return -EINVAL; - - if (isempty(text)) - text = path; - - if (!urlify_enabled()) { - char *n; - - n = strdup(text); - if (!n) - return -ENOMEM; - - *ret = n; - return 0; - } - - if (uname(&u) < 0) - return -errno; - - if (!path_is_absolute(path)) { - r = path_make_absolute_cwd(path, &absolute); - if (r < 0) - return r; - - path = absolute; - } - - /* As suggested by https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda, let's include the local - * hostname here. Note that we don't use gethostname_malloc() or gethostname_strict() since we are interested - * in the raw string the kernel has set, whatever it may be, under the assumption that terminals are not overly - * careful with validating the strings either. */ - - url = strjoina("file://", u.nodename, path); - - return terminal_urlify(url, text, ret); -} - -int terminal_urlify_man(const char *page, const char *section, char **ret) { - const char *url, *text; - - url = strjoina("man:", page, "(", section, ")"); - text = strjoina(page, "(", section, ") man page"); - - return terminal_urlify(url, text, ret); -} - -static int cat_file(const char *filename, bool newline) { - _cleanup_fclose_ FILE *f = NULL; - _cleanup_free_ char *urlified = NULL; - int r; - - f = fopen(filename, "re"); - if (!f) - return -errno; - - r = terminal_urlify_path(filename, NULL, &urlified); - if (r < 0) - return r; - - printf("%s%s# %s%s\n", - newline ? "\n" : "", - ansi_highlight_blue(), - urlified, - ansi_normal()); - fflush(stdout); - - for (;;) { - _cleanup_free_ char *line = NULL; - - r = read_line(f, LONG_LINE_MAX, &line); - if (r < 0) - return log_error_errno(r, "Failed to read \"%s\": %m", filename); - if (r == 0) - break; - - puts(line); - } - - return 0; -} - -int cat_files(const char *file, char **dropins, CatFlags flags) { - char **path; - int r; - - if (file) { - r = cat_file(file, false); - if (r == -ENOENT && (flags & CAT_FLAGS_MAIN_FILE_OPTIONAL)) - printf("%s# config file %s not found%s\n", - ansi_highlight_magenta(), - file, - ansi_normal()); - else if (r < 0) - return log_warning_errno(r, "Failed to cat %s: %m", file); - } - - STRV_FOREACH(path, dropins) { - r = cat_file(*path, file || path != dropins); - if (r < 0) - return log_warning_errno(r, "Failed to cat %s: %m", *path); - } - - return 0; -} - -void print_separator(void) { - - /* Outputs a separator line that resolves to whitespace when copied from the terminal. We do that by outputting - * one line filled with spaces with ANSI underline set, followed by a second (empty) line. */ - - if (underline_enabled()) { - size_t i, c; - - c = columns(); - - flockfile(stdout); - fputs_unlocked(ANSI_UNDERLINE, stdout); - - for (i = 0; i < c; i++) - fputc_unlocked(' ', stdout); - - fputs_unlocked(ANSI_NORMAL "\n\n", stdout); - funlockfile(stdout); - } else - fputs("\n\n", stdout); -} diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index 436951be98..2d64afaee6 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -154,15 +154,3 @@ int open_terminal_in_namespace(pid_t pid, const char *name, int mode); int vt_default_utf8(void); int vt_reset_keyboard(int fd); - -int terminal_urlify(const char *url, const char *text, char **ret); -int terminal_urlify_path(const char *path, const char *text, char **ret); -int terminal_urlify_man(const char *page, const char *section, char **ret); - -typedef enum CatFlags { - CAT_FLAGS_MAIN_FILE_OPTIONAL = 1 << 0, -} CatFlags; - -int cat_files(const char *file, char **dropins, CatFlags flags); - -void print_separator(void); |