mirror of
https://github.com/systemd/systemd
synced 2024-10-15 20:45:09 +00:00
Merge pull request #8767 from poettering/urlify-all-things
try to generate clickable links in our output if we can
This commit is contained in:
commit
65a2718af5
|
@ -855,6 +855,15 @@
|
|||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>$SYSTEMD_URLIFY</varname></term>
|
||||
|
||||
<listitem><para>The value must be a boolean. Controls whether clickable links should be generated in the output
|
||||
for terminal emulators supporting this. This can be specified to override the decision that
|
||||
<command>systemd</command> makes based on <varname>$TERM</varname> and other conditions.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>$LISTEN_PID</varname></term>
|
||||
<term><varname>$LISTEN_FDS</varname></term>
|
||||
|
|
|
@ -8,21 +8,22 @@
|
|||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/time.h>
|
||||
#include <linux/kd.h>
|
||||
#include <linux/tiocl.h>
|
||||
#include <linux/vt.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
@ -34,6 +35,7 @@
|
|||
#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"
|
||||
|
@ -1269,3 +1271,94 @@ 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 properl
|
||||
* 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);
|
||||
}
|
||||
|
|
|
@ -156,3 +156,6 @@ 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);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "bus-util.h"
|
||||
#include "hostname-util.h"
|
||||
#include "spawn-polkit-agent.h"
|
||||
#include "terminal-util.h"
|
||||
#include "util.h"
|
||||
#include "verbs.h"
|
||||
|
||||
|
@ -44,6 +45,7 @@ typedef struct StatusInfo {
|
|||
const char *os_cpe_name;
|
||||
const char *virtualization;
|
||||
const char *architecture;
|
||||
const char *home_url;
|
||||
} StatusInfo;
|
||||
|
||||
static void print_status_info(StatusInfo *i) {
|
||||
|
@ -87,8 +89,17 @@ static void print_status_info(StatusInfo *i) {
|
|||
if (!isempty(i->virtualization))
|
||||
printf(" Virtualization: %s\n", i->virtualization);
|
||||
|
||||
if (!isempty(i->os_pretty_name))
|
||||
printf(" Operating System: %s\n", i->os_pretty_name);
|
||||
if (!isempty(i->os_pretty_name)) {
|
||||
_cleanup_free_ char *formatted = NULL;
|
||||
const char *t = i->os_pretty_name;
|
||||
|
||||
if (i->home_url) {
|
||||
if (terminal_urlify(i->home_url, i->os_pretty_name, &formatted) >= 0)
|
||||
t = formatted;
|
||||
}
|
||||
|
||||
printf(" Operating System: %s\n", t);
|
||||
}
|
||||
|
||||
if (!isempty(i->os_cpe_name))
|
||||
printf(" CPE OS Name: %s\n", i->os_cpe_name);
|
||||
|
@ -141,6 +152,7 @@ static int show_all_names(sd_bus *bus, sd_bus_error *error) {
|
|||
{ "KernelRelease", "s", NULL, offsetof(StatusInfo, kernel_release) },
|
||||
{ "OperatingSystemPrettyName", "s", NULL, offsetof(StatusInfo, os_pretty_name) },
|
||||
{ "OperatingSystemCPEName", "s", NULL, offsetof(StatusInfo, os_cpe_name) },
|
||||
{ "HomeURL", "s", NULL, offsetof(StatusInfo, home_url) },
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ enum {
|
|||
PROP_KERNEL_VERSION,
|
||||
PROP_OS_PRETTY_NAME,
|
||||
PROP_OS_CPE_NAME,
|
||||
PROP_HOME_URL,
|
||||
_PROP_MAX
|
||||
};
|
||||
|
||||
|
@ -100,6 +101,7 @@ static int context_read_data(Context *c) {
|
|||
r = parse_env_file("/etc/os-release", NEWLINE,
|
||||
"PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
|
||||
"CPE_NAME", &c->data[PROP_OS_CPE_NAME],
|
||||
"HOME_URL", &c->data[PROP_HOME_URL],
|
||||
NULL);
|
||||
if (r == -ENOENT)
|
||||
r = parse_env_file("/usr/lib/os-release", NEWLINE,
|
||||
|
@ -640,6 +642,7 @@ static const sd_bus_vtable hostname_vtable[] = {
|
|||
SD_BUS_PROPERTY("KernelVersion", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_VERSION, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("OperatingSystemCPEName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("HomeURL", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOME_URL, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_METHOD("SetHostname", "sb", NULL, method_set_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("SetStaticHostname", "sb", NULL, method_set_static_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("SetPrettyHostname", "sb", NULL, method_set_pretty_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
|
|
@ -3954,11 +3954,11 @@ static void print_status_info(
|
|||
UnitStatusInfo *i,
|
||||
bool *ellipsized) {
|
||||
|
||||
ExecStatusInfo *p;
|
||||
char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1, since2[FORMAT_TIMESTAMP_MAX], *s2;
|
||||
const char *active_on, *active_off, *on, *off, *ss;
|
||||
_cleanup_free_ char *formatted_path = NULL;
|
||||
ExecStatusInfo *p;
|
||||
usec_t timestamp;
|
||||
char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
|
||||
char since2[FORMAT_TIMESTAMP_MAX], *s2;
|
||||
const char *path;
|
||||
char **t, **t2;
|
||||
int r;
|
||||
|
@ -3993,7 +3993,9 @@ static void print_status_info(
|
|||
} else
|
||||
on = off = "";
|
||||
|
||||
path = i->source_path ? i->source_path : i->fragment_path;
|
||||
path = i->source_path ?: i->fragment_path;
|
||||
if (path && terminal_urlify_path(path, NULL, &formatted_path) >= 0)
|
||||
path = formatted_path;
|
||||
|
||||
if (i->load_error != 0)
|
||||
printf(" Loaded: %s%s%s (Reason: %s)\n",
|
||||
|
@ -4021,6 +4023,9 @@ static void print_status_info(
|
|||
char ** dropin;
|
||||
|
||||
STRV_FOREACH(dropin, i->dropin_paths) {
|
||||
_cleanup_free_ char *dropin_formatted = NULL;
|
||||
const char *df;
|
||||
|
||||
if (!dir || last) {
|
||||
printf(dir ? " " :
|
||||
" Drop-In: ");
|
||||
|
@ -4040,7 +4045,12 @@ static void print_status_info(
|
|||
|
||||
last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
|
||||
|
||||
printf("%s%s", basename(*dropin), last ? "\n" : ", ");
|
||||
if (terminal_urlify_path(*dropin, basename(*dropin), &dropin_formatted) >= 0)
|
||||
df = dropin_formatted;
|
||||
else
|
||||
df = *dropin;
|
||||
|
||||
printf("%s%s", df, last ? "\n" : ", ");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4143,8 +4153,17 @@ static void print_status_info(
|
|||
if (i->what)
|
||||
printf(" What: %s\n", i->what);
|
||||
|
||||
STRV_FOREACH(t, i->documentation)
|
||||
printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", *t);
|
||||
STRV_FOREACH(t, i->documentation) {
|
||||
_cleanup_free_ char *formatted = NULL;
|
||||
const char *q;
|
||||
|
||||
if (terminal_urlify(*t, NULL, &formatted) >= 0)
|
||||
q = formatted;
|
||||
else
|
||||
q = *t;
|
||||
|
||||
printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", q);
|
||||
}
|
||||
|
||||
STRV_FOREACH_PAIR(t, t2, i->listen)
|
||||
printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "log.h"
|
||||
|
@ -63,12 +64,25 @@ static void test_read_one_char(void) {
|
|||
unlink(name);
|
||||
}
|
||||
|
||||
static void test_terminal_urlify(void) {
|
||||
_cleanup_free_ char *formatted = NULL;
|
||||
|
||||
assert_se(terminal_urlify("https://www.freedesktop.org/wiki/Software/systemd/", "systemd homepage", &formatted) >= 0);
|
||||
printf("Hey, considere visiting the %s right now! It is very good!\n", formatted);
|
||||
|
||||
formatted = mfree(formatted);
|
||||
|
||||
assert_se(terminal_urlify_path("/etc/fstab", "this link to your /etc/fstab", &formatted) >= 0);
|
||||
printf("Or click on %s to have a look at it!\n", formatted);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
test_default_term_for_tty();
|
||||
test_read_one_char();
|
||||
test_terminal_urlify();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue