1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-11 09:18:07 +03:00

socket: add new Symlinks= option for socket units

With Symlinks= we can manage one or more symlinks to AF_UNIX or FIFO
nodes in the file system, with the same lifecycle as the socket itself.

This has two benefits: first, this allows us to remove /dev/log and
/dev/initctl from /dev, thus leaving only symlinks, device nodes and
directories in the /dev tree. More importantly however, this allows us
to move /dev/log out of /dev, while still making it accessible there, so
that PrivateDevices= can provide /dev/log too.
This commit is contained in:
Lennart Poettering 2014-06-04 16:19:00 +02:00
parent e9fc29f4ec
commit 811ba7a0e2
7 changed files with 160 additions and 16 deletions

View File

@ -738,17 +738,35 @@
removed when it is stopped. This
applies to AF_UNIX sockets in the file
system, POSIX message queues as well
as FIFOs. Normally it should not be
necessary to use this option, and is
not recommended as services might
continue to run after the socket unit
has been terminated and it should
still be possible to communicate with
them via their file system
node. Defaults to
as FIFOs, as well as any symlinks to
them configured with
<varname>Symlinks=</varname>. Normally
it should not be necessary to use this
option, and is not recommended as
services might continue to run after
the socket unit has been terminated
and it should still be possible to
communicate with them via their file
system node. Defaults to
off.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Symlinks=</varname></term>
<listitem><para>Takes a list of file
system paths. The specified paths will
be created as symlinks to the AF_UNIX
socket path or FIFO path of this
socket unit. If this setting is used
only one AF_UNIX socket in the file
system or one FIFO may be configured
for the socket unit. Use this option
to manage one or more symlinked alias
names for a socket, binding their
lifecycle together. Defaults to the
empty list.</para></listitem>
</varlistentry>
</variablelist>
<para>Check

View File

@ -108,6 +108,7 @@ const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_PROPERTY("PassSecurity", "b", bus_property_get_bool, offsetof(Socket, pass_sec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RemoveOnStop", "b", bus_property_get_bool, offsetof(Socket, remove_on_stop), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Listen", "a(ss)", property_get_listen, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Symlinks", "as", NULL, offsetof(Socket, symlinks), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Mark", "i", bus_property_get_int, offsetof(Socket, mark), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MaxConnections", "u", bus_property_get_unsigned, offsetof(Socket, max_connections), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MessageQueueMaxMessages", "x", bus_property_get_long, offsetof(Socket, mq_maxmsg), SD_BUS_VTABLE_PROPERTY_CONST),

View File

@ -243,6 +243,7 @@ Socket.ReusePort, config_parse_bool, 0,
Socket.MessageQueueMaxMessages, config_parse_long, 0, offsetof(Socket, mq_maxmsg)
Socket.MessageQueueMessageSize, config_parse_long, 0, offsetof(Socket, mq_msgsize)
Socket.RemoveOnStop, config_parse_bool, 0, offsetof(Socket, remove_on_stop)
Socket.Symlinks, config_parse_unit_path_strv_printf, 0, offsetof(Socket, symlinks)
Socket.Service, config_parse_socket_service, 0, 0
m4_ifdef(`HAVE_SMACK',
`Socket.SmackLabel, config_parse_string, 0, offsetof(Socket, smack)

View File

@ -197,8 +197,8 @@ int config_parse_unit_path_printf(const char *unit,
void *data,
void *userdata) {
Unit *u = userdata;
_cleanup_free_ char *k = NULL;
Unit *u = userdata;
int r;
assert(filename);
@ -207,12 +207,69 @@ int config_parse_unit_path_printf(const char *unit,
assert(u);
r = unit_full_printf(u, rvalue, &k);
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, -r,
"Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
return 0;
}
return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype,
k ? k : rvalue, data, userdata);
return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
}
int config_parse_unit_path_strv_printf(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
char *w, *state, ***x = data;
Unit *u = userdata;
size_t l;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(u);
FOREACH_WORD_QUOTED(w, l, rvalue, state) {
_cleanup_free_ char *k = NULL;
char t[l+1];
memcpy(t, w, l);
t[l] = 0;
r = unit_full_printf(u, t, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
return 0;
}
if (!utf8_is_valid(k)) {
log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
return 0;
}
if (!path_is_absolute(k)) {
log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
return 0;
}
path_kill_slashes(k);
r = strv_push(x, k);
if (r < 0)
return log_oom();
k = NULL;
}
return 0;
}
int config_parse_socket_listen(const char *unit,

View File

@ -34,6 +34,7 @@ int config_parse_unit_deps(const char *unit, const char *filename, unsigned line
int config_parse_unit_string_printf(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_strv_printf(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_path_printf(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_path_strv_printf(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_documentation(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_socket_listen(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_socket_bind(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);

View File

@ -145,6 +145,8 @@ static void socket_done(Unit *u) {
free(s->smack_ip_in);
free(s->smack_ip_out);
strv_free(s->symlinks);
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
}
@ -355,6 +357,39 @@ static int socket_add_extras(Socket *s) {
return 0;
}
static const char *socket_find_symlink_target(Socket *s) {
const char *found = NULL;
SocketPort *p;
LIST_FOREACH(port, p, s->ports) {
const char *f = NULL;
switch (p->type) {
case SOCKET_FIFO:
f = p->path;
break;
case SOCKET_SOCKET:
if (p->address.sockaddr.un.sun_path[0] != 0)
f = p->address.sockaddr.un.sun_path;
break;
default:
break;
}
if (f) {
if (found)
return NULL;
found = f;
}
}
return found;
}
static int socket_verify(Socket *s) {
assert(s);
@ -387,6 +422,11 @@ static int socket_verify(Socket *s) {
return -EINVAL;
}
if (!strv_isempty(s->symlinks) && !socket_find_symlink_target(s)) {
log_error_unit(UNIT(s)->id, "%s has symlinks set but none or more than one node in the file system. Refusing.", UNIT(s)->id);
return -EINVAL;
}
return 0;
}
@ -692,6 +732,7 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) {
static void socket_close_fds(Socket *s) {
SocketPort *p;
char **i;
assert(s);
@ -732,6 +773,10 @@ static void socket_close_fds(Socket *s) {
}
}
}
if (s->remove_on_stop)
STRV_FOREACH(i, s->symlinks)
unlink(*i);
}
static void socket_apply_socket_options(Socket *s, int fd) {
@ -915,7 +960,8 @@ static int special_address_create(
assert(path);
assert(_fd);
if ((fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) {
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW);
if (fd < 0) {
r = -errno;
goto fail;
}
@ -968,7 +1014,6 @@ static int mq_address_create(
/* Include the original umask in our mask */
umask(~mq_mode | old_mask);
fd = mq_open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_CREAT, mq_mode, attr);
umask(old_mask);
@ -998,6 +1043,22 @@ fail:
return r;
}
static int socket_symlink(Socket *s) {
const char *p;
char **i;
assert(s);
p = socket_find_symlink_target(s);
if (!p)
return 0;
STRV_FOREACH(i, s->symlinks)
symlink(p, *i);
return 0;
}
static int socket_open_fds(Socket *s) {
SocketPort *p;
int r;
@ -1045,6 +1106,7 @@ static int socket_open_fds(Socket *s) {
p->fd = r;
socket_apply_socket_options(s, p->fd);
socket_symlink(s);
} else if (p->type == SOCKET_SPECIAL) {
@ -1065,6 +1127,8 @@ static int socket_open_fds(Socket *s) {
goto rollback;
socket_apply_fifo_options(s, p->fd);
socket_symlink(s);
} else if (p->type == SOCKET_MQUEUE) {
r = mq_address_create(

View File

@ -125,6 +125,8 @@ struct Socket {
SocketResult result;
char **symlinks;
bool accept;
bool remove_on_stop;