* add dbus call to convert snapshot ino target
-* make use of TIOCVHANGUP
+* move nss-myhostname into systemd
+
+* figure out a standard place to configure timezone name, inform myllynen@redhat.com
+
+* add dbus call to convert snapshot into target
+
+* make use of TIOCVHANGUP to revoke access to tty before we spawn a getty on it
+
+* release VT before we spawn a getty on it to entirely clear scrollback buffer
+ https://bugzilla.redhat.com/show_bug.cgi?id=701704
* move /selinux to /sys/fs/selinux
* add prefix match to sysctl, tmpfiles, ...
-* Add ConditionPathExists= checks to binfmt automount units, to avoid
- installing the automount point if the directory does not exist.
-
* drop /.readahead on bigger upgrades with yum
* add inode stat() check to readahead to suppress preloading changed files
-* POSIX mqueue support in .socket units
-
* allow list of pathes in config_parse_condition_path()
* introduce dbus calls for enabling/disabling a service
<refname>sd_is_socket</refname>
<refname>sd_is_socket_inet</refname>
<refname>sd_is_socket_unix</refname>
+ <refname>sd_is_mq</refname>
<refpurpose>Check the type of a file descriptor</refpurpose>
</refnamediv>
<paramdef>size_t <parameter>length</parameter></paramdef>
</funcprototype>
+ <funcprototype>
+ <funcdef>int <function>sd_is_mq</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>const char *<parameter>path</parameter></paramdef>
+ </funcprototype>
+
</funcsynopsis>
</refsynopsisdiv>
address, including the initial 0 byte and set
<parameter>path</parameter> to the initial 0 byte of
the socket address.</para>
+
+ <para><function>sd_is_mq()</function> may be called to
+ check whether the specified file descriptor refers to
+ a POSIX message queue. If the
+ <parameter>path</parameter> parameter is not NULL, it
+ is checked whether the message queue is bound to the
+ specified name.</para>
</refsect1>
<refsect1>
directive above.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>ListenMessageQueue=</varname></term>
+ <listitem><para>Specifies a POSIX
+ message queue name to listen on. This
+ expects a valid message queue name
+ (i.e. beginning with /). Behaviour
+ otherwise is very similar to the
+ <varname>ListenFIFO=</varname>
+ directive above. On Linux message
+ queue descriptors are actually file
+ descriptors and can be inherited
+ between processes.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>BindIPv6Only=</varname></term>
<listitem><para>Takes a one of
for details.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>MessageQueueMaxMessages=</varname>,
+ <varname>MessageQueueMessageSize=</varname></term>
+ <listitem><para>These two settings
+ take integer values and control the
+ mq_maxmsg resp. mq_msgsize field when
+ creating the message queue. Note that
+ either none or both of these variables
+ need to be set. See
+ <citerefentry><refentrytitle>mq_setattr</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ for details.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>FreeBind=</varname></term>
<listitem><para>Takes a boolean
return 0;
}
+int config_parse_long(
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ long *i = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if ((r = safe_atoli(rvalue, i)) < 0) {
+ log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
+ return r;
+ }
+
+ return 0;
+}
+
int config_parse_uint64(
const char *filename,
unsigned line,
/* Generic parsers */
int config_parse_int(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unsigned(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_long(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_uint64(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_size(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_bool(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
return 0;
}
+int bus_property_append_long(DBusMessageIter *i, const char *property, void *data) {
+ uint64_t u;
+
+ assert(i);
+ assert(property);
+ assert(data);
+
+ u = (int64_t) *(long*) data;
+
+ if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT64, &u))
+ return -ENOMEM;
+
+ return 0;
+}
+
const char *bus_errno_to_dbus(int error) {
switch(error) {
int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data);
int bus_property_append_size(DBusMessageIter *i, const char *property, void *data);
int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data);
+int bus_property_append_long(DBusMessageIter *i, const char *property, void *data);
#define bus_property_append_int bus_property_append_int32
#define bus_property_append_pid bus_property_append_uint32
{ "org.freedesktop.systemd1.Socket", "MaxConnections", bus_property_append_unsigned, "u", &u->socket.max_connections },
{ "org.freedesktop.systemd1.Socket", "NConnections", bus_property_append_unsigned, "u", &u->socket.n_connections },
{ "org.freedesktop.systemd1.Socket", "NAccepted", bus_property_append_unsigned, "u", &u->socket.n_accepted },
+ { "org.freedesktop.systemd1.Socket", "MessageQueueMaxMessages", bus_property_append_long,"t", &u->socket.mq_maxmsg },
+ { "org.freedesktop.systemd1.Socket", "MessageQueueMessageSize", bus_property_append_long,"t", &u->socket.mq_msgsize },
{ NULL, NULL, NULL, NULL, NULL }
};
path_kill_slashes(p->path);
+ } else if (streq(lvalue, "ListenMessageQueue")) {
+
+ p->type = SOCKET_MQUEUE;
+
+ if (!(p->path = strdup(rvalue))) {
+ free(p);
+ return -ENOMEM;
+ }
+
+ path_kill_slashes(p->path);
+
} else if (streq(lvalue, "ListenNetlink")) {
p->type = SOCKET_SOCKET;
{ "ListenFIFO", config_parse_listen, 0, &u->socket, "Socket" },
{ "ListenNetlink", config_parse_listen, 0, &u->socket, "Socket" },
{ "ListenSpecial", config_parse_listen, 0, &u->socket, "Socket" },
+ { "ListenMessageQueue", config_parse_listen, 0, &u->socket, "Socket" },
{ "BindIPv6Only", config_parse_socket_bind, 0, &u->socket, "Socket" },
{ "Backlog", config_parse_unsigned, 0, &u->socket.backlog, "Socket" },
{ "BindToDevice", config_parse_bindtodevice, 0, &u->socket, "Socket" },
{ "PipeSize", config_parse_size, 0, &u->socket.pipe_size, "Socket" },
{ "FreeBind", config_parse_bool, 0, &u->socket.free_bind, "Socket" },
{ "TCPCongestion", config_parse_string, 0, &u->socket.tcp_congestion, "Socket" },
+ { "MessageQueueMaxMessages", config_parse_long, 0, &u->socket.mq_maxmsg, "Socket" },
+ { "MessageQueueMessageSize", config_parse_long, 0, &u->socket.mq_msgsize, "Socket" },
{ "Service", config_parse_socket_service, 0, &u->socket, "Socket" },
EXEC_CONTEXT_CONFIG_ITEMS(u->socket.exec_context, "Socket"),
#include <stdarg.h>
#include <stdio.h>
#include <stddef.h>
+#include <limits.h>
+
+#if defined(__linux__)
+#include <mqueue.h>
+#endif
#include "sd-daemon.h"
return 1;
}
+int sd_is_mq(int fd, const char *path) {
+#if !defined(__linux__)
+ return 0;
+#else
+ struct mq_attr attr;
+
+ if (fd < 0)
+ return -EINVAL;
+
+ if (mq_getattr(fd, &attr) < 0)
+ return -errno;
+
+ if (path) {
+ char fpath[PATH_MAX];
+ struct stat a, b;
+
+ if (path[0] != '/')
+ return -EINVAL;
+
+ if (fstat(fd, &a) < 0)
+ return -errno;
+
+ strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
+ fpath[sizeof(fpath)-1] = 0;
+
+ if (stat(fpath, &b) < 0)
+ return -errno;
+
+ if (a.st_dev != b.st_dev ||
+ a.st_ino != b.st_ino)
+ return 0;
+ }
+
+ return 1;
+#endif
+}
+
int sd_notify(int unset_environment, const char *state) {
#if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC)
return 0;
*/
int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) _sd_hidden_;
+/*
+ Helper call for identifying a passed file descriptor. Returns 1 if
+ the file descriptor is a POSIX Message Queue of the specified name,
+ 0 otherwise. If path is NULL a message queue name check is not
+ done. Returns a negative errno style error code on failure.
+*/
+int sd_is_mq(int fd, const char *path) _sd_hidden_;
+
/*
Informs systemd about changed daemon state. This takes a number of
newline separated environment-style variable assignments in a
#include <sys/epoll.h>
#include <signal.h>
#include <arpa/inet.h>
+#include <mqueue.h>
#include "unit.h"
#include "socket.h"
if (p->type == SOCKET_SOCKET) {
if (socket_address_needs_mount(&p->address, prefix))
return true;
- } else {
- assert(p->type == SOCKET_FIFO || p->type == SOCKET_SPECIAL);
+ } else if (p->type == SOCKET_FIFO || p->type == SOCKET_SPECIAL) {
if (path_startswith(p->path, prefix))
return true;
}
"%sMark: %i\n",
prefix, s->mark);
+ if (s->mq_maxmsg > 0)
+ fprintf(f,
+ "%sMessageQueueMaxMessages: %li\n",
+ prefix, s->mq_maxmsg);
+
+ if (s->mq_msgsize > 0)
+ fprintf(f,
+ "%sMessageQueueMessageSize: %li\n",
+ prefix, s->mq_msgsize);
+
LIST_FOREACH(port, p, s->ports) {
if (p->type == SOCKET_SOCKET) {
free(k);
} else if (p->type == SOCKET_SPECIAL)
fprintf(f, "%sListenSpecial: %s\n", prefix, p->path);
+ else if (p->type == SOCKET_MQUEUE)
+ fprintf(f, "%sListenMessageQueue: %s\n", prefix, p->path);
else
fprintf(f, "%sListenFIFO: %s\n", prefix, p->path);
}
return r;
}
+static int mq_address_create(
+ const char *path,
+ mode_t mq_mode,
+ long maxmsg,
+ long msgsize,
+ int *_fd) {
+
+ int fd = -1, r = 0;
+ struct stat st;
+ mode_t old_mask;
+ struct mq_attr _attr, *attr = NULL;
+
+ assert(path);
+ assert(_fd);
+
+ if (maxmsg > 0 && msgsize > 0) {
+ zero(_attr);
+ _attr.mq_flags = O_NONBLOCK;
+ _attr.mq_maxmsg = maxmsg;
+ _attr.mq_msgsize = msgsize;
+ attr = &_attr;
+ }
+
+ /* Enforce the right access mode for the mq */
+ old_mask = umask(~ mq_mode);
+
+ /* 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);
+
+ if (fd < 0 && errno != EEXIST) {
+ r = -errno;
+ goto fail;
+ }
+
+ if (fstat(fd, &st) < 0) {
+ r = -errno;
+ goto fail;
+ }
+
+ if ((st.st_mode & 0777) != (mq_mode & ~old_mask) ||
+ st.st_uid != getuid() ||
+ st.st_gid != getgid()) {
+
+ r = -EEXIST;
+ goto fail;
+ }
+
+ *_fd = fd;
+ return 0;
+
+fail:
+ if (fd >= 0)
+ close_nointr_nofail(fd);
+
+ return r;
+}
+
static int socket_open_fds(Socket *s) {
SocketPort *p;
int r;
goto rollback;
socket_apply_fifo_options(s, p->fd);
+ } else if (p->type == SOCKET_MQUEUE) {
+ if ((r = mq_address_create(
+ p->path,
+ s->socket_mode,
+ s->mq_maxmsg,
+ s->mq_msgsize,
+ &p->fd)) < 0)
+ goto rollback;
} else
assert_not_reached("Unknown port type");
}
SOCKET_SOCKET,
SOCKET_FIFO,
SOCKET_SPECIAL,
+ SOCKET_MQUEUE,
_SOCKET_FIFO_MAX,
_SOCKET_FIFO_INVALID = -1
} SocketType;
size_t pipe_size;
char *bind_to_device;
char *tcp_congestion;
+ long mq_maxmsg;
+ long mq_msgsize;
};
/* Called from the service code when collecting fds */