[systemd-commits] 43 commits - configure.ac .gitignore Makefile.am man/systemd.exec.xml org.freedesktop.hostname1.xml org.freedesktop.locale1.xml org.freedesktop.timedate1.xml src/70-uaccess.rules src/71-seat.rules src/99-systemd.rules src/automount.c src/dbus.c src/dbus-common.c src/dbus-common.h src/dbus.h src/dbus-loop.c src/dbus-loop.h src/dbus-manager.c src/hostnamed.c src/localed.c src/logind-acl.c src/logind-acl.h src/logind.c src/logind-dbus.c src/logind-device.c src/logind-device.h src/logind.h src/logind-seat.c src/logind-seat-dbus.c src/logind-seat.h src/logind-session.c src/logind-session-dbus.c src/logind-session.h src/logind-user.c src/logind-user-dbus.c src/logind-user.h src/main.c src/manager.c src/manager.h src/mount.c src/org.freedesktop.locale1.conf src/org.freedesktop.locale1.policy src/org.freedesktop.locale1.service src/org.freedesktop.login1.conf src/org.freedesktop.login1.policy src/org.freedesktop.login1.service src/org.freedesktop.timedate1.conf src/org.freed esktop.timedate1.policy src/org.freedesktop.timedate1.service src/pam-module.c src/path.c src/polkit.c src/polkit.h src/service.c src/service.h src/shutdownd.c src/socket.c src/swap.c src/timedated.c src/uaccess.c src/unit.c src/unit.h src/user-sessions.c src/util.c src/util.h TODO units/.gitignore units/systemd-localed.service.in units/systemd-logind.service.in units/systemd-timedated.service.in
Lennart Poettering
lennart at kemper.freedesktop.org
Mon Jun 27 04:48:16 PDT 2011
.gitignore | 4
Makefile.am | 136 +++-
TODO | 20
configure.ac | 38 +
man/systemd.exec.xml | 2
org.freedesktop.hostname1.xml | 26
org.freedesktop.locale1.xml | 11
org.freedesktop.timedate1.xml | 22
src/70-uaccess.rules | 72 ++
src/71-seat.rules | 20
src/99-systemd.rules | 2
src/automount.c | 2
src/dbus-common.c | 135 +++-
src/dbus-common.h | 10
src/dbus-loop.c | 263 ++++++++
src/dbus-loop.h | 30
src/dbus-manager.c | 62 +
src/dbus.c | 146 +---
src/dbus.h | 4
src/hostnamed.c | 253 ++------
src/localed.c | 612 +++++++++++++++++++
src/logind-acl.c | 282 +++++++++
src/logind-acl.h | 40 +
src/logind-dbus.c | 1006 ++++++++++++++++++++++++++++++++
src/logind-device.c | 85 ++
src/logind-device.h | 48 +
src/logind-seat-dbus.c | 403 ++++++++++++
src/logind-seat.c | 491 +++++++++++++++
src/logind-seat.h | 81 ++
src/logind-session-dbus.c | 454 ++++++++++++++
src/logind-session.c | 830 ++++++++++++++++++++++++++
src/logind-session.h | 111 +++
src/logind-user-dbus.c | 387 ++++++++++++
src/logind-user.c | 515 ++++++++++++++++
src/logind-user.h | 85 ++
src/logind.c | 1064 ++++++++++++++++++++++++++++++++++
src/logind.h | 135 ++++
src/main.c | 7
src/manager.c | 47 -
src/manager.h | 2
src/mount.c | 16
src/org.freedesktop.locale1.conf | 27
src/org.freedesktop.locale1.policy | 29
src/org.freedesktop.locale1.service | 12
src/org.freedesktop.login1.conf | 27
src/org.freedesktop.login1.policy | 29
src/org.freedesktop.login1.service | 12
src/org.freedesktop.timedate1.conf | 27
src/org.freedesktop.timedate1.policy | 50 +
src/org.freedesktop.timedate1.service | 12
src/pam-module.c | 627 +++++---------------
src/path.c | 2
src/polkit.c | 190 ++++++
src/polkit.h | 35 +
src/service.c | 52 +
src/service.h | 1
src/shutdownd.c | 2
src/socket.c | 6
src/swap.c | 6
src/timedated.c | 615 +++++++++++++++++++
src/uaccess.c | 87 ++
src/unit.c | 30
src/unit.h | 5
src/user-sessions.c | 2
src/util.c | 757 ++++++++++++++++++------
src/util.h | 36 -
units/.gitignore | 3
units/systemd-localed.service.in | 17
units/systemd-logind.service.in | 18
units/systemd-timedated.service.in | 17
70 files changed, 9692 insertions(+), 1000 deletions(-)
New commits:
commit 18fa6b2705aaef42041942f47f013e426640b6a4
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon Jun 27 13:47:03 2011 +0200
dbus: send our finished signal when we are finished booting
diff --git a/TODO b/TODO
index d7c92e1..2700c7a 100644
--- a/TODO
+++ b/TODO
@@ -56,8 +56,6 @@ Features:
* add prefix match to sysctl, tmpfiles, ...
-* send out "finished" signal when we are finished booting
-
* drop /.readahead on bigger upgrades with yum
* add inode stat() check to readahead to suppress preloading changed files
diff --git a/src/dbus-manager.c b/src/dbus-manager.c
index cc2b4d0..b4e2f86 100644
--- a/src/dbus-manager.c
+++ b/src/dbus-manager.c
@@ -151,6 +151,12 @@
" <arg name=\"id\" type=\"u\"/>\n" \
" <arg name=\"job\" type=\"o\"/>\n" \
" <arg name=\"result\" type=\"s\"/>\n" \
+ " </signal>" \
+ " <signal name=\"StartupFinished\">\n" \
+ " <arg name=\"kernel\" type=\"t\"/>\n" \
+ " <arg name=\"initrd\" type=\"t\"/>\n" \
+ " <arg name=\"userspace\" type=\"t\"/>\n" \
+ " <arg name=\"total\" type=\"t\"/>\n" \
" </signal>"
#define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
diff --git a/src/dbus.c b/src/dbus.c
index 93a19a4..764c65c 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -1274,3 +1274,42 @@ int bus_fdset_add_all(Manager *m, FDSet *fds) {
return 0;
}
+
+void bus_broadcast_finished(
+ Manager *m,
+ usec_t kernel_usec,
+ usec_t initrd_usec,
+ usec_t userspace_usec,
+ usec_t total_usec) {
+
+ DBusMessage *message;
+
+ assert(m);
+
+ message = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished");
+ if (!message) {
+ log_error("Out of memory.");
+ return;
+ }
+
+ assert_cc(sizeof(usec_t) == sizeof(uint64_t));
+ if (!dbus_message_append_args(message,
+ DBUS_TYPE_UINT64, &kernel_usec,
+ DBUS_TYPE_UINT64, &initrd_usec,
+ DBUS_TYPE_UINT64, &userspace_usec,
+ DBUS_TYPE_UINT64, &total_usec,
+ DBUS_TYPE_INVALID)) {
+ log_error("Out of memory.");
+ goto finish;
+ }
+
+
+ if (bus_broadcast(m, message) < 0) {
+ log_error("Out of memory.");
+ goto finish;
+ }
+
+finish:
+ if (m)
+ dbus_message_unref(message);
+}
diff --git a/src/dbus.h b/src/dbus.h
index c47e782..bd539d0 100644
--- a/src/dbus.h
+++ b/src/dbus.h
@@ -43,6 +43,8 @@ bool bus_connection_has_subscriber(Manager *m, DBusConnection *c);
int bus_fdset_add_all(Manager *m, FDSet *fds);
+void bus_broadcast_finished(Manager *m, usec_t kernel_usec, usec_t initrd_usec, usec_t userspace_usec, usec_t total_usec);
+
#define BUS_CONNECTION_SUBSCRIBED(m, c) dbus_connection_get_data((c), (m)->subscribed_data_slot)
#define BUS_PENDING_CALL_NAME(m, p) dbus_pending_call_get_data((p), (m)->name_data_slot)
diff --git a/src/logind.h b/src/logind.h
index d512c3e..be8bb1d 100644
--- a/src/logind.h
+++ b/src/logind.h
@@ -37,7 +37,7 @@
* recreate VTs when disallocated
* spawn user systemd
* direct client API
- * D-Bus method: AttachDevice(seat, device);
+ * D-Bus method: AttachDevices(seat, devices[]);
* D-Bus method: SetLinger(user, bool b);
*
* non-local X11 server
diff --git a/src/manager.c b/src/manager.c
index 19172a2..0830e80 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -2899,6 +2899,7 @@ bool manager_unit_pending_inactive(Manager *m, const char *name) {
void manager_check_finished(Manager *m) {
char userspace[FORMAT_TIMESPAN_MAX], initrd[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX];
+ usec_t kernel_usec = 0, initrd_usec = 0, userspace_usec = 0, total_usec = 0;
assert(m);
@@ -2912,29 +2913,37 @@ void manager_check_finished(Manager *m) {
if (m->running_as == MANAGER_SYSTEM && detect_container(NULL) <= 0) {
+ userspace_usec = m->finish_timestamp.monotonic - m->startup_timestamp.monotonic;
+ total_usec = m->finish_timestamp.monotonic;
+
if (dual_timestamp_is_set(&m->initrd_timestamp)) {
+
+ kernel_usec = m->initrd_timestamp.monotonic;
+ initrd_usec = m->startup_timestamp.monotonic - m->initrd_timestamp.monotonic;
+
log_info("Startup finished in %s (kernel) + %s (initrd) + %s (userspace) = %s.",
- format_timespan(kernel, sizeof(kernel),
- m->initrd_timestamp.monotonic),
- format_timespan(initrd, sizeof(initrd),
- m->startup_timestamp.monotonic - m->initrd_timestamp.monotonic),
- format_timespan(userspace, sizeof(userspace),
- m->finish_timestamp.monotonic - m->startup_timestamp.monotonic),
- format_timespan(sum, sizeof(sum),
- m->finish_timestamp.monotonic));
- } else
+ format_timespan(kernel, sizeof(kernel), kernel_usec),
+ format_timespan(initrd, sizeof(initrd), initrd_usec),
+ format_timespan(userspace, sizeof(userspace), userspace_usec),
+ format_timespan(sum, sizeof(sum), total_usec));
+ } else {
+ kernel_usec = m->startup_timestamp.monotonic;
+ initrd_usec = 0;
+
log_info("Startup finished in %s (kernel) + %s (userspace) = %s.",
- format_timespan(kernel, sizeof(kernel),
- m->startup_timestamp.monotonic),
- format_timespan(userspace, sizeof(userspace),
- m->finish_timestamp.monotonic - m->startup_timestamp.monotonic),
- format_timespan(sum, sizeof(sum),
- m->finish_timestamp.monotonic));
- } else
+ format_timespan(kernel, sizeof(kernel), kernel_usec),
+ format_timespan(userspace, sizeof(userspace), userspace_usec),
+ format_timespan(sum, sizeof(sum), total_usec));
+ }
+ } else {
+ userspace_usec = initrd_usec = kernel_usec = 0;
+ total_usec = m->finish_timestamp.monotonic - m->startup_timestamp.monotonic;
+
log_debug("Startup finished in %s.",
- format_timespan(userspace, sizeof(userspace),
- m->finish_timestamp.monotonic - m->startup_timestamp.monotonic));
+ format_timespan(sum, sizeof(sum), total_usec));
+ }
+ bus_broadcast_finished(m, kernel_usec, initrd_usec, userspace_usec, total_usec);
}
void manager_run_generators(Manager *m) {
commit 3084a7c453680fac7bdca9cf76bde397ec6a67de
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Jun 24 23:52:02 2011 +0200
logind: add more necessary caps to the service
diff --git a/units/systemd-logind.service.in b/units/systemd-logind.service.in
index d4734c3..82a2c6a 100644
--- a/units/systemd-logind.service.in
+++ b/units/systemd-logind.service.in
@@ -14,5 +14,5 @@ Description=Login Service
ExecStart=@rootlibexecdir@/systemd-logind
Type=dbus
BusName=org.freedesktop.login1
-CapabilityBoundingSet=CAP_AUDIT_CONTROL CAP_CHOWN CAP_KILL
+CapabilityBoundingSet=CAP_AUDIT_CONTROL CAP_CHOWN CAP_KILL CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP_FOWNER
StandardOutput=syslog
commit ee8545b06c2325e5dca7afd9ea8dbc35342a7768
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Jun 24 23:51:49 2011 +0200
pam: fix up tty if it is actually a display
diff --git a/src/pam-module.c b/src/pam-module.c
index eba59f6..1658348 100644
--- a/src/pam-module.c
+++ b/src/pam-module.c
@@ -382,6 +382,16 @@ _public_ PAM_EXTERN int pam_sm_open_session(
remote_host = strempty(remote_host);
seat = strempty(seat);
+ if (strchr(tty, ':')) {
+ /* A tty with a colon is usually an X11 display, place
+ * there to show up in utmp. We rearrange things and
+ * don't pretend that an X display was a tty */
+
+ if (isempty(display))
+ display = tty;
+ tty = NULL;
+ }
+
type = !isempty(display) ? "x11" :
!isempty(tty) ? "tty" : "other";
commit a91e4e5337a46db3f0a4f1415c1b60285e5c33a3
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Jun 24 23:50:39 2011 +0200
logind: save/restore session type
diff --git a/src/logind-session.c b/src/logind-session.c
index 16d6c17..e71ff4f 100644
--- a/src/logind-session.c
+++ b/src/logind-session.c
@@ -136,6 +136,11 @@ int session_save(Session *s) {
s->remote,
s->kill_processes);
+ if (s->type >= 0)
+ fprintf(f,
+ "TYPE=%s\n",
+ session_type_to_string(s->type));
+
if (s->cgroup_path)
fprintf(f,
"CGROUP=%s\n",
@@ -210,7 +215,8 @@ int session_load(Session *s) {
*seat = NULL,
*vtnr = NULL,
*leader = NULL,
- *audit_id = NULL;
+ *audit_id = NULL,
+ *type = NULL;
int k, r;
@@ -228,6 +234,7 @@ int session_load(Session *s) {
"SERVICE", &s->service,
"VTNR", &vtnr,
"LEADER", &leader,
+ "TYPE", &type,
NULL);
if (r < 0)
@@ -272,6 +279,14 @@ int session_load(Session *s) {
}
}
+ if (type) {
+ SessionType t;
+
+ t = session_type_from_string(type);
+ if (t >= 0)
+ s->type = t;
+ }
+
finish:
free(remote);
free(kill_processes);
@@ -809,7 +824,7 @@ void session_add_to_gc_queue(Session *s) {
static const char* const session_type_table[_SESSION_TYPE_MAX] = {
[SESSION_TTY] = "tty",
[SESSION_X11] = "x11",
- [SESSION_OTHER] = "other"
+ [SESSION_UNSPECIFIED] = "unspecified"
};
DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
diff --git a/src/logind-session.h b/src/logind-session.h
index 7a8001e..72f85ca 100644
--- a/src/logind-session.h
+++ b/src/logind-session.h
@@ -31,9 +31,9 @@ typedef struct Session Session;
#include "logind-user.h"
typedef enum SessionType {
+ SESSION_UNSPECIFIED,
SESSION_TTY,
SESSION_X11,
- SESSION_OTHER,
_SESSION_TYPE_MAX,
_SESSION_TYPE_INVALID = -1
} SessionType;
commit 31b79c2b4a34961eefc3b3680704124d8490d105
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Jun 24 23:25:28 2011 +0200
logind: use pipe fd to detect when a session is dead
diff --git a/src/logind-dbus.c b/src/logind-dbus.c
index d48d68c..136f610 100644
--- a/src/logind-dbus.c
+++ b/src/logind-dbus.c
@@ -437,7 +437,9 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
goto fail;
}
- session->pipe_fd = pipe_fds[0];
+ r = session_set_pipe_fd(session, pipe_fds[0]);
+ if (r < 0)
+ goto fail;
pipe_fds[0] = -1;
if (s) {
diff --git a/src/logind-session.c b/src/logind-session.c
index 9278f30..16d6c17 100644
--- a/src/logind-session.c
+++ b/src/logind-session.c
@@ -22,6 +22,7 @@
#include <errno.h>
#include <string.h>
#include <unistd.h>
+#include <sys/epoll.h>
#include "logind-session.h"
#include "strv.h"
@@ -97,8 +98,7 @@ void session_free(Session *s) {
hashmap_remove(s->manager->sessions, s->id);
- if (s->pipe_fd >= 0)
- close_nointr_nofail(s->pipe_fd);
+ session_unset_pipe_fd(s);
free(s->state_file);
free(s);
@@ -729,6 +729,45 @@ void session_set_idle_hint(Session *s, bool b) {
"IdleSinceHintMonotonic\0");
}
+int session_set_pipe_fd(Session *s, int fd) {
+ struct epoll_event ev;
+ int r;
+
+ assert(s);
+ assert(fd >= 0);
+ assert(s->pipe_fd < 0);
+
+ r = hashmap_put(s->manager->pipe_fds, INT_TO_PTR(fd + 1), s);
+ if (r < 0)
+ return r;
+
+ zero(ev);
+ ev.events = 0;
+ ev.data.u32 = FD_PIPE_BASE + fd;
+
+ if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
+ assert_se(hashmap_remove(s->manager->pipe_fds, INT_TO_PTR(fd + 1)) == s);
+ return -errno;
+ }
+
+ s->pipe_fd = fd;
+ return 0;
+}
+
+void session_unset_pipe_fd(Session *s) {
+ assert(s);
+
+ if (s->pipe_fd < 0)
+ return;
+
+ assert_se(hashmap_remove(s->manager->pipe_fds, INT_TO_PTR(s->pipe_fd + 1)) == s);
+
+ assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->pipe_fd, NULL) == 0);
+
+ close_nointr_nofail(s->pipe_fd);
+ s->pipe_fd = -1;
+}
+
int session_check_gc(Session *s) {
int r;
diff --git a/src/logind-session.h b/src/logind-session.h
index 01c9504..7a8001e 100644
--- a/src/logind-session.h
+++ b/src/logind-session.h
@@ -91,6 +91,8 @@ int session_activate(Session *s);
bool session_is_active(Session *s);
int session_get_idle_hint(Session *s, dual_timestamp *t);
void session_set_idle_hint(Session *s, bool b);
+int session_set_pipe_fd(Session *s, int fd);
+void session_unset_pipe_fd(Session *s);
int session_start(Session *s);
int session_stop(Session *s);
int session_save(Session *s);
diff --git a/src/logind.c b/src/logind.c
index 2665ab9..2577320 100644
--- a/src/logind.c
+++ b/src/logind.c
@@ -33,12 +33,6 @@
#include "dbus-common.h"
#include "dbus-loop.h"
-enum {
- FD_UDEV,
- FD_CONSOLE,
- FD_BUS
-};
-
Manager *manager_new(void) {
Manager *m;
@@ -57,6 +51,7 @@ Manager *manager_new(void) {
m->sessions = hashmap_new(string_hash_func, string_compare_func);
m->users = hashmap_new(trivial_hash_func, trivial_compare_func);
m->cgroups = hashmap_new(string_hash_func, string_compare_func);
+ m->pipe_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
if (!m->devices || !m->seats || !m->sessions || !m->users) {
manager_free(m);
@@ -102,6 +97,7 @@ void manager_free(Manager *m) {
hashmap_free(m->devices);
hashmap_free(m->seats);
hashmap_free(m->cgroups);
+ hashmap_free(m->pipe_fds);
if (m->console_active_fd >= 0)
close_nointr_nofail(m->console_active_fd);
@@ -714,6 +710,19 @@ void manager_cgroup_notify_empty(Manager *m, const char *cgroup) {
free(p);
}
+static void manager_pipe_notify_eof(Manager *m, int fd) {
+ Session *s;
+
+ assert_se(m);
+ assert_se(fd >= 0);
+
+ assert_se(s = hashmap_get(m->pipe_fds, INT_TO_PTR(fd + 1)));
+ assert(s->pipe_fd == fd);
+ session_unset_pipe_fd(s);
+
+ session_add_to_gc_queue(s);
+}
+
static int manager_connect_bus(Manager *m) {
DBusError error;
int r;
@@ -1006,6 +1015,10 @@ int manager_run(Manager *m) {
case FD_BUS:
bus_loop_dispatch(m->bus_fd);
break;
+
+ default:
+ if (event.data.u32 >= FD_PIPE_BASE)
+ manager_pipe_notify_eof(m, event.data.u32 - FD_PIPE_BASE);
}
}
diff --git a/src/logind.h b/src/logind.h
index d8674e7..d512c3e 100644
--- a/src/logind.h
+++ b/src/logind.h
@@ -37,9 +37,8 @@
* recreate VTs when disallocated
* spawn user systemd
* direct client API
- * subscribe to fd HUP
* D-Bus method: AttachDevice(seat, device);
- * D-Bus method: PermitLinger(user, bool b);
+ * D-Bus method: SetLinger(user, bool b);
*
* non-local X11 server
* reboot/shutdown halt management
@@ -86,6 +85,14 @@ struct Manager {
unsigned long session_counter;
Hashmap *cgroups;
+ Hashmap *pipe_fds;
+};
+
+enum {
+ FD_UDEV,
+ FD_CONSOLE,
+ FD_BUS,
+ FD_PIPE_BASE
};
Manager *manager_new(void);
commit 094062918c50cd5a34f7b6510fe206bf78d7cc58
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Jun 24 22:55:51 2011 +0200
logind: fix set of capabilities
diff --git a/units/systemd-logind.service.in b/units/systemd-logind.service.in
index 52c4acf..d4734c3 100644
--- a/units/systemd-logind.service.in
+++ b/units/systemd-logind.service.in
@@ -14,4 +14,5 @@ Description=Login Service
ExecStart=@rootlibexecdir@/systemd-logind
Type=dbus
BusName=org.freedesktop.login1
-CapabilityBoundingSet=
+CapabilityBoundingSet=CAP_AUDIT_CONTROL CAP_CHOWN CAP_KILL
+StandardOutput=syslog
commit 21c390ccd1b4f7bc962c16549df929ad518a1d37
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Jun 24 22:55:39 2011 +0200
logind: properly handle if two session with identical loginuids are attempted to be created
diff --git a/src/logind-dbus.c b/src/logind-dbus.c
index 2bad549..d48d68c 100644
--- a/src/logind-dbus.c
+++ b/src/logind-dbus.c
@@ -314,9 +314,53 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
goto fail;
}
- if (hashmap_get(m->sessions, id)) {
- r = -EEXIST;
- goto fail;
+ session = hashmap_get(m->sessions, id);
+
+ if (session) {
+
+ /* Session already exists, client is probably
+ * something like "su" which changes uid but
+ * is still the same audit session */
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ /* Create a throw-away fd */
+ if (pipe(pipe_fds) < 0) {
+ r = -errno;
+ goto fail;
+ }
+
+ close_nointr_nofail(pipe_fds[0]);
+ pipe_fds[0] = -1;
+
+ p = session_bus_path(session);
+ if (!p) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ b = dbus_message_append_args(
+ reply,
+ DBUS_TYPE_STRING, &session->id,
+ DBUS_TYPE_OBJECT_PATH, &p,
+ DBUS_TYPE_STRING, &session->user->runtime_path,
+ DBUS_TYPE_UNIX_FD, &pipe_fds[1],
+ DBUS_TYPE_INVALID);
+ free(p);
+
+ if (!b) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ close_nointr_nofail(pipe_fds[1]);
+ *_reply = reply;
+
+ return 0;
}
} else {
diff --git a/src/logind.h b/src/logind.h
index 2b9b702..d8674e7 100644
--- a/src/logind.h
+++ b/src/logind.h
@@ -40,7 +40,6 @@
* subscribe to fd HUP
* D-Bus method: AttachDevice(seat, device);
* D-Bus method: PermitLinger(user, bool b);
- * properly handle if two sessions with the same loginuid are attempted to be created
*
* non-local X11 server
* reboot/shutdown halt management
diff --git a/src/pam-module.c b/src/pam-module.c
index dc7c001..eba59f6 100644
--- a/src/pam-module.c
+++ b/src/pam-module.c
@@ -457,10 +457,12 @@ _public_ PAM_EXTERN int pam_sm_open_session(
goto finish;
}
- r = pam_set_data(handle, "systemd.session-fd", INT_TO_PTR(session_fd+1), NULL);
- if (r != PAM_SUCCESS) {
- pam_syslog(handle, LOG_ERR, "Failed to install session fd.");
- return r;
+ if (session_fd >= 0) {
+ r = pam_set_data(handle, "systemd.session-fd", INT_TO_PTR(session_fd+1), NULL);
+ if (r != PAM_SUCCESS) {
+ pam_syslog(handle, LOG_ERR, "Failed to install session fd.");
+ return r;
+ }
}
session_fd = -1;
commit 0771475394887e3635e67196fa6f56486fa2126c
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Jun 24 20:46:22 2011 +0200
logind: when generating session ids with a counter, retry if session is already allocated
diff --git a/src/logind-dbus.c b/src/logind-dbus.c
index 0f3de41..2bad549 100644
--- a/src/logind-dbus.c
+++ b/src/logind-dbus.c
@@ -176,7 +176,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
Seat *s;
DBusMessageIter iter;
int r;
- char *id, *p;
+ char *id = NULL, *p;
int vtnr = -1;
int pipe_fds[2] = { -1, -1 };
DBusMessage *reply = NULL;
@@ -306,19 +306,30 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
audit_session_from_pid(leader, &audit_id);
- if (audit_id > 0)
+ if (audit_id > 0) {
asprintf(&id, "%lu", (unsigned long) audit_id);
- else
- asprintf(&id, "c%lu", ++m->session_counter);
- if (!id) {
- r = -ENOMEM;
- goto fail;
- }
+ if (!id) {
+ r = -ENOMEM;
+ goto fail;
+ }
- if (hashmap_get(m->sessions, id)) {
- r = -EEXIST;
- goto fail;
+ if (hashmap_get(m->sessions, id)) {
+ r = -EEXIST;
+ goto fail;
+ }
+
+ } else {
+ do {
+ free(id);
+ asprintf(&id, "c%lu", ++m->session_counter);
+
+ if (!id) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ } while (hashmap_get(m->sessions, id));
}
r = manager_add_session(m, user, id, &session);
diff --git a/src/logind.h b/src/logind.h
index d8674e7..2b9b702 100644
--- a/src/logind.h
+++ b/src/logind.h
@@ -40,6 +40,7 @@
* subscribe to fd HUP
* D-Bus method: AttachDevice(seat, device);
* D-Bus method: PermitLinger(user, bool b);
+ * properly handle if two sessions with the same loginuid are attempted to be created
*
* non-local X11 server
* reboot/shutdown halt management
commit 1713813de365486617ab87899f950e9b6ec928ef
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Jun 24 20:41:56 2011 +0200
logind: remove a session when its cgroup is gone
diff --git a/src/logind-dbus.c b/src/logind-dbus.c
index 2a85749..0f3de41 100644
--- a/src/logind-dbus.c
+++ b/src/logind-dbus.c
@@ -896,6 +896,36 @@ const DBusObjectPathVTable bus_manager_vtable = {
.message_function = manager_message_handler
};
+DBusHandlerResult bus_message_filter(
+ DBusConnection *connection,
+ DBusMessage *message,
+ void *userdata) {
+
+ Manager *m = userdata;
+ DBusError error;
+
+ assert(m);
+ assert(connection);
+ assert(message);
+
+ dbus_error_init(&error);
+
+ if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
+ const char *cgroup;
+
+ if (!dbus_message_get_args(message, &error,
+ DBUS_TYPE_STRING, &cgroup,
+ DBUS_TYPE_INVALID))
+ log_error("Failed to parse Released message: %s", bus_error_message(&error));
+ else
+ manager_cgroup_notify_empty(m, cgroup);
+ }
+
+ dbus_error_free(&error);
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
int manager_send_changed(Manager *manager, const char *properties) {
DBusMessage *m;
int r = -ENOMEM;
diff --git a/src/logind-session.c b/src/logind-session.c
index 74f8ad1..9278f30 100644
--- a/src/logind-session.c
+++ b/src/logind-session.c
@@ -83,6 +83,9 @@ void session_free(Session *s) {
LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
}
+ if (s->cgroup_path)
+ hashmap_remove(s->manager->cgroups, s->cgroup_path);
+
free(s->cgroup_path);
strv_free(s->controllers);
@@ -468,6 +471,8 @@ static int session_create_cgroup(Session *s) {
}
}
+ hashmap_put(s->manager->cgroups, s->cgroup_path, s);
+
return 0;
}
@@ -562,6 +567,8 @@ static int session_kill_cgroup(Session *s) {
STRV_FOREACH(k, s->user->manager->controllers)
cg_trim(*k, s->cgroup_path, true);
+ hashmap_remove(s->manager->cgroups, s->cgroup_path);
+
free(s->cgroup_path);
s->cgroup_path = NULL;
diff --git a/src/logind.c b/src/logind.c
index cdb4da7..2665ab9 100644
--- a/src/logind.c
+++ b/src/logind.c
@@ -56,6 +56,7 @@ Manager *manager_new(void) {
m->seats = hashmap_new(string_hash_func, string_compare_func);
m->sessions = hashmap_new(string_hash_func, string_compare_func);
m->users = hashmap_new(trivial_hash_func, trivial_compare_func);
+ m->cgroups = hashmap_new(string_hash_func, string_compare_func);
if (!m->devices || !m->seats || !m->sessions || !m->users) {
manager_free(m);
@@ -100,6 +101,7 @@ void manager_free(Manager *m) {
hashmap_free(m->users);
hashmap_free(m->devices);
hashmap_free(m->seats);
+ hashmap_free(m->cgroups);
if (m->console_active_fd >= 0)
close_nointr_nofail(m->console_active_fd);
@@ -682,12 +684,34 @@ int manager_spawn_autovt(Manager *m, int vtnr) {
return 0;
}
-static DBusHandlerResult login_message_filter(
- DBusConnection *connection,
- DBusMessage *message,
- void *userdata) {
+void manager_cgroup_notify_empty(Manager *m, const char *cgroup) {
+ Session *s;
+ char *p;
+
+ assert(m);
+ assert(cgroup);
+
+ p = strdup(cgroup);
+ if (!p) {
+ log_error("Out of memory.");
+ return;
+ }
+
+ for (;;) {
+ char *e;
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ if (isempty(p) || streq(p, "/"))
+ break;
+
+ s = hashmap_get(m->cgroups, p);
+ if (s)
+ session_add_to_gc_queue(s);
+
+ assert_se(e = strrchr(p, '/'));
+ *e = 0;
+ }
+
+ free(p);
}
static int manager_connect_bus(Manager *m) {
@@ -712,7 +736,7 @@ static int manager_connect_bus(Manager *m) {
!dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/seat", &bus_seat_vtable, m) ||
!dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/session", &bus_session_vtable, m) ||
!dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/user", &bus_user_vtable, m) ||
- !dbus_connection_add_filter(m->bus, login_message_filter, m, NULL)) {
+ !dbus_connection_add_filter(m->bus, bus_message_filter, m, NULL)) {
log_error("Not enough memory");
r = -ENOMEM;
goto fail;
@@ -958,6 +982,8 @@ int manager_run(Manager *m) {
if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE)
continue;
+ manager_gc(m);
+
n = epoll_wait(m->epoll_fd, &event, 1, -1);
if (n < 0) {
if (errno == EINTR || errno == EAGAIN)
diff --git a/src/logind.h b/src/logind.h
index 22eab55..d8674e7 100644
--- a/src/logind.h
+++ b/src/logind.h
@@ -37,7 +37,7 @@
* recreate VTs when disallocated
* spawn user systemd
* direct client API
- * subscribe to cgroup changes, fd HUP
+ * subscribe to fd HUP
* D-Bus method: AttachDevice(seat, device);
* D-Bus method: PermitLinger(user, bool b);
*
@@ -84,6 +84,8 @@ struct Manager {
bool kill_user_processes;
unsigned long session_counter;
+
+ Hashmap *cgroups;
};
Manager *manager_new(void);
@@ -109,6 +111,8 @@ int manager_startup(Manager *m);
int manager_run(Manager *m);
int manager_spawn_autovt(Manager *m, int vtnr);
+void manager_cgroup_notify_empty(Manager *m, const char *cgroup);
+
void manager_gc(Manager *m);
int manager_get_idle_hint(Manager *m, dual_timestamp *t);
@@ -117,6 +121,8 @@ bool x11_display_is_local(const char *display);
extern const DBusObjectPathVTable bus_manager_vtable;
+DBusHandlerResult bus_message_filter(DBusConnection *c, DBusMessage *message, void *userdata);
+
int manager_send_changed(Manager *manager, const char *properties);
#endif
commit dec15e9263cadae02f4f51463860248af40475d0
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Jun 24 20:41:22 2011 +0200
logind: fix generation of bus arrays
diff --git a/src/logind-dbus.c b/src/logind-dbus.c
index 693906e..2a85749 100644
--- a/src/logind-dbus.c
+++ b/src/logind-dbus.c
@@ -589,7 +589,7 @@ static DBusHandlerResult manager_message_handler(
dbus_message_iter_init_append(reply, &iter);
- if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "susso", &sub))
+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
goto oom;
HASHMAP_FOREACH(session, m->sessions, i) {
@@ -635,7 +635,7 @@ static DBusHandlerResult manager_message_handler(
dbus_message_iter_init_append(reply, &iter);
- if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "uso", &sub))
+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
goto oom;
HASHMAP_FOREACH(user, m->users, i) {
@@ -679,7 +679,7 @@ static DBusHandlerResult manager_message_handler(
dbus_message_iter_init_append(reply, &iter);
- if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "so", &sub))
+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
goto oom;
HASHMAP_FOREACH(seat, m->seats, i) {
diff --git a/src/logind-seat-dbus.c b/src/logind-seat-dbus.c
index ad0298e..669e83e 100644
--- a/src/logind-seat-dbus.c
+++ b/src/logind-seat-dbus.c
@@ -102,7 +102,7 @@ static int bus_seat_append_sessions(DBusMessageIter *i, const char *property, vo
assert(property);
assert(s);
- if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "so", &sub))
+ if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(so)", &sub))
return -ENOMEM;
LIST_FOREACH(sessions_by_seat, session, s->sessions) {
diff --git a/src/logind-user-dbus.c b/src/logind-user-dbus.c
index 6d7e8e7..7263d1b 100644
--- a/src/logind-user-dbus.c
+++ b/src/logind-user-dbus.c
@@ -121,7 +121,7 @@ static int bus_user_append_sessions(DBusMessageIter *i, const char *property, vo
assert(property);
assert(u);
- if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "so", &sub))
+ if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(so)", &sub))
return -ENOMEM;
LIST_FOREACH(sessions_by_user, session, u->sessions) {
commit 19bc719ec28e731159671b06254d9bfd49014894
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Jun 24 20:40:00 2011 +0200
logind: make sure we hand out write fd, and keep read fd for session end detection
diff --git a/TODO b/TODO
index aab4431..d7c92e1 100644
--- a/TODO
+++ b/TODO
@@ -80,6 +80,8 @@ Features:
* avoid DefaultStandardOutput=syslog to have any effect on StandardInput=socket services
+* cgroup_notify_empty(): recursively check groups up the tree, too
+
* fix alsa mixer restore to not print error when no config is stored
* show enablement status in systemctl status
diff --git a/src/dbus.c b/src/dbus.c
index 2a379a2..93a19a4 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -446,7 +446,7 @@ static DBusHandlerResult system_bus_message_filter(DBusConnection *connection, D
if (!dbus_message_get_args(message, &error,
DBUS_TYPE_STRING, &cgroup,
DBUS_TYPE_INVALID))
- log_error("Failed to parse Released message: %s", error.message);
+ log_error("Failed to parse Released message: %s", bus_error_message(&error));
else
cgroup_notify_empty(m, cgroup);
}
diff --git a/src/logind-dbus.c b/src/logind-dbus.c
index 10a826b..693906e 100644
--- a/src/logind-dbus.c
+++ b/src/logind-dbus.c
@@ -382,8 +382,8 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
goto fail;
}
- session->pipe_fd = pipe_fds[1];
- pipe_fds[1] = -1;
+ session->pipe_fd = pipe_fds[0];
+ pipe_fds[0] = -1;
if (s) {
r = seat_attach_session(s, session);
@@ -412,7 +412,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
DBUS_TYPE_STRING, &session->id,
DBUS_TYPE_OBJECT_PATH, &p,
DBUS_TYPE_STRING, &session->user->runtime_path,
- DBUS_TYPE_UNIX_FD, &pipe_fds[0],
+ DBUS_TYPE_UNIX_FD, &pipe_fds[1],
DBUS_TYPE_INVALID);
free(p);
@@ -421,7 +421,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
goto fail;
}
- close_nointr_nofail(pipe_fds[0]);
+ close_nointr_nofail(pipe_fds[1]);
*_reply = reply;
return 0;
commit ed18b08bed983b845c72a83666a7d7db546d89ad
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Jun 24 19:42:45 2011 +0200
logind: various clean-ups
diff --git a/src/logind-seat-dbus.c b/src/logind-seat-dbus.c
index 4a4527d..ad0298e 100644
--- a/src/logind-seat-dbus.c
+++ b/src/logind-seat-dbus.c
@@ -378,6 +378,9 @@ int seat_send_changed(Seat *s, const char *properties) {
assert(s);
+ if (!s->started)
+ return 0;
+
p = seat_bus_path(s);
if (!p)
return -ENOMEM;
diff --git a/src/logind-seat.c b/src/logind-seat.c
index 26c2bd4..c232a87 100644
--- a/src/logind-seat.c
+++ b/src/logind-seat.c
@@ -350,18 +350,17 @@ int seat_stop(Seat *s) {
assert(s);
- if (!s->started)
- return 0;
-
- log_info("Removed seat %s.", s->id);
-
- seat_send_signal(s, false);
+ if (s->started)
+ log_info("Removed seat %s.", s->id);
seat_stop_sessions(s);
unlink(s->state_file);
seat_add_to_gc_queue(s);
+ if (s->started)
+ seat_send_signal(s, false);
+
s->started = false;
return r;
diff --git a/src/logind-session-dbus.c b/src/logind-session-dbus.c
index 8d1e607..2435a65 100644
--- a/src/logind-session-dbus.c
+++ b/src/logind-session-dbus.c
@@ -429,6 +429,9 @@ int session_send_changed(Session *s, const char *properties) {
assert(s);
+ if (!s->started)
+ return 0;
+
p = session_bus_path(s);
if (!p)
return -ENOMEM;
diff --git a/src/logind-session.c b/src/logind-session.c
index 42d2801..74f8ad1 100644
--- a/src/logind-session.c
+++ b/src/logind-session.c
@@ -480,6 +480,10 @@ int session_start(Session *s) {
if (s->started)
return 0;
+ r = user_start(s->user);
+ if (r < 0)
+ return r;
+
log_info("New session %s of user %s.", s->id, s->user->name);
/* Create cgroup */
@@ -514,7 +518,16 @@ int session_start(Session *s) {
static bool session_shall_kill(Session *s) {
assert(s);
- return s->kill_processes;
+ if (!s->kill_processes)
+ return false;
+
+ if (strv_contains(s->manager->kill_exclude_users, s->user->name))
+ return false;
+
+ if (strv_isempty(s->manager->kill_only_users))
+ return true;
+
+ return strv_contains(s->manager->kill_only_users, s->user->name);
}
static int session_kill_cgroup(Session *s) {
@@ -584,10 +597,8 @@ int session_stop(Session *s) {
assert(s);
- if (!s->started)
- return 0;
-
- log_info("Removed session %s.", s->id);
+ if (s->started)
+ log_info("Removed session %s.", s->id);
/* Kill cgroup */
k = session_kill_cgroup(s);
@@ -599,8 +610,10 @@ int session_stop(Session *s) {
unlink(s->state_file);
session_add_to_gc_queue(s);
+ user_add_to_gc_queue(s->user);
- session_send_signal(s, false);
+ if (s->started)
+ session_send_signal(s, false);
if (s->seat) {
if (s->seat->active == s)
diff --git a/src/logind-user-dbus.c b/src/logind-user-dbus.c
index 5926dcf..6d7e8e7 100644
--- a/src/logind-user-dbus.c
+++ b/src/logind-user-dbus.c
@@ -362,6 +362,9 @@ int user_send_changed(User *u, const char *properties) {
assert(u);
+ if (!u->started)
+ return 0;
+
p = user_bus_path(u);
if (!p)
return -ENOMEM;
diff --git a/src/logind-user.c b/src/logind-user.c
index 8ebd6ec..63033e0 100644
--- a/src/logind-user.c
+++ b/src/logind-user.c
@@ -265,6 +265,8 @@ int user_start(User *u) {
if (u->started)
return 0;
+ log_info("New user %s logged in.", u->name);
+
/* Make XDG_RUNTIME_DIR */
r = user_mkdir_runtime_path(u);
if (r < 0)
@@ -304,7 +306,16 @@ static int user_stop_service(User *u) {
static int user_shall_kill(User *u) {
assert(u);
- return u->manager->kill_user_processes;
+ if (!u->manager->kill_user_processes)
+ return false;
+
+ if (strv_contains(u->manager->kill_exclude_users, u->name))
+ return false;
+
+ if (strv_isempty(u->manager->kill_only_users))
+ return true;
+
+ return strv_contains(u->manager->kill_only_users, u->name);
}
static int user_kill_cgroup(User *u) {
@@ -368,8 +379,8 @@ int user_stop(User *u) {
int r = 0, k;
assert(u);
- if (!u->started)
- return 0;
+ if (u->started)
+ log_info("User %s logged out.", u->name);
LIST_FOREACH(sessions_by_user, s, u->sessions) {
k = session_stop(s);
@@ -377,8 +388,6 @@ int user_stop(User *u) {
r = k;
}
- user_send_signal(u, false);
-
/* Kill systemd */
k = user_stop_service(u);
if (k < 0)
@@ -397,6 +406,9 @@ int user_stop(User *u) {
unlink(u->state_file);
user_add_to_gc_queue(u);
+ if (u->started)
+ user_send_signal(u, false);
+
u->started = false;
return r;
diff --git a/src/logind.h b/src/logind.h
index 7de8e3b..22eab55 100644
--- a/src/logind.h
+++ b/src/logind.h
@@ -35,10 +35,11 @@
/* TODO:
*
* recreate VTs when disallocated
- * PAM rewrite
* spawn user systemd
* direct client API
* subscribe to cgroup changes, fd HUP
+ * D-Bus method: AttachDevice(seat, device);
+ * D-Bus method: PermitLinger(user, bool b);
*
* non-local X11 server
* reboot/shutdown halt management
diff --git a/src/pam-module.c b/src/pam-module.c
index b742d64..dc7c001 100644
--- a/src/pam-module.c
+++ b/src/pam-module.c
@@ -60,7 +60,7 @@ static int parse_argv(pam_handle_t *handle,
if (startswith(argv[i], "kill-processes=")) {
if ((k = parse_boolean(argv[i] + 15)) < 0) {
- pam_syslog(handle, LOG_ERR, "Failed to parse kill-session= argument.");
+ pam_syslog(handle, LOG_ERR, "Failed to parse kill-processes= argument.");
return k;
}
@@ -304,26 +304,25 @@ _public_ PAM_EXTERN int pam_sm_open_session(
int flags,
int argc, const char **argv) {
- const char *username = NULL;
struct passwd *pw;
bool kill_processes = false, debug = false;
+ const char *username, *id, *object_path, *runtime_path, *service = NULL, *tty = NULL, *display = NULL, *remote_user = NULL, *remote_host = NULL, *seat = NULL, *type;
char **controllers = NULL, **reset_controllers = NULL, **kill_only_users = NULL, **kill_exclude_users = NULL;
- int r;
DBusError error;
uint32_t uid, pid;
DBusMessageIter iter;
dbus_bool_t kp;
- const char *id, *object_path, *runtime_path, *service = NULL, *tty = NULL, *display = NULL, *remote_user = NULL, *remote_host = NULL, *seat = NULL, *type;
int session_fd = -1;
DBusConnection *bus = NULL;
DBusMessage *m = NULL, *reply = NULL;
dbus_bool_t remote;
+ int r;
assert(handle);
dbus_error_init(&error);
- pam_syslog(handle, LOG_ERR, "pam-systemd initializing");
+ /* pam_syslog(handle, LOG_INFO, "pam-systemd initializing"); */
/* Make this a NOP on non-systemd systems */
if (sd_booted() <= 0)
@@ -333,8 +332,10 @@ _public_ PAM_EXTERN int pam_sm_open_session(
argc, argv,
&controllers, &reset_controllers,
&kill_processes, &kill_only_users, &kill_exclude_users,
- &debug) < 0)
- return PAM_SESSION_ERR;
+ &debug) < 0) {
+ r = PAM_SESSION_ERR;
+ goto finish;
+ }
r = get_user_data(handle, &username, &pw);
if (r != PAM_SUCCESS)
@@ -343,6 +344,8 @@ _public_ PAM_EXTERN int pam_sm_open_session(
if (kill_processes)
kill_processes = check_user_lists(handle, pw->pw_uid, kill_only_users, kill_exclude_users);
+ dbus_connection_set_change_sigpipe(FALSE);
+
bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
if (!bus) {
pam_syslog(handle, LOG_ERR, "Failed to connect to system bus: %s", bus_error_message(&error));
@@ -370,18 +373,14 @@ _public_ PAM_EXTERN int pam_sm_open_session(
pam_get_item(handle, PAM_TTY, (const void**) &tty);
pam_get_item(handle, PAM_RUSER, (const void**) &remote_user);
pam_get_item(handle, PAM_RHOST, (const void**) &remote_host);
+ seat = pam_getenv(handle, "XDG_SEAT");
- if (isempty(tty))
- service = "";
- if (isempty(tty))
- tty = "";
- if (isempty(display))
- display = "";
- if (isempty(remote_user))
- remote_user = "";
- if (isempty(remote_host))
- remote_host = "";
- seat = "";
+ service = strempty(service);
+ tty = strempty(tty);
+ display = strempty(display);
+ remote_user = strempty(remote_user);
+ remote_host = strempty(remote_host);
+ seat = strempty(seat);
type = !isempty(display) ? "x11" :
!isempty(tty) ? "tty" : "other";
@@ -481,12 +480,12 @@ finish:
dbus_connection_unref(bus);
}
- if (reply)
- dbus_message_unref(reply);
-
if (m)
dbus_message_unref(m);
+ if (reply)
+ dbus_message_unref(reply);
+
if (session_fd >= 0)
close_nointr_nofail(session_fd);
commit 98a28fef2618e54a644614c759f371f297381b70
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Jun 24 18:50:50 2011 +0200
logind: hook up PAM module with logind
diff --git a/Makefile.am b/Makefile.am
index a2d7397..bfc1079 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1248,10 +1248,12 @@ systemd_tty_ask_password_agent_LDADD = \
pam_systemd_la_SOURCES = \
src/pam-module.c \
- src/cgroup-util.c
+ src/dbus-common.c
pam_systemd_la_CFLAGS = \
- $(AM_CFLAGS)
+ $(AM_CFLAGS) \
+ $(PAM_CFLAGS) \
+ $(DBUS_CFLAGS) \
-fvisibility=hidden
pam_systemd_la_LDFLAGS = \
@@ -1264,7 +1266,8 @@ pam_systemd_la_LDFLAGS = \
pam_systemd_la_LIBADD = \
libsystemd-basic.la \
libsystemd-daemon.la \
- $(PAM_LIBS)
+ $(PAM_LIBS) \
+ $(DBUS_LIBS)
SED_PROCESS = \
$(AM_V_GEN)$(MKDIR_P) $(dir $@) && \
@@ -1510,7 +1513,7 @@ endif
$(LN_S) graphical.target runlevel5.target && \
$(LN_S) reboot.target runlevel6.target )
( cd $(DESTDIR)$(systemunitdir) && \
- rm -f default.target ctrl-alt-del.target dbus-org.freedesktop.hostname1.service && \
+ rm -f default.target ctrl-alt-del.target dbus-org.freedesktop.hostname1.service dbus-org.freedesktop.locale1.service dbus-org.freedesktop.timedate1.service dbus-org.freedesktop.login1.service && \
$(LN_S) graphical.target default.target && \
$(LN_S) reboot.target ctrl-alt-del.target && \
$(LN_S) systemd-hostnamed.service dbus-org.freedesktop.hostname1.service && \
diff --git a/src/dbus-common.c b/src/dbus-common.c
index e439a42..73f9e87 100644
--- a/src/dbus-common.c
+++ b/src/dbus-common.c
@@ -463,23 +463,12 @@ int bus_property_append_string(DBusMessageIter *i, const char *property, void *d
}
int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data) {
- DBusMessageIter sub;
char **t = data;
assert(i);
assert(property);
- if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
- return -ENOMEM;
-
- STRV_FOREACH(t, t)
- if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, t))
- return -ENOMEM;
-
- if (!dbus_message_iter_close_container(i, &sub))
- return -ENOMEM;
-
- return 0;
+ return bus_append_strv_iter(i, t);
}
int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data) {
@@ -796,3 +785,21 @@ int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) {
return 0;
}
+
+int bus_append_strv_iter(DBusMessageIter *iter, char **l) {
+ DBusMessageIter sub;
+
+ assert(iter);
+
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &sub))
+ return -ENOMEM;
+
+ STRV_FOREACH(l, l)
+ if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, l))
+ return -ENOMEM;
+
+ if (!dbus_message_iter_close_container(iter, &sub))
+ return -ENOMEM;
+
+ return 0;
+}
diff --git a/src/dbus-common.h b/src/dbus-common.h
index 9368f75..04485e5 100644
--- a/src/dbus-common.h
+++ b/src/dbus-common.h
@@ -161,4 +161,6 @@ unsigned bus_events_to_flags(uint32_t events);
int bus_parse_strv(DBusMessage *m, char ***_l);
int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l);
+int bus_append_strv_iter(DBusMessageIter *iter, char **l);
+
#endif
diff --git a/src/logind-dbus.c b/src/logind-dbus.c
index 662ffd0..10a826b 100644
--- a/src/logind-dbus.c
+++ b/src/logind-dbus.c
@@ -21,9 +21,11 @@
#include <errno.h>
#include <string.h>
+#include <unistd.h>
#include "logind.h"
#include "dbus-common.h"
+#include "strv.h"
#define BUS_MANAGER_INTERFACE \
" <interface name=\"org.freedesktop.login1.Manager\">\n" \
@@ -51,6 +53,7 @@
" <method name=\"CreateSession\">\n" \
" <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
" <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
+ " <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
" <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
" <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
" <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
@@ -60,9 +63,10 @@
" <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
" <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
" <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
- " <arg name=\"kill_processes\" type=\"as\" direction=\"in\"/>\n" \
+ " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
" <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
" <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
+ " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
" <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
" </method>\n" \
" <method name=\"ActivateSession\">\n" \
@@ -161,6 +165,285 @@ static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *pr
return 0;
}
+static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
+ Session *session = NULL;
+ User *user = NULL;
+ const char *type, *seat, *tty, *display, *remote_user, *remote_host, *service;
+ uint32_t uid, leader, audit_id = 0;
+ dbus_bool_t remote, kill_processes;
+ char **controllers = NULL, **reset_controllers = NULL;
+ SessionType t;
+ Seat *s;
+ DBusMessageIter iter;
+ int r;
+ char *id, *p;
+ int vtnr = -1;
+ int pipe_fds[2] = { -1, -1 };
+ DBusMessage *reply = NULL;
+ bool b;
+
+ assert(m);
+ assert(message);
+ assert(_reply);
+
+ if (!dbus_message_iter_init(message, &iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(&iter, &uid);
+
+ if (!dbus_message_iter_next(&iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(&iter, &leader);
+
+ if (leader <= 0 ||
+ !dbus_message_iter_next(&iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(&iter, &service);
+
+ if (!dbus_message_iter_next(&iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(&iter, &type);
+ t = session_type_from_string(type);
+
+ if (t < 0 ||
+ !dbus_message_iter_next(&iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(&iter, &seat);
+
+ if (isempty(seat))
+ s = NULL;
+ else {
+ s = hashmap_get(m->seats, seat);
+ if (!s)
+ return -ENOENT;
+ }
+
+ if (!dbus_message_iter_next(&iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(&iter, &tty);
+
+ if (tty_is_vc(tty)) {
+
+ if (!s)
+ s = m->vtconsole;
+ else if (s != m->vtconsole)
+ return -EINVAL;
+
+ vtnr = vtnr_from_tty(tty);
+
+ if (vtnr <= 0)
+ return vtnr < 0 ? vtnr : -EINVAL;
+
+ } else if (s == m->vtconsole)
+ return -EINVAL;
+
+ if (!dbus_message_iter_next(&iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(&iter, &display);
+
+ if (!dbus_message_iter_next(&iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(&iter, &remote);
+
+ if (!dbus_message_iter_next(&iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(&iter, &remote_user);
+
+ if (!dbus_message_iter_next(&iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(&iter, &remote_host);
+
+ if (!dbus_message_iter_next(&iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
+ return -EINVAL;
+
+ r = bus_parse_strv_iter(&iter, &controllers);
+ if (r < 0)
+ return -EINVAL;
+
+ if (!dbus_message_iter_next(&iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
+ r = -EINVAL;
+ goto fail;
+ }
+
+ r = bus_parse_strv_iter(&iter, &reset_controllers);
+ if (r < 0)
+ goto fail;
+
+ if (!dbus_message_iter_next(&iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
+ r = -EINVAL;
+ goto fail;
+ }
+
+ dbus_message_iter_get_basic(&iter, &kill_processes);
+
+ r = manager_add_user_by_uid(m, uid, &user);
+ if (r < 0)
+ goto fail;
+
+ audit_session_from_pid(leader, &audit_id);
+
+ if (audit_id > 0)
+ asprintf(&id, "%lu", (unsigned long) audit_id);
+ else
+ asprintf(&id, "c%lu", ++m->session_counter);
+
+ if (!id) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ if (hashmap_get(m->sessions, id)) {
+ r = -EEXIST;
+ goto fail;
+ }
+
+ r = manager_add_session(m, user, id, &session);
+ free(id);
+ if (r < 0)
+ goto fail;
+
+ session->leader = leader;
+ session->audit_id = audit_id;
+ session->type = t;
+ session->remote = remote;
+ session->controllers = controllers;
+ session->reset_controllers = reset_controllers;
+ session->kill_processes = kill_processes;
+ session->vtnr = vtnr;
+
+ controllers = reset_controllers = NULL;
+
+ if (!isempty(tty)) {
+ session->tty = strdup(tty);
+ if (!session->tty) {
+ r = -ENOMEM;
+ goto fail;
+ }
+ }
+
+ if (!isempty(display)) {
+ session->display = strdup(display);
+ if (!session->display) {
+ r = -ENOMEM;
+ goto fail;
+ }
+ }
+
+ if (!isempty(remote_user)) {
+ session->remote_user = strdup(remote_user);
+ if (!session->remote_user) {
+ r = -ENOMEM;
+ goto fail;
+ }
+ }
+
+ if (!isempty(remote_host)) {
+ session->remote_host = strdup(remote_host);
+ if (!session->remote_host) {
+ r = -ENOMEM;
+ goto fail;
+ }
+ }
+
+ if (!isempty(service)) {
+ session->service = strdup(service);
+ if (!session->service) {
+ r = -ENOMEM;
+ goto fail;
+ }
+ }
+
+ if (pipe(pipe_fds) < 0) {
+ r = -errno;
+ goto fail;
+ }
+
+ session->pipe_fd = pipe_fds[1];
+ pipe_fds[1] = -1;
+
+ if (s) {
+ r = seat_attach_session(s, session);
+ if (r < 0)
+ goto fail;
+ }
+
+ r = session_start(session);
+ if (r < 0)
+ goto fail;
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ p = session_bus_path(session);
+ if (!p) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ b = dbus_message_append_args(
+ reply,
+ DBUS_TYPE_STRING, &session->id,
+ DBUS_TYPE_OBJECT_PATH, &p,
+ DBUS_TYPE_STRING, &session->user->runtime_path,
+ DBUS_TYPE_UNIX_FD, &pipe_fds[0],
+ DBUS_TYPE_INVALID);
+ free(p);
+
+ if (!b) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ close_nointr_nofail(pipe_fds[0]);
+ *_reply = reply;
+
+ return 0;
+
+fail:
+ strv_free(controllers);
+ strv_free(reset_controllers);
+
+ if (session)
+ session_add_to_gc_queue(session);
+
+ if (user)
+ user_add_to_gc_queue(user);
+
+ close_pipe(pipe_fds);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ return r;
+}
+
static DBusHandlerResult manager_message_handler(
DBusConnection *connection,
DBusMessage *message,
@@ -171,7 +454,6 @@ static DBusHandlerResult manager_message_handler(
const BusProperty properties[] = {
{ "org.freedesktop.login1.Manager", "ControlGroupHierarchy", bus_property_append_string, "s", m->cgroup_path },
{ "org.freedesktop.login1.Manager", "Controllers", bus_property_append_strv, "as", m->controllers },
- { "org.freedesktop.login1.Manager", "ResetControllers", bus_property_append_strv, "as", m->reset_controllers },
{ "org.freedesktop.login1.Manager", "NAutoVTs", bus_property_append_unsigned, "u", &m->n_autovts },
{ "org.freedesktop.login1.Manager", "KillOnlyUsers", bus_property_append_strv, "as", m->kill_only_users },
{ "org.freedesktop.login1.Manager", "KillExcludeUsers", bus_property_append_strv, "as", m->kill_exclude_users },
@@ -425,6 +707,15 @@ static DBusHandlerResult manager_message_handler(
if (!dbus_message_iter_close_container(&iter, &sub))
goto oom;
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
+
+ r = bus_manager_create_session(m, message, &reply);
+ if (r == -ENOMEM)
+ goto oom;
+
+ if (r < 0)
+ return bus_send_error_reply(connection, message, &error, r);
+
} else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
const char *name;
Session *session;
diff --git a/src/logind-seat.c b/src/logind-seat.c
index 12a1b80..26c2bd4 100644
--- a/src/logind-seat.c
+++ b/src/logind-seat.c
@@ -41,7 +41,7 @@ Seat *seat_new(Manager *m, const char *id) {
if (!s)
return NULL;
- s->state_file = strappend("/run/systemd/seat/", id);
+ s->state_file = strappend("/run/systemd/seats/", id);
if (!s->state_file) {
free(s);
return NULL;
@@ -86,7 +86,7 @@ int seat_save(Seat *s) {
assert(s);
- r = safe_mkdir("/run/systemd/seat", 0755, 0, 0);
+ r = safe_mkdir("/run/systemd/seats", 0755, 0, 0);
if (r < 0)
goto finish;
@@ -246,6 +246,14 @@ int seat_set_active(Seat *s, Session *session) {
if (!session || session->started)
seat_send_changed(s, "ActiveSession\0");
+ seat_save(s);
+
+ if (session)
+ session_save(session);
+
+ if (old_active)
+ session_save(old_active);
+
return 0;
}
diff --git a/src/logind-session-dbus.c b/src/logind-session-dbus.c
index b0e592d..8d1e607 100644
--- a/src/logind-session-dbus.c
+++ b/src/logind-session-dbus.c
@@ -49,6 +49,7 @@
" <property name=\"Remote\" type=\"b\" access=\"read\"/>\n" \
" <property name=\"RemoteHost\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"RemoteUser\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Service\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"Leader\" type=\"u\" access=\"read\"/>\n" \
" <property name=\"Audit\" type=\"u\" access=\"read\"/>\n" \
" <property name=\"Type\" type=\"s\" access=\"read\"/>\n" \
@@ -236,6 +237,7 @@ static DBusHandlerResult session_message_dispatch(
{ "org.freedesktop.login1.Session", "Remote", bus_property_append_bool, "b", &s->remote },
{ "org.freedesktop.login1.Session", "RemoteUser", bus_property_append_string, "s", s->remote_user },
{ "org.freedesktop.login1.Session", "RemoteHost", bus_property_append_string, "s", s->remote_host },
+ { "org.freedesktop.login1.Session", "Service", bus_property_append_string, "s", s->service },
{ "org.freedesktop.login1.Session", "Leader", bus_property_append_pid, "u", &s->leader },
{ "org.freedesktop.login1.Session", "Audit", bus_property_append_uint32, "u", &s->audit_id },
{ "org.freedesktop.login1.Session", "Type", bus_session_append_type, "s", &s->type },
diff --git a/src/logind-session.c b/src/logind-session.c
index 5ba6b21..42d2801 100644
--- a/src/logind-session.c
+++ b/src/logind-session.c
@@ -40,7 +40,7 @@ Session* session_new(Manager *m, User *u, const char *id) {
if (!s)
return NULL;
- s->state_file = strappend("/run/systemd/session/", id);
+ s->state_file = strappend("/run/systemd/sessions/", id);
if (!s->state_file) {
free(s);
return NULL;
@@ -90,9 +90,13 @@ void session_free(Session *s) {
free(s->display);
free(s->remote_host);
free(s->remote_user);
+ free(s->service);
hashmap_remove(s->manager->sessions, s->id);
+ if (s->pipe_fd >= 0)
+ close_nointr_nofail(s->pipe_fd);
+
free(s->state_file);
free(s);
}
@@ -104,7 +108,7 @@ int session_save(Session *s) {
assert(s);
- r = safe_mkdir("/run/systemd/session", 0755, 0, 0);
+ r = safe_mkdir("/run/systemd/sessions", 0755, 0, 0);
if (r < 0)
goto finish;
@@ -159,6 +163,11 @@ int session_save(Session *s) {
"REMOTE_USER=%s\n",
s->remote_user);
+ if (s->service)
+ fprintf(f,
+ "SERVICE=%s\n",
+ s->service);
+
if (s->seat && seat_is_vtconsole(s->seat))
fprintf(f,
"VTNR=%i\n",
@@ -213,9 +222,9 @@ int session_load(Session *s) {
"DISPLAY", &s->display,
"REMOTE_HOST", &s->remote_host,
"REMOTE_USER", &s->remote_user,
+ "SERVICE", &s->service,
"VTNR", &vtnr,
"LEADER", &leader,
- "AUDIT_ID", &audit_id,
NULL);
if (r < 0)
@@ -253,16 +262,11 @@ int session_load(Session *s) {
pid_t pid;
k = parse_pid(leader, &pid);
- if (k >= 0 && pid >= 1)
+ if (k >= 0 && pid >= 1) {
s->leader = pid;
- }
-
- if (audit_id) {
- uint32_t l;
- k = safe_atou32(audit_id, &l);
- if (k >= 0 && l >= l)
- s->audit_id = l;
+ audit_session_from_pid(pid, &s->audit_id);
+ }
}
finish:
@@ -384,6 +388,28 @@ done:
return 0;
}
+static int session_create_one_group(Session *s, const char *controller, const char *path) {
+ int r;
+
+ assert(s);
+ assert(controller);
+ assert(path);
+
+ if (s->leader > 0)
+ r = cg_create_and_attach(controller, path, s->leader);
+ else
+ r = cg_create(controller, path);
+
+ if (r < 0)
+ return r;
+
+ r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid);
+ if (r >= 0)
+ r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
+
+ return r;
+}
+
static int session_create_cgroup(Session *s) {
char **k;
char *p;
@@ -401,11 +427,7 @@ static int session_create_cgroup(Session *s) {
} else
p = s->cgroup_path;
- if (s->leader > 0)
- r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, p, s->leader);
- else
- r = cg_create(SYSTEMD_CGROUP_CONTROLLER, p);
-
+ r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
if (r < 0) {
free(p);
s->cgroup_path = NULL;
@@ -415,14 +437,35 @@ static int session_create_cgroup(Session *s) {
s->cgroup_path = p;
+ STRV_FOREACH(k, s->controllers) {
+
+ if (strv_contains(s->reset_controllers, *k))
+ continue;
+
+ r = session_create_one_group(s, *k, p);
+ if (r < 0)
+ log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
+ }
+
STRV_FOREACH(k, s->manager->controllers) {
- if (s->leader > 0)
- r = cg_create_and_attach(*k, p, s->leader);
- else
- r = cg_create(*k, p);
+ if (strv_contains(s->reset_controllers, *k) ||
+ strv_contains(s->controllers, *k))
+ continue;
+
+ r = session_create_one_group(s, *k, p);
if (r < 0)
- log_warning("Failed to create cgroup %s:%s: %s", *k, p, strerror(-r));
+ log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
+ }
+
+ if (s->leader > 0) {
+
+ STRV_FOREACH(k, s->reset_controllers) {
+ r = cg_attach(*k, "/", s->leader);
+ if (r < 0)
+ log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
+
+ }
}
return 0;
@@ -437,6 +480,8 @@ int session_start(Session *s) {
if (s->started)
return 0;
+ log_info("New session %s of user %s.", s->id, s->user->name);
+
/* Create cgroup */
r = session_create_cgroup(s);
if (r < 0)
@@ -542,6 +587,8 @@ int session_stop(Session *s) {
if (!s->started)
return 0;
+ log_info("Removed session %s.", s->id);
+
/* Kill cgroup */
k = session_kill_cgroup(s);
if (k < 0)
@@ -702,7 +749,8 @@ void session_add_to_gc_queue(Session *s) {
static const char* const session_type_table[_SESSION_TYPE_MAX] = {
[SESSION_TTY] = "tty",
- [SESSION_X11] = "x11"
+ [SESSION_X11] = "x11",
+ [SESSION_OTHER] = "other"
};
DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
diff --git a/src/logind-session.h b/src/logind-session.h
index d2f2552..01c9504 100644
--- a/src/logind-session.h
+++ b/src/logind-session.h
@@ -33,6 +33,7 @@ typedef struct Session Session;
typedef enum SessionType {
SESSION_TTY,
SESSION_X11,
+ SESSION_OTHER,
_SESSION_TYPE_MAX,
_SESSION_TYPE_INVALID = -1
} SessionType;
@@ -56,6 +57,8 @@ struct Session {
char *remote_user;
char *remote_host;
+ char *service;
+
int vtnr;
Seat *seat;
diff --git a/src/logind-user.c b/src/logind-user.c
index cb3e441..8ebd6ec 100644
--- a/src/logind-user.c
+++ b/src/logind-user.c
@@ -45,7 +45,7 @@ User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
return NULL;
}
- if (asprintf(&u->state_file, "/run/systemd/user/%lu", (unsigned long) uid) < 0) {
+ if (asprintf(&u->state_file, "/run/systemd/users/%lu", (unsigned long) uid) < 0) {
free(u->name);
free(u);
return NULL;
@@ -94,7 +94,7 @@ int user_save(User *u) {
assert(u);
assert(u->state_file);
- r = safe_mkdir("/run/systemd/user", 0755, 0, 0);
+ r = safe_mkdir("/run/systemd/users", 0755, 0, 0);
if (r < 0)
goto finish;
@@ -152,7 +152,7 @@ finish:
int user_load(User *u) {
int r;
char *display = NULL;
- Session *s;
+ Session *s = NULL;
assert(u);
@@ -172,8 +172,10 @@ int user_load(User *u) {
return r;
}
- s = hashmap_get(u->manager->sessions, display);
- free(display);
+ if (display) {
+ s = hashmap_get(u->manager->sessions, display);
+ free(display);
+ }
if (s && s->display && x11_display_is_local(s->display))
u->display = s;
diff --git a/src/logind.h b/src/logind.h
index 1b7a2b2..7de8e3b 100644
--- a/src/logind.h
+++ b/src/logind.h
@@ -37,8 +37,8 @@
* recreate VTs when disallocated
* PAM rewrite
* spawn user systemd
- * dbus API
* direct client API
+ * subscribe to cgroup changes, fd HUP
*
* non-local X11 server
* reboot/shutdown halt management
@@ -76,11 +76,13 @@ struct Manager {
Seat *vtconsole;
char *cgroup_path;
- char **controllers, **reset_controllers;
+ char **controllers;
char **kill_only_users, **kill_exclude_users;
bool kill_user_processes;
+
+ unsigned long session_counter;
};
Manager *manager_new(void);
diff --git a/src/pam-module.c b/src/pam-module.c
index bdf6133..b742d64 100644
--- a/src/pam-module.c
+++ b/src/pam-module.c
@@ -33,18 +33,17 @@
#include <security/pam_misc.h>
#include "util.h"
-#include "cgroup-util.h"
#include "macro.h"
#include "sd-daemon.h"
#include "strv.h"
+#include "dbus-common.h"
+#include "def.h"
static int parse_argv(pam_handle_t *handle,
int argc, const char **argv,
- bool *create_session,
- bool *kill_session,
- bool *kill_user,
char ***controllers,
char ***reset_controllers,
+ bool *kill_processes,
char ***kill_only_users,
char ***kill_exclude_users,
bool *debug) {
@@ -59,32 +58,25 @@ static int parse_argv(pam_handle_t *handle,
for (i = 0; i < (unsigned) argc; i++) {
int k;
- if (startswith(argv[i], "create-session=")) {
+ if (startswith(argv[i], "kill-processes=")) {
if ((k = parse_boolean(argv[i] + 15)) < 0) {
- pam_syslog(handle, LOG_ERR, "Failed to parse create-session= argument.");
+ pam_syslog(handle, LOG_ERR, "Failed to parse kill-session= argument.");
return k;
}
- if (create_session)
- *create_session = k;
+ if (kill_processes)
+ *kill_processes = k;
} else if (startswith(argv[i], "kill-session=")) {
+ /* As compatibility for old versions */
+
if ((k = parse_boolean(argv[i] + 13)) < 0) {
pam_syslog(handle, LOG_ERR, "Failed to parse kill-session= argument.");
return k;
}
- if (kill_session)
- *kill_session = k;
-
- } else if (startswith(argv[i], "kill-user=")) {
- if ((k = parse_boolean(argv[i] + 10)) < 0) {
- pam_syslog(handle, LOG_ERR, "Failed to parse kill-user= argument.");
- return k;
- }
-
- if (kill_user)
- *kill_user = k;
+ if (kill_processes)
+ *kill_processes = k;
} else if (startswith(argv[i], "controllers=")) {
@@ -155,6 +147,11 @@ static int parse_argv(pam_handle_t *handle,
if (debug)
*debug = k;
+ } else if (startswith(argv[i], "create-session=") ||
+ startswith(argv[i], "kill-user=")) {
+
+ pam_syslog(handle, LOG_WARNING, "Option %s not supported anymore, ignoring.", argv[i]);
+
} else {
pam_syslog(handle, LOG_ERR, "Unknown parameter '%s'.", argv[i]);
return -EINVAL;
@@ -173,13 +170,10 @@ static int parse_argv(pam_handle_t *handle,
}
if (controllers)
- strv_remove(*controllers, "name=systemd");
+ strv_remove(*controllers, SYSTEMD_CGROUP_CONTROLLER);
if (reset_controllers)
- strv_remove(*reset_controllers, "name=systemd");
-
- if (kill_session && *kill_session && kill_user)
- *kill_user = true;
+ strv_remove(*reset_controllers, SYSTEMD_CGROUP_CONTROLLER);
if (!kill_exclude_users_set && kill_exclude_users) {
char **l;
@@ -195,96 +189,6 @@ static int parse_argv(pam_handle_t *handle,
return 0;
}
-static int open_file_and_lock(const char *fn) {
- int fd;
-
- assert(fn);
-
- if ((fd = open(fn, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW|O_CREAT, 0600)) < 0)
- return -errno;
-
- /* The BSD socket semantics are a lot nicer than those of
- * POSIX locks. Which is why we use flock() here. BSD locking
- * does not work across NFS which however is not needed here
- * as the filesystems in question should be local, and only
- * locally accessible, and most likely even tmpfs. */
-
- if (flock(fd, LOCK_EX) < 0) {
- close_nointr_nofail(fd);
- return -errno;
- }
-
- return fd;
-}
-
-enum {
- SESSION_ID_AUDIT = 'a',
- SESSION_ID_COUNTER = 'c',
- SESSION_ID_RANDOM = 'r'
-};
-
-static uint64_t get_session_id(int *mode) {
- char *s;
- int fd;
-
- assert(mode);
-
- /* First attempt: let's use the session ID of the audit
- * system, if it is available. */
- if (have_effective_cap(CAP_AUDIT_CONTROL) > 0)
- if (read_one_line_file("/proc/self/sessionid", &s) >= 0) {
- uint32_t u;
- int r;
-
- r = safe_atou32(s, &u);
- free(s);
-
- if (r >= 0 && u != (uint32_t) -1 && u > 0) {
- *mode = SESSION_ID_AUDIT;
- return (uint64_t) u;
- }
- }
-
- /* Second attempt, use our own counter. */
- if ((fd = open_file_and_lock(RUNTIME_DIR "/user/.pam-systemd-session")) >= 0) {
- uint64_t counter;
- ssize_t r;
-
- /* We do a bit of endianess swapping here, just to be
- * sure. /run should be machine specific anyway, and
- * even mounted from tmpfs, so this byteswapping
- * should really not be necessary. But then again, you
- * never know, so let's avoid any risk. */
-
- if (loop_read(fd, &counter, sizeof(counter), false) != sizeof(counter))
- counter = 1;
- else
- counter = le64toh(counter) + 1;
-
- if (lseek(fd, 0, SEEK_SET) == 0) {
- uint64_t swapped = htole64(counter);
-
- r = loop_write(fd, &swapped, sizeof(swapped), false);
-
- if (r != sizeof(swapped))
- r = -EIO;
- } else
- r = -errno;
-
- close_nointr_nofail(fd);
-
- if (r >= 0) {
- *mode = SESSION_ID_COUNTER;
- return counter;
- }
- }
-
- *mode = SESSION_ID_RANDOM;
-
- /* Last attempt, pick a random value */
- return (uint64_t) random_ull();
-}
-
static int get_user_data(
pam_handle_t *handle,
const char **ret_username,
@@ -346,232 +250,6 @@ static int get_user_data(
return PAM_SUCCESS;
}
-static int create_user_group(
- pam_handle_t *handle,
- const char *controller,
- const char *group,
- struct passwd *pw,
- bool attach,
- bool remember) {
-
- int r;
-
- assert(handle);
- assert(group);
-
- if (attach)
- r = cg_create_and_attach(controller, group, 0);
- else
- r = cg_create(controller, group);
-
- if (r < 0) {
- pam_syslog(handle, LOG_ERR, "Failed to create cgroup: %s", strerror(-r));
- return PAM_SESSION_ERR;
- }
-
- if (r > 0 && remember) {
- /* Remember that it was us who created this group, and
- * that hence we need to remove it too. This is a
- * protection against removing the cgroup when run
- * recursively. */
- if ((r = pam_set_data(handle, "systemd.created", INT_TO_PTR(1), NULL)) != PAM_SUCCESS) {
- pam_syslog(handle, LOG_ERR, "Failed to install created variable.");
- return r;
- }
- }
-
- if ((r = cg_set_task_access(controller, group, 0644, pw->pw_uid, pw->pw_gid)) < 0 ||
- (r = cg_set_group_access(controller, group, 0755, pw->pw_uid, pw->pw_gid)) < 0) {
- pam_syslog(handle, LOG_ERR, "Failed to change access modes: %s", strerror(-r));
- return PAM_SESSION_ERR;
- }
-
- return PAM_SUCCESS;
-}
-
-static int reset_group(
- pam_handle_t *handle,
- const char *controller) {
-
- int r;
-
- assert(handle);
-
- if ((r = cg_attach(controller, "/", 0)) < 0) {
- pam_syslog(handle, LOG_ERR, "Failed to reset cgroup for controller %s: %s", controller, strerror(-r));
- return PAM_SESSION_ERR;
- }
-
- return PAM_SUCCESS;
-}
-
-_public_ PAM_EXTERN int pam_sm_open_session(
- pam_handle_t *handle,
- int flags,
- int argc, const char **argv) {
-
- const char *username = NULL;
- struct passwd *pw;
- int r;
- char *buf = NULL;
- int lock_fd = -1;
- bool create_session = true;
- bool debug = false;
- char **controllers = NULL, **reset_controllers = NULL, **c;
- char *cgroup_user_tree = NULL;
-
- assert(handle);
-
- /* pam_syslog(handle, LOG_DEBUG, "pam-systemd initializing"); */
-
- /* Make this a NOP on non-systemd systems */
- if (sd_booted() <= 0)
- return PAM_SUCCESS;
-
- if (parse_argv(handle,
- argc, argv,
- &create_session, NULL, NULL,
- &controllers, &reset_controllers,
- NULL, NULL, &debug) < 0)
- return PAM_SESSION_ERR;
-
- if ((r = get_user_data(handle, &username, &pw)) != PAM_SUCCESS)
- goto finish;
-
- if ((r = cg_get_user_path(&cgroup_user_tree)) < 0) {
- pam_syslog(handle, LOG_ERR, "Failed to determine user cgroup tree: %s", strerror(-r));
- r = PAM_SYSTEM_ERR;
- goto finish;
- }
-
- if (safe_mkdir(RUNTIME_DIR "/user", 0755, 0, 0) < 0) {
- pam_syslog(handle, LOG_ERR, "Failed to create runtime directory: %m");
- r = PAM_SYSTEM_ERR;
- goto finish;
- }
-
- if ((lock_fd = open_file_and_lock(RUNTIME_DIR "/user/.pam-systemd-lock")) < 0) {
- pam_syslog(handle, LOG_ERR, "Failed to lock runtime directory: %m");
- r = PAM_SYSTEM_ERR;
- goto finish;
- }
-
- /* Create /run/user/$USER */
- free(buf);
- if (asprintf(&buf, RUNTIME_DIR "/user/%s", username) < 0) {
- r = PAM_BUF_ERR;
- goto finish;
- }
-
- if (safe_mkdir(buf, 0700, pw->pw_uid, pw->pw_gid) < 0) {
- pam_syslog(handle, LOG_WARNING, "Failed to create runtime directory: %m");
- r = PAM_SYSTEM_ERR;
- goto finish;
- } else if ((r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", buf, 0)) != PAM_SUCCESS) {
- pam_syslog(handle, LOG_ERR, "Failed to set runtime dir.");
- goto finish;
- }
-
- free(buf);
- buf = NULL;
-
- if (create_session) {
- const char *id;
-
- /* Reuse or create XDG session ID */
- if (!(id = pam_getenv(handle, "XDG_SESSION_ID"))) {
- int mode;
-
- if (asprintf(&buf, "%llux", (unsigned long long) get_session_id(&mode)) < 0) {
- r = PAM_BUF_ERR;
- goto finish;
- }
-
- /* To avoid id clashes we add the session id
- * source to our session ids. Note that the
- * session id source might change during
- * runtime, because a filesystem became
- * writable or the system reconfigured. */
- buf[strlen(buf)-1] =
- mode != SESSION_ID_AUDIT ? (char) mode : 0;
-
- if ((r = pam_misc_setenv(handle, "XDG_SESSION_ID", buf, 0)) != PAM_SUCCESS) {
- pam_syslog(handle, LOG_ERR, "Failed to set session id.");
- goto finish;
- }
-
- if (!(id = pam_getenv(handle, "XDG_SESSION_ID"))) {
- pam_syslog(handle, LOG_ERR, "Failed to get session id.");
- r = PAM_SESSION_ERR;
- goto finish;
- }
- }
-
- r = asprintf(&buf, "%s/%s/%s", cgroup_user_tree, username, id);
- } else
- r = asprintf(&buf, "%s/%s/master", cgroup_user_tree, username);
-
- if (r < 0) {
- r = PAM_BUF_ERR;
- goto finish;
- }
-
- if (debug)
- pam_syslog(handle, LOG_DEBUG, "Moving new user session for %s into control group %s.", username, buf);
-
- if ((r = create_user_group(handle, SYSTEMD_CGROUP_CONTROLLER, buf, pw, true, true)) != PAM_SUCCESS)
- goto finish;
-
- /* The additional controllers don't really matter, so we
- * ignore the return value */
- STRV_FOREACH(c, controllers)
- create_user_group(handle, *c, buf, pw, true, false);
-
- STRV_FOREACH(c, reset_controllers)
- reset_group(handle, *c);
-
- r = PAM_SUCCESS;
-
-finish:
- free(buf);
-
- if (lock_fd >= 0)
- close_nointr_nofail(lock_fd);
-
- strv_free(controllers);
- strv_free(reset_controllers);
-
- free(cgroup_user_tree);
-
- return r;
-}
-
-static int session_remains(pam_handle_t *handle, const char *user_path) {
- int r;
- bool remains = false;
- DIR *d;
- char *subgroup;
-
- if ((r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, user_path, &d)) < 0)
- return r;
-
- while ((r = cg_read_subgroup(d, &subgroup)) > 0) {
-
- remains = !streq(subgroup, "master");
- free(subgroup);
-
- if (remains)
- break;
- }
-
- closedir(d);
-
- if (r < 0)
- return r;
-
- return !!remains;
-}
-
static bool check_user_lists(
pam_handle_t *handle,
uid_t uid,
@@ -588,7 +266,8 @@ static bool check_user_lists(
else {
struct passwd *pw;
- if ((pw = pam_modutil_getpwuid(handle, uid)))
+ pw = pam_modutil_getpwuid(handle, uid);
+ if (pw)
name = pw->pw_name;
}
@@ -620,158 +299,211 @@ static bool check_user_lists(
return false;
}
-_public_ PAM_EXTERN int pam_sm_close_session(
+_public_ PAM_EXTERN int pam_sm_open_session(
pam_handle_t *handle,
int flags,
int argc, const char **argv) {
const char *username = NULL;
- bool kill_session = false;
- bool kill_user = false;
- bool debug = false;
- int lock_fd = -1, r;
- char *session_path = NULL, *nosession_path = NULL, *user_path = NULL;
- const char *id;
struct passwd *pw;
- const void *created = NULL;
- char **controllers = NULL, **c, **kill_only_users = NULL, **kill_exclude_users = NULL;
- char *cgroup_user_tree = NULL;
+ bool kill_processes = false, debug = false;
+ char **controllers = NULL, **reset_controllers = NULL, **kill_only_users = NULL, **kill_exclude_users = NULL;
+ int r;
+ DBusError error;
+ uint32_t uid, pid;
+ DBusMessageIter iter;
+ dbus_bool_t kp;
+ const char *id, *object_path, *runtime_path, *service = NULL, *tty = NULL, *display = NULL, *remote_user = NULL, *remote_host = NULL, *seat = NULL, *type;
+ int session_fd = -1;
+ DBusConnection *bus = NULL;
+ DBusMessage *m = NULL, *reply = NULL;
+ dbus_bool_t remote;
assert(handle);
+ dbus_error_init(&error);
+
+ pam_syslog(handle, LOG_ERR, "pam-systemd initializing");
+
/* Make this a NOP on non-systemd systems */
if (sd_booted() <= 0)
return PAM_SUCCESS;
if (parse_argv(handle,
argc, argv,
- NULL, &kill_session, &kill_user,
- &controllers, NULL,
- &kill_only_users, &kill_exclude_users, &debug) < 0)
+ &controllers, &reset_controllers,
+ &kill_processes, &kill_only_users, &kill_exclude_users,
+ &debug) < 0)
return PAM_SESSION_ERR;
- if ((r = get_user_data(handle, &username, &pw)) != PAM_SUCCESS)
+ r = get_user_data(handle, &username, &pw);
+ if (r != PAM_SUCCESS)
goto finish;
- if ((r = cg_get_user_path(&cgroup_user_tree)) < 0) {
- pam_syslog(handle, LOG_ERR, "Failed to determine user cgroup tree: %s", strerror(-r));
- r = PAM_SYSTEM_ERR;
- goto finish;
- }
+ if (kill_processes)
+ kill_processes = check_user_lists(handle, pw->pw_uid, kill_only_users, kill_exclude_users);
- if ((lock_fd = open_file_and_lock(RUNTIME_DIR "/user/.pam-systemd-lock")) < 0) {
- pam_syslog(handle, LOG_ERR, "Failed to lock runtime directory: %m");
- r = PAM_SYSTEM_ERR;
+ bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
+ if (!bus) {
+ pam_syslog(handle, LOG_ERR, "Failed to connect to system bus: %s", bus_error_message(&error));
+ r = PAM_SESSION_ERR;
goto finish;
}
- /* We are probably still in some session/user dir. Move ourselves out of the way as first step */
- if ((r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, cgroup_user_tree, 0)) < 0)
- pam_syslog(handle, LOG_ERR, "Failed to move us away: %s", strerror(-r));
-
- STRV_FOREACH(c, controllers)
- if ((r = cg_attach(*c, cgroup_user_tree, 0)) < 0)
- pam_syslog(handle, LOG_ERR, "Failed to move us away in %s hierarchy: %s", *c, strerror(-r));
+ m = dbus_message_new_method_call(
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "CreateSession");
- if (asprintf(&user_path, "%s/%s", cgroup_user_tree, username) < 0) {
+ if (!m) {
+ pam_syslog(handle, LOG_ERR, "Could not allocate create session message.");
r = PAM_BUF_ERR;
goto finish;
}
- pam_get_data(handle, "systemd.created", &created);
-
- if ((id = pam_getenv(handle, "XDG_SESSION_ID")) && created) {
+ uid = pw->pw_uid;
+ pid = getpid();
+
+ pam_get_item(handle, PAM_SERVICE, (const void**) &service);
+ pam_get_item(handle, PAM_XDISPLAY, (const void**) &display);
+ pam_get_item(handle, PAM_TTY, (const void**) &tty);
+ pam_get_item(handle, PAM_RUSER, (const void**) &remote_user);
+ pam_get_item(handle, PAM_RHOST, (const void**) &remote_host);
+
+ if (isempty(tty))
+ service = "";
+ if (isempty(tty))
+ tty = "";
+ if (isempty(display))
+ display = "";
+ if (isempty(remote_user))
+ remote_user = "";
+ if (isempty(remote_host))
+ remote_host = "";
+ seat = "";
+
+ type = !isempty(display) ? "x11" :
+ !isempty(tty) ? "tty" : "other";
+
+ remote = !isempty(remote_host) && !streq(remote_host, "localhost") && !streq(remote_host, "localhost.localdomain");
+
+ if (!dbus_message_append_args(m,
+ DBUS_TYPE_UINT32, &uid,
+ DBUS_TYPE_UINT32, &pid,
+ DBUS_TYPE_STRING, &service,
+ DBUS_TYPE_STRING, &type,
+ DBUS_TYPE_STRING, &seat,
+ DBUS_TYPE_STRING, &tty,
+ DBUS_TYPE_STRING, &display,
+ DBUS_TYPE_BOOLEAN, &remote,
+ DBUS_TYPE_STRING, &remote_user,
+ DBUS_TYPE_STRING, &remote_host,
+ DBUS_TYPE_INVALID)) {
+ pam_syslog(handle, LOG_ERR, "Could not attach parameters to message.");
+ r = PAM_BUF_ERR;
+ goto finish;
+ }
- if (asprintf(&session_path, "%s/%s/%s", cgroup_user_tree, username, id) < 0 ||
- asprintf(&nosession_path, "%s/%s/master", cgroup_user_tree, username) < 0) {
- r = PAM_BUF_ERR;
- goto finish;
- }
+ dbus_message_iter_init_append(m, &iter);
- if (kill_session && check_user_lists(handle, pw->pw_uid, kill_only_users, kill_exclude_users)) {
- if (debug)
- pam_syslog(handle, LOG_DEBUG, "Killing remaining processes of user session %s of %s.", id, username);
+ r = bus_append_strv_iter(&iter, controllers);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Could not attach parameter to message.");
+ r = PAM_BUF_ERR;
+ goto finish;
+ }
- /* Kill processes in session cgroup, and delete it */
- if ((r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, session_path, true)) < 0)
- pam_syslog(handle, LOG_ERR, "Failed to kill session cgroup: %s", strerror(-r));
- } else {
- if (debug)
- pam_syslog(handle, LOG_DEBUG, "Moving remaining processes of user session %s of %s into control group %s.", id, username, nosession_path);
+ r = bus_append_strv_iter(&iter, reset_controllers);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Could not attach parameter to message.");
+ r = PAM_BUF_ERR;
+ goto finish;
+ }
- /* Migrate processes from session to user
- * cgroup. First, try to create the user group
- * in case it doesn't exist yet. Also, delete
- * the session group. */
- create_user_group(handle, SYSTEMD_CGROUP_CONTROLLER, nosession_path, pw, false, false);
+ kp = kill_processes;
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &kp)) {
+ pam_syslog(handle, LOG_ERR, "Could not attach parameter to message.");
+ r = PAM_BUF_ERR;
+ goto finish;
+ }
- if ((r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, session_path, nosession_path, false, true)) < 0)
- pam_syslog(handle, LOG_ERR, "Failed to migrate session cgroup: %s", strerror(-r));
- }
+ reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+ if (!reply) {
+ pam_syslog(handle, LOG_ERR, "Failed to create session: %s", bus_error_message(&error));
+ r = PAM_SESSION_ERR;
+ goto finish;
+ }
- STRV_FOREACH(c, controllers) {
- create_user_group(handle, *c, nosession_path, pw, false, false);
+ if (!dbus_message_get_args(reply, &error,
+ DBUS_TYPE_STRING, &id,
+ DBUS_TYPE_OBJECT_PATH, &object_path,
+ DBUS_TYPE_STRING, &runtime_path,
+ DBUS_TYPE_UNIX_FD, &session_fd,
+ DBUS_TYPE_INVALID)) {
+ pam_syslog(handle, LOG_ERR, "Failed to parse message: %s", bus_error_message(&error));
+ r = PAM_SESSION_ERR;
+ goto finish;
+ }
- if ((r = cg_migrate_recursive(*c, session_path, nosession_path, false, true)) < 0)
- pam_syslog(handle, LOG_ERR, "Failed to migrate session cgroup in hierarchy %s: %s", *c, strerror(-r));
- }
+ r = pam_misc_setenv(handle, "XDG_SESSION_ID", id, 0);
+ if (r != PAM_SUCCESS) {
+ pam_syslog(handle, LOG_ERR, "Failed to set session id.");
+ goto finish;
}
- /* GC user tree */
- cg_trim(SYSTEMD_CGROUP_CONTROLLER, user_path, false);
+ r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", runtime_path, 0);
+ if (r != PAM_SUCCESS) {
+ pam_syslog(handle, LOG_ERR, "Failed to set runtime dir.");
+ goto finish;
+ }
- if ((r = session_remains(handle, user_path)) < 0)
- pam_syslog(handle, LOG_ERR, "Failed to determine whether a session remains: %s", strerror(-r));
+ r = pam_set_data(handle, "systemd.session-fd", INT_TO_PTR(session_fd+1), NULL);
+ if (r != PAM_SUCCESS) {
+ pam_syslog(handle, LOG_ERR, "Failed to install session fd.");
+ return r;
+ }
- /* Kill user processes not attached to any session */
- if (kill_user && r == 0 && check_user_lists(handle, pw->pw_uid, kill_only_users, kill_exclude_users)) {
+ session_fd = -1;
- /* Kill user cgroup */
- if ((r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, user_path, true)) < 0)
- pam_syslog(handle, LOG_ERR, "Failed to kill user cgroup: %s", strerror(-r));
- } else {
+ r = PAM_SUCCESS;
- if ((r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, user_path, true)) < 0)
- pam_syslog(handle, LOG_ERR, "Failed to check user cgroup: %s", strerror(-r));
+finish:
+ strv_free(controllers);
+ strv_free(reset_controllers);
+ strv_free(kill_only_users);
+ strv_free(kill_exclude_users);
- /* Remove user cgroup */
- if (r > 0) {
- if ((r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, user_path)) < 0)
- pam_syslog(handle, LOG_ERR, "Failed to delete user cgroup: %s", strerror(-r));
+ dbus_error_free(&error);
- /* If we managed to find somebody, don't cleanup the cgroup. */
- } else if (r == 0)
- r = -EBUSY;
+ if (bus) {
+ dbus_connection_close(bus);
+ dbus_connection_unref(bus);
}
- STRV_FOREACH(c, controllers)
- cg_trim(*c, user_path, true);
-
- if (r >= 0) {
- const char *runtime_dir;
+ if (reply)
+ dbus_message_unref(reply);
- if ((runtime_dir = pam_getenv(handle, "XDG_RUNTIME_DIR")))
- if ((r = rm_rf(runtime_dir, false, true)) < 0)
- pam_syslog(handle, LOG_ERR, "Failed to remove runtime directory: %s", strerror(-r));
- }
+ if (m)
+ dbus_message_unref(m);
- /* pam_syslog(handle, LOG_DEBUG, "pam-systemd done"); */
+ if (session_fd >= 0)
+ close_nointr_nofail(session_fd);
- r = PAM_SUCCESS;
+ return r;
+}
-finish:
- if (lock_fd >= 0)
- close_nointr_nofail(lock_fd);
+_public_ PAM_EXTERN int pam_sm_close_session(
+ pam_handle_t *handle,
+ int flags,
+ int argc, const char **argv) {
- free(session_path);
- free(nosession_path);
- free(user_path);
+ const void *p = NULL;
- strv_free(controllers);
- strv_free(kill_exclude_users);
- strv_free(kill_only_users);
+ pam_get_data(handle, "systemd.session-fd", &p);
- free(cgroup_user_tree);
+ if (p)
+ close_nointr(PTR_TO_INT(p) - 1);
- return r;
+ return PAM_SUCCESS;
}
diff --git a/src/uaccess.c b/src/uaccess.c
index e55ab51..524e4f0 100644
--- a/src/uaccess.c
+++ b/src/uaccess.c
@@ -45,7 +45,7 @@ int main(int argc, char *argv[]) {
path = argv[1];
seat = argv[2];
- p = strappend("/run/systemd/seat/", seat);
+ p = strappend("/run/systemd/seats/", seat);
if (!p) {
log_error("Out of memory.");
goto finish;
diff --git a/src/util.c b/src/util.c
index 08529cc..5d57d52 100644
--- a/src/util.c
+++ b/src/util.c
@@ -4040,8 +4040,31 @@ bool tty_is_vc(const char *tty) {
if (startswith(tty, "/dev/"))
tty += 5;
- return startswith(tty, "tty") &&
- tty[3] >= '0' && tty[3] <= '9';
+ return vtnr_from_tty(tty) >= 0;
+}
+
+int vtnr_from_tty(const char *tty) {
+ int i, r;
+
+ assert(tty);
+
+ if (startswith(tty, "/dev/"))
+ tty += 5;
+
+ if (!startswith(tty, "tty") )
+ return -EINVAL;
+
+ if (tty[3] < '0' || tty[3] > '9')
+ return -EINVAL;
+
+ r = safe_atoi(tty+3, &i);
+ if (r < 0)
+ return r;
+
+ if (i < 0 || i > 63)
+ return -EINVAL;
+
+ return i;
}
const char *default_term_for_tty(const char *tty) {
@@ -5068,6 +5091,38 @@ int symlink_or_copy_atomic(const char *from, const char *to) {
return r;
}
+int audit_session_from_pid(pid_t pid, uint32_t *id) {
+ char *p, *s;
+ uint32_t u;
+ int r;
+
+ assert(pid >= 1);
+ assert(id);
+
+ if (have_effective_cap(CAP_AUDIT_CONTROL) <= 0)
+ return -ENOENT;
+
+ if (asprintf(&p, "/proc/%lu/sessionid", (unsigned long) pid) < 0)
+ return -ENOMEM;
+
+ r = read_one_line_file(p, &s);
+ free(p);
+ if (r < 0)
+ return r;
+
+ r = safe_atou32(s, &u);
+ free(s);
+
+ if (r < 0)
+ return r;
+
+ if (u == (uint32_t) -1 || u <= 0)
+ return -ENOENT;
+
+ *id = u;
+ return 0;
+}
+
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",
diff --git a/src/util.h b/src/util.h
index 76e1d4f..ceabe92 100644
--- a/src/util.h
+++ b/src/util.h
@@ -396,6 +396,7 @@ char *fstab_node_to_udev_node(const char *p);
void filter_environ(const char *prefix);
bool tty_is_vc(const char *tty);
+int vtnr_from_tty(const char *tty);
const char *default_term_for_tty(const char *tty);
int detect_vm(const char **id);
@@ -439,6 +440,8 @@ int hwclock_reset_localtime_delta(void);
int hwclock_get_time(struct tm *tm);
int hwclock_set_time(const struct tm *tm);
+int audit_session_from_pid(pid_t pid, uint32_t *id);
+
#define NULSTR_FOREACH(i, l) \
for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
commit 77527da0a02029ce9c5ec86d5db5ea42147a658f
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jun 21 22:29:25 2011 +0200
logind: make idle hint logic work
diff --git a/src/logind-dbus.c b/src/logind-dbus.c
index f73307f..662ffd0 100644
--- a/src/logind-dbus.c
+++ b/src/logind-dbus.c
@@ -130,13 +130,13 @@
static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
Manager *m = data;
- bool b;
+ dbus_bool_t b;
assert(i);
assert(property);
assert(m);
- b = manager_get_idle_hint(m, NULL);
+ b = manager_get_idle_hint(m, NULL) > 0;
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
return -ENOMEM;
diff --git a/src/logind-seat-dbus.c b/src/logind-seat-dbus.c
index 1895fe6..4a4527d 100644
--- a/src/logind-seat-dbus.c
+++ b/src/logind-seat-dbus.c
@@ -151,13 +151,13 @@ static int bus_seat_append_can_activate(DBusMessageIter *i, const char *property
static int bus_seat_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
Seat *s = data;
- bool b;
+ dbus_bool_t b;
assert(i);
assert(property);
assert(s);
- b = seat_get_idle_hint(s, NULL);
+ b = seat_get_idle_hint(s, NULL) > 0;
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
return -ENOMEM;
diff --git a/src/logind-seat.c b/src/logind-seat.c
index 09356b6..12a1b80 100644
--- a/src/logind-seat.c
+++ b/src/logind-seat.c
@@ -230,8 +230,7 @@ int seat_set_active(Seat *s, Session *session) {
Session *old_active;
assert(s);
- assert(session);
- assert(session->seat == s);
+ assert(!session || session->seat == s);
if (session == s->active)
return 0;
diff --git a/src/logind-session-dbus.c b/src/logind-session-dbus.c
index 0ce880c..b0e592d 100644
--- a/src/logind-session-dbus.c
+++ b/src/logind-session-dbus.c
@@ -144,7 +144,7 @@ static int bus_session_append_user(DBusMessageIter *i, const char *property, voi
static int bus_session_append_active(DBusMessageIter *i, const char *property, void *data) {
Session *s = data;
- bool b;
+ dbus_bool_t b;
assert(i);
assert(property);
@@ -159,13 +159,13 @@ static int bus_session_append_active(DBusMessageIter *i, const char *property, v
static int bus_session_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
Session *s = data;
- bool b;
+ int b;
assert(i);
assert(property);
assert(s);
- b = session_get_idle_hint(s, NULL);
+ b = session_get_idle_hint(s, NULL) > 0;
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
return -ENOMEM;
diff --git a/src/logind-user-dbus.c b/src/logind-user-dbus.c
index 623f2c9..5926dcf 100644
--- a/src/logind-user-dbus.c
+++ b/src/logind-user-dbus.c
@@ -154,13 +154,14 @@ static int bus_user_append_sessions(DBusMessageIter *i, const char *property, vo
static int bus_user_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
User *u = data;
- bool b;
+ dbus_bool_t b;
assert(i);
assert(property);
assert(u);
- b = user_get_idle_hint(u, NULL);
+ b = user_get_idle_hint(u, NULL) > 0;
+
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
return -ENOMEM;
commit 9418f14772e7e646fe981d45506b3bbce68d6ccf
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jun 21 21:46:13 2011 +0200
logind: send out PropertyChanged signals where appropriate
diff --git a/src/logind-dbus.c b/src/logind-dbus.c
index f9ee7e5..f73307f 100644
--- a/src/logind-dbus.c
+++ b/src/logind-dbus.c
@@ -604,3 +604,25 @@ oom:
const DBusObjectPathVTable bus_manager_vtable = {
.message_function = manager_message_handler
};
+
+int manager_send_changed(Manager *manager, const char *properties) {
+ DBusMessage *m;
+ int r = -ENOMEM;
+
+ assert(manager);
+
+ m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
+ if (!m)
+ goto finish;
+
+ if (!dbus_connection_send(manager->bus, m, NULL))
+ goto finish;
+
+ r = 0;
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ return r;
+}
diff --git a/src/logind-seat-dbus.c b/src/logind-seat-dbus.c
index 33eafe5..1895fe6 100644
--- a/src/logind-seat-dbus.c
+++ b/src/logind-seat-dbus.c
@@ -370,3 +370,31 @@ finish:
return r;
}
+
+int seat_send_changed(Seat *s, const char *properties) {
+ DBusMessage *m;
+ int r = -ENOMEM;
+ char *p = NULL;
+
+ assert(s);
+
+ p = seat_bus_path(s);
+ if (!p)
+ return -ENOMEM;
+
+ m = bus_properties_changed_new(p, "org.freedesktop.login1.Seat", properties);
+ if (!m)
+ goto finish;
+
+ if (!dbus_connection_send(s->manager->bus, m, NULL))
+ goto finish;
+
+ r = 0;
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+ free(p);
+
+ return r;
+}
diff --git a/src/logind-seat.c b/src/logind-seat.c
index 95c66dd..09356b6 100644
--- a/src/logind-seat.c
+++ b/src/logind-seat.c
@@ -226,8 +226,33 @@ int seat_apply_acls(Seat *s, Session *old_active) {
return r;
}
+int seat_set_active(Seat *s, Session *session) {
+ Session *old_active;
+
+ assert(s);
+ assert(session);
+ assert(session->seat == s);
+
+ if (session == s->active)
+ return 0;
+
+ old_active = s->active;
+ s->active = session;
+
+ seat_apply_acls(s, old_active);
+
+ if (session && session->started)
+ session_send_changed(session, "Active\0");
+
+ if (!session || session->started)
+ seat_send_changed(s, "ActiveSession\0");
+
+ return 0;
+}
+
int seat_active_vt_changed(Seat *s, int vtnr) {
- Session *i, *new_active = NULL, *old_active;
+ Session *i, *new_active = NULL;
+ int r;
assert(s);
assert(vtnr >= 1);
@@ -243,16 +268,10 @@ int seat_active_vt_changed(Seat *s, int vtnr) {
break;
}
- if (new_active == s->active)
- return 0;
-
- old_active = s->active;
- s->active = new_active;
-
- seat_apply_acls(s, old_active);
+ r = seat_set_active(s, new_active);
manager_spawn_autovt(s->manager, vtnr);
- return 0;
+ return r;
}
int seat_read_active_vt(Seat *s) {
@@ -361,17 +380,19 @@ int seat_attach_session(Seat *s, Session *session) {
assert(session);
assert(!session->seat);
- if (!seat_is_vtconsole(s)) {
- if (s->sessions)
- return -EEXIST;
-
- assert(!s->active);
- s->active = session;
- }
+ if (!seat_is_vtconsole(s) && s->sessions)
+ return -EEXIST;
session->seat = s;
LIST_PREPEND(Session, sessions_by_seat, s->sessions, session);
+ seat_send_changed(s, "Sessions\0");
+
+ if (!seat_is_vtconsole(s)) {
+ assert(!s->active);
+ seat_set_active(s, session);
+ }
+
return 0;
}
diff --git a/src/logind-seat.h b/src/logind-seat.h
index a7cd6c7..275939e 100644
--- a/src/logind-seat.h
+++ b/src/logind-seat.h
@@ -54,6 +54,7 @@ int seat_save(Seat *s);
int seat_load(Seat *s);
int seat_apply_acls(Seat *s, Session *old_active);
+int seat_set_active(Seat *s, Session *session);
int seat_active_vt_changed(Seat *s, int vtnr);
int seat_read_active_vt(Seat *s);
@@ -75,5 +76,6 @@ char *seat_bus_path(Seat *s);
extern const DBusObjectPathVTable bus_seat_vtable;
int seat_send_signal(Seat *s, bool new_seat);
+int seat_send_changed(Seat *s, const char *properties);
#endif
diff --git a/src/logind-session-dbus.c b/src/logind-session-dbus.c
index edc96dd..0ce880c 100644
--- a/src/logind-session-dbus.c
+++ b/src/logind-session-dbus.c
@@ -419,3 +419,31 @@ finish:
return r;
}
+
+int session_send_changed(Session *s, const char *properties) {
+ DBusMessage *m;
+ int r = -ENOMEM;
+ char *p = NULL;
+
+ assert(s);
+
+ p = session_bus_path(s);
+ if (!p)
+ return -ENOMEM;
+
+ m = bus_properties_changed_new(p, "org.freedesktop.login1.Session", properties);
+ if (!m)
+ goto finish;
+
+ if (!dbus_connection_send(s->manager->bus, m, NULL))
+ goto finish;
+
+ r = 0;
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+ free(p);
+
+ return r;
+}
diff --git a/src/logind-session.c b/src/logind-session.c
index 26f857d..5ba6b21 100644
--- a/src/logind-session.c
+++ b/src/logind-session.c
@@ -76,8 +76,12 @@ void session_free(Session *s) {
s->user->display = NULL;
}
- if (s->seat)
+ if (s->seat) {
+ if (s->seat->active == s)
+ s->seat->active = NULL;
+
LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
+ }
free(s->cgroup_path);
strv_free(s->controllers);
@@ -229,7 +233,7 @@ int session_load(Session *s) {
s->kill_processes = k;
}
- if (seat) {
+ if (seat && !s->seat) {
Seat *o;
o = hashmap_get(s->manager->seats, seat);
@@ -430,6 +434,9 @@ int session_start(Session *s) {
assert(s);
assert(s->user);
+ if (s->started)
+ return 0;
+
/* Create cgroup */
r = session_create_cgroup(s);
if (r < 0)
@@ -443,8 +450,19 @@ int session_start(Session *s) {
dual_timestamp_get(&s->timestamp);
+ s->started = true;
+
session_send_signal(s, true);
+ if (s->seat) {
+ if (s->seat->active == s)
+ seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
+ else
+ seat_send_changed(s->seat, "Sessions\0");
+ }
+
+ user_send_changed(s->user, "Sessions\0");
+
return 0;
}
@@ -521,7 +539,8 @@ int session_stop(Session *s) {
assert(s);
- session_send_signal(s, false);
+ if (!s->started)
+ return 0;
/* Kill cgroup */
k = session_kill_cgroup(s);
@@ -534,6 +553,19 @@ int session_stop(Session *s) {
unlink(s->state_file);
session_add_to_gc_queue(s);
+ session_send_signal(s, false);
+
+ if (s->seat) {
+ if (s->seat->active == s)
+ seat_set_active(s->seat, NULL);
+
+ seat_send_changed(s->seat, "Sessions\0");
+ }
+
+ user_send_changed(s->user, "Sessions\0");
+
+ s->started = false;
+
return r;
}
@@ -607,6 +639,27 @@ void session_set_idle_hint(Session *s, bool b) {
s->idle_hint = b;
dual_timestamp_get(&s->idle_hint_timestamp);
+
+ session_send_changed(s,
+ "IdleHint\0"
+ "IdleSinceHint\0"
+ "IdleSinceHintMonotonic\0");
+
+ if (s->seat)
+ seat_send_changed(s->seat,
+ "IdleHint\0"
+ "IdleSinceHint\0"
+ "IdleSinceHintMonotonic\0");
+
+ user_send_changed(s->user,
+ "IdleHint\0"
+ "IdleSinceHint\0"
+ "IdleSinceHintMonotonic\0");
+
+ manager_send_changed(s->manager,
+ "IdleHint\0"
+ "IdleSinceHint\0"
+ "IdleSinceHintMonotonic\0");
}
int session_check_gc(Session *s) {
diff --git a/src/logind-session.h b/src/logind-session.h
index a30c3e7..d2f2552 100644
--- a/src/logind-session.h
+++ b/src/logind-session.h
@@ -72,6 +72,7 @@ struct Session {
bool kill_processes;
bool in_gc_queue:1;
+ bool started:1;
LIST_FIELDS(Session, sessions_by_user);
LIST_FIELDS(Session, sessions_by_seat);
@@ -97,6 +98,7 @@ char *session_bus_path(Session *s);
extern const DBusObjectPathVTable bus_session_vtable;
int session_send_signal(Session *s, bool new_session);
+int session_send_changed(Session *s, const char *properties);
const char* session_type_to_string(SessionType t);
SessionType session_type_from_string(const char *s);
diff --git a/src/logind-user-dbus.c b/src/logind-user-dbus.c
index c8d47de..623f2c9 100644
--- a/src/logind-user-dbus.c
+++ b/src/logind-user-dbus.c
@@ -353,3 +353,31 @@ finish:
return r;
}
+
+int user_send_changed(User *u, const char *properties) {
+ DBusMessage *m;
+ int r = -ENOMEM;
+ char *p = NULL;
+
+ assert(u);
+
+ p = user_bus_path(u);
+ if (!p)
+ return -ENOMEM;
+
+ m = bus_properties_changed_new(p, "org.freedesktop.login1.User", properties);
+ if (!m)
+ goto finish;
+
+ if (!dbus_connection_send(u->manager->bus, m, NULL))
+ goto finish;
+
+ r = 0;
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+ free(p);
+
+ return r;
+}
diff --git a/src/logind-user.c b/src/logind-user.c
index 70d6a9a..cb3e441 100644
--- a/src/logind-user.c
+++ b/src/logind-user.c
@@ -260,6 +260,9 @@ int user_start(User *u) {
assert(u);
+ if (u->started)
+ return 0;
+
/* Make XDG_RUNTIME_DIR */
r = user_mkdir_runtime_path(u);
if (r < 0)
@@ -280,6 +283,8 @@ int user_start(User *u) {
dual_timestamp_get(&u->timestamp);
+ u->started = true;
+
user_send_signal(u, true);
return 0;
@@ -361,6 +366,9 @@ int user_stop(User *u) {
int r = 0, k;
assert(u);
+ if (!u->started)
+ return 0;
+
LIST_FOREACH(sessions_by_user, s, u->sessions) {
k = session_stop(s);
if (k < 0)
@@ -387,6 +395,8 @@ int user_stop(User *u) {
unlink(u->state_file);
user_add_to_gc_queue(u);
+ u->started = false;
+
return r;
}
diff --git a/src/logind-user.h b/src/logind-user.h
index c6f1401..dd0dcad 100644
--- a/src/logind-user.h
+++ b/src/logind-user.h
@@ -55,6 +55,7 @@ struct User {
dual_timestamp timestamp;
bool in_gc_queue:1;
+ bool started:1;
LIST_HEAD(Session, sessions);
LIST_FIELDS(User, gc_queue);
@@ -76,6 +77,7 @@ char *user_bus_path(User *s);
extern const DBusObjectPathVTable bus_user_vtable;
int user_send_signal(User *u, bool new_user);
+int user_send_changed(User *u, const char *properties);
const char* user_state_to_string(UserState s);
UserState user_state_from_string(const char *s);
diff --git a/src/logind.c b/src/logind.c
index d72a5bf..cdb4da7 100644
--- a/src/logind.c
+++ b/src/logind.c
@@ -890,7 +890,6 @@ int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
return idle_hint;
}
-
int manager_startup(Manager *m) {
int r;
Seat *seat;
diff --git a/src/logind.h b/src/logind.h
index e18a357..1b7a2b2 100644
--- a/src/logind.h
+++ b/src/logind.h
@@ -114,4 +114,6 @@ bool x11_display_is_local(const char *display);
extern const DBusObjectPathVTable bus_manager_vtable;
+int manager_send_changed(Manager *manager, const char *properties);
+
#endif
commit da11939561b1e6eeb1131b68dbf43042fd633a05
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jun 21 20:43:34 2011 +0200
logind: send dbus signals when sessions/users/seats come and go
diff --git a/src/logind-seat-dbus.c b/src/logind-seat-dbus.c
index 32171ce..33eafe5 100644
--- a/src/logind-seat-dbus.c
+++ b/src/logind-seat-dbus.c
@@ -333,3 +333,40 @@ char *seat_bus_path(Seat *s) {
return r;
}
+
+int seat_send_signal(Seat *s, bool new_seat) {
+ DBusMessage *m;
+ int r = -ENOMEM;
+ char *p = NULL;
+
+ assert(s);
+
+ m = dbus_message_new_signal("/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ new_seat ? "SeatNew" : "SeatRemoved");
+
+ if (!m)
+ return -ENOMEM;
+
+ p = seat_bus_path(s);
+ if (!p)
+ goto finish;
+
+ if (!dbus_message_append_args(
+ m,
+ DBUS_TYPE_STRING, &s->id,
+ DBUS_TYPE_OBJECT_PATH, &p,
+ DBUS_TYPE_INVALID))
+ goto finish;
+
+ if (!dbus_connection_send(s->manager->bus, m, NULL))
+ goto finish;
+
+ r = 0;
+
+finish:
+ dbus_message_unref(m);
+ free(p);
+
+ return r;
+}
diff --git a/src/logind-seat.c b/src/logind-seat.c
index 751f59a..95c66dd 100644
--- a/src/logind-seat.c
+++ b/src/logind-seat.c
@@ -314,6 +314,8 @@ int seat_start(Seat *s) {
s->started = true;
+ seat_send_signal(s, true);
+
return 0;
}
@@ -327,6 +329,8 @@ int seat_stop(Seat *s) {
log_info("Removed seat %s.", s->id);
+ seat_send_signal(s, false);
+
seat_stop_sessions(s);
unlink(s->state_file);
diff --git a/src/logind-seat.h b/src/logind-seat.h
index dfbb2a2..a7cd6c7 100644
--- a/src/logind-seat.h
+++ b/src/logind-seat.h
@@ -74,4 +74,6 @@ char *seat_bus_path(Seat *s);
extern const DBusObjectPathVTable bus_seat_vtable;
+int seat_send_signal(Seat *s, bool new_seat);
+
#endif
diff --git a/src/logind-session-dbus.c b/src/logind-session-dbus.c
index 6bded6a..edc96dd 100644
--- a/src/logind-session-dbus.c
+++ b/src/logind-session-dbus.c
@@ -382,3 +382,40 @@ char *session_bus_path(Session *s) {
return r;
}
+
+int session_send_signal(Session *s, bool new_session) {
+ DBusMessage *m;
+ int r = -ENOMEM;
+ char *p = NULL;
+
+ assert(s);
+
+ m = dbus_message_new_signal("/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ new_session ? "SessionNew" : "SessionRemoved");
+
+ if (!m)
+ return -ENOMEM;
+
+ p = session_bus_path(s);
+ if (!p)
+ goto finish;
+
+ if (!dbus_message_append_args(
+ m,
+ DBUS_TYPE_STRING, &s->id,
+ DBUS_TYPE_OBJECT_PATH, &p,
+ DBUS_TYPE_INVALID))
+ goto finish;
+
+ if (!dbus_connection_send(s->manager->bus, m, NULL))
+ goto finish;
+
+ r = 0;
+
+finish:
+ dbus_message_unref(m);
+ free(p);
+
+ return r;
+}
diff --git a/src/logind-session.c b/src/logind-session.c
index 0d34037..26f857d 100644
--- a/src/logind-session.c
+++ b/src/logind-session.c
@@ -443,6 +443,8 @@ int session_start(Session *s) {
dual_timestamp_get(&s->timestamp);
+ session_send_signal(s, true);
+
return 0;
}
@@ -519,6 +521,8 @@ int session_stop(Session *s) {
assert(s);
+ session_send_signal(s, false);
+
/* Kill cgroup */
k = session_kill_cgroup(s);
if (k < 0)
diff --git a/src/logind-session.h b/src/logind-session.h
index 9f58165..a30c3e7 100644
--- a/src/logind-session.h
+++ b/src/logind-session.h
@@ -96,6 +96,8 @@ char *session_bus_path(Session *s);
extern const DBusObjectPathVTable bus_session_vtable;
+int session_send_signal(Session *s, bool new_session);
+
const char* session_type_to_string(SessionType t);
SessionType session_type_from_string(const char *s);
diff --git a/src/logind-user-dbus.c b/src/logind-user-dbus.c
index 3be2c05..c8d47de 100644
--- a/src/logind-user-dbus.c
+++ b/src/logind-user-dbus.c
@@ -313,3 +313,43 @@ char *user_bus_path(User *u) {
return s;
}
+
+int user_send_signal(User *u, bool new_user) {
+ DBusMessage *m;
+ int r = -ENOMEM;
+ char *p = NULL;
+ uint32_t uid;
+
+ assert(u);
+
+ m = dbus_message_new_signal("/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ new_user ? "UserNew" : "UserRemoved");
+
+ if (!m)
+ return -ENOMEM;
+
+ p = user_bus_path(u);
+ if (!p)
+ goto finish;
+
+ uid = u->uid;
+
+ if (!dbus_message_append_args(
+ m,
+ DBUS_TYPE_UINT32, &uid,
+ DBUS_TYPE_OBJECT_PATH, &p,
+ DBUS_TYPE_INVALID))
+ goto finish;
+
+ if (!dbus_connection_send(u->manager->bus, m, NULL))
+ goto finish;
+
+ r = 0;
+
+finish:
+ dbus_message_unref(m);
+ free(p);
+
+ return r;
+}
diff --git a/src/logind-user.c b/src/logind-user.c
index 206064f..70d6a9a 100644
--- a/src/logind-user.c
+++ b/src/logind-user.c
@@ -280,6 +280,8 @@ int user_start(User *u) {
dual_timestamp_get(&u->timestamp);
+ user_send_signal(u, true);
+
return 0;
}
@@ -365,6 +367,8 @@ int user_stop(User *u) {
r = k;
}
+ user_send_signal(u, false);
+
/* Kill systemd */
k = user_stop_service(u);
if (k < 0)
diff --git a/src/logind-user.h b/src/logind-user.h
index c891119..c6f1401 100644
--- a/src/logind-user.h
+++ b/src/logind-user.h
@@ -75,6 +75,8 @@ char *user_bus_path(User *s);
extern const DBusObjectPathVTable bus_user_vtable;
+int user_send_signal(User *u, bool new_user);
+
const char* user_state_to_string(UserState s);
UserState user_state_from_string(const char *s);
commit e1c9c2d53606f987110b4215cf08c236af637ff1
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jun 21 20:14:24 2011 +0200
logind: implement ListXXX bus methods
diff --git a/src/logind-dbus.c b/src/logind-dbus.c
index f7ec148..f9ee7e5 100644
--- a/src/logind-dbus.c
+++ b/src/logind-dbus.c
@@ -40,7 +40,7 @@
" <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
" </method>\n" \
" <method name=\"ListSessions\">\n" \
- " <arg name=\"users\" type=\"a(sussso)\" direction=\"out\"/>\n" \
+ " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
" </method>\n" \
" <method name=\"ListUsers\">\n" \
" <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
@@ -294,6 +294,137 @@ static DBusHandlerResult manager_message_handler(
if (!b)
goto oom;
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
+ char *p;
+ Session *session;
+ Iterator i;
+ DBusMessageIter iter, sub;
+ const char *empty = "";
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ goto oom;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "susso", &sub))
+ goto oom;
+
+ HASHMAP_FOREACH(session, m->sessions, i) {
+ DBusMessageIter sub2;
+ uint32_t uid;
+
+ if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
+ goto oom;
+
+ uid = session->user->uid;
+
+ p = session_bus_path(session);
+ if (!p)
+ goto oom;
+
+ if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
+ !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
+ !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
+ !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
+ !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
+ free(p);
+ goto oom;
+ }
+
+ free(p);
+
+ if (!dbus_message_iter_close_container(&sub, &sub2))
+ goto oom;
+ }
+
+ if (!dbus_message_iter_close_container(&iter, &sub))
+ goto oom;
+
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
+ char *p;
+ User *user;
+ Iterator i;
+ DBusMessageIter iter, sub;
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ goto oom;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "uso", &sub))
+ goto oom;
+
+ HASHMAP_FOREACH(user, m->users, i) {
+ DBusMessageIter sub2;
+ uint32_t uid;
+
+ if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
+ goto oom;
+
+ uid = user->uid;
+
+ p = user_bus_path(user);
+ if (!p)
+ goto oom;
+
+ if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
+ !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
+ !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
+ free(p);
+ goto oom;
+ }
+
+ free(p);
+
+ if (!dbus_message_iter_close_container(&sub, &sub2))
+ goto oom;
+ }
+
+ if (!dbus_message_iter_close_container(&iter, &sub))
+ goto oom;
+
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
+ char *p;
+ Seat *seat;
+ Iterator i;
+ DBusMessageIter iter, sub;
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ goto oom;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "so", &sub))
+ goto oom;
+
+ HASHMAP_FOREACH(seat, m->seats, i) {
+ DBusMessageIter sub2;
+
+ if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
+ goto oom;
+
+ p = seat_bus_path(seat);
+ if (!p)
+ goto oom;
+
+ if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
+ !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
+ free(p);
+ goto oom;
+ }
+
+ free(p);
+
+ if (!dbus_message_iter_close_container(&sub, &sub2))
+ goto oom;
+ }
+
+ if (!dbus_message_iter_close_container(&iter, &sub))
+ goto oom;
+
} else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
const char *name;
Session *session;
commit bef422ae1e7cbe77ad72dcbfe44798b0fe5e2931
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jun 21 19:20:05 2011 +0200
logind: implement more dbus functionality
diff --git a/src/logind-dbus.c b/src/logind-dbus.c
index 42374d7..f7ec148 100644
--- a/src/logind-dbus.c
+++ b/src/logind-dbus.c
@@ -27,26 +27,26 @@
#define BUS_MANAGER_INTERFACE \
" <interface name=\"org.freedesktop.login1.Manager\">\n" \
- " <method name=\"GetSeat\">\n" \
+ " <method name=\"GetSession\">\n" \
" <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
+ " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
" </method>\n" \
" <method name=\"GetUser\">\n" \
- " <arg name=\"uid\" type=\"t\" direction=\"in\"/>\n" \
+ " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
" <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
" </method>\n" \
- " <method name=\"GetSession\">\n" \
+ " <method name=\"GetSeat\">\n" \
" <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
+ " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
" </method>\n" \
- " <method name=\"ListSeats\">\n" \
- " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
+ " <method name=\"ListSessions\">\n" \
+ " <arg name=\"users\" type=\"a(sussso)\" direction=\"out\"/>\n" \
" </method>\n" \
" <method name=\"ListUsers\">\n" \
" <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
" </method>\n" \
- " <method name=\"ListSessions\">\n" \
- " <arg name=\"users\" type=\"a(sussso)\" direction=\"out\"/>\n" \
+ " <method name=\"ListSeats\">\n" \
+ " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
" </method>\n" \
" <method name=\"CreateSession\">\n" \
" <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
@@ -72,7 +72,7 @@
" <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
" </method>\n" \
" <method name=\"TerminateUser\">\n" \
- " <arg name=\"uid\" type=\"t\" direction=\"in\"/>\n" \
+ " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
" </method>\n" \
" <method name=\"TerminateSeat\">\n" \
" <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
@@ -184,6 +184,7 @@ static DBusHandlerResult manager_message_handler(
DBusError error;
DBusMessage *reply = NULL;
+ int r;
assert(connection);
assert(message);
@@ -191,7 +192,201 @@ static DBusHandlerResult manager_message_handler(
dbus_error_init(&error);
- if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
+ if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
+ const char *name;
+ char *p;
+ Session *session;
+ bool b;
+
+ if (!dbus_message_get_args(
+ message,
+ &error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+ return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+ session = hashmap_get(m->sessions, name);
+ if (!session)
+ return bus_send_error_reply(connection, message, &error, -ENOENT);
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ goto oom;
+
+ p = session_bus_path(session);
+ if (!p)
+ goto oom;
+
+ b = dbus_message_append_args(
+ reply,
+ DBUS_TYPE_OBJECT_PATH, &p,
+ DBUS_TYPE_INVALID);
+ free(p);
+
+ if (!b)
+ goto oom;
+
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
+ uint32_t uid;
+ char *p;
+ User *user;
+ bool b;
+
+ if (!dbus_message_get_args(
+ message,
+ &error,
+ DBUS_TYPE_UINT32, &uid,
+ DBUS_TYPE_INVALID))
+ return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+ user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
+ if (!user)
+ return bus_send_error_reply(connection, message, &error, -ENOENT);
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ goto oom;
+
+ p = user_bus_path(user);
+ if (!p)
+ goto oom;
+
+ b = dbus_message_append_args(
+ reply,
+ DBUS_TYPE_OBJECT_PATH, &p,
+ DBUS_TYPE_INVALID);
+ free(p);
+
+ if (!b)
+ goto oom;
+
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
+ const char *name;
+ char *p;
+ Seat *seat;
+ bool b;
+
+ if (!dbus_message_get_args(
+ message,
+ &error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+ return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+ seat = hashmap_get(m->seats, name);
+ if (!seat)
+ return bus_send_error_reply(connection, message, &error, -ENOENT);
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ goto oom;
+
+ p = seat_bus_path(seat);
+ if (!p)
+ goto oom;
+
+ b = dbus_message_append_args(
+ reply,
+ DBUS_TYPE_OBJECT_PATH, &p,
+ DBUS_TYPE_INVALID);
+ free(p);
+
+ if (!b)
+ goto oom;
+
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
+ const char *name;
+ Session *session;
+
+ if (!dbus_message_get_args(
+ message,
+ &error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+ return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+ session = hashmap_get(m->sessions, name);
+ if (!session)
+ return bus_send_error_reply(connection, message, &error, -ENOENT);
+
+ r = session_activate(session);
+ if (r < 0)
+ return bus_send_error_reply(connection, message, NULL, r);
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ goto oom;
+
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
+ const char *name;
+ Session *session;
+
+ if (!dbus_message_get_args(
+ message,
+ &error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+ return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+ session = hashmap_get(m->sessions, name);
+ if (!session)
+ return bus_send_error_reply(connection, message, &error, -ENOENT);
+
+ r = session_stop(session);
+ if (r < 0)
+ return bus_send_error_reply(connection, message, NULL, r);
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ goto oom;
+
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
+ uint32_t uid;
+ User *user;
+
+ if (!dbus_message_get_args(
+ message,
+ &error,
+ DBUS_TYPE_UINT32, &uid,
+ DBUS_TYPE_INVALID))
+ return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+ user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
+ if (!user)
+ return bus_send_error_reply(connection, message, &error, -ENOENT);
+
+ r = user_stop(user);
+ if (r < 0)
+ return bus_send_error_reply(connection, message, NULL, r);
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ goto oom;
+
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
+ const char *name;
+ Seat *seat;
+
+ if (!dbus_message_get_args(
+ message,
+ &error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+ return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+ seat = hashmap_get(m->seats, name);
+ if (!seat)
+ return bus_send_error_reply(connection, message, &error, -ENOENT);
+
+ r = seat_stop_sessions(seat);
+ if (r < 0)
+ return bus_send_error_reply(connection, message, NULL, r);
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ goto oom;
+
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
char *introspection = NULL;
FILE *f;
Iterator i;
diff --git a/src/logind-session-dbus.c b/src/logind-session-dbus.c
index 8b5b3ad..6bded6a 100644
--- a/src/logind-session-dbus.c
+++ b/src/logind-session-dbus.c
@@ -249,11 +249,90 @@ static DBusHandlerResult session_message_dispatch(
{ NULL, NULL, NULL, NULL, NULL }
};
+ DBusError error;
+ DBusMessage *reply = NULL;
+ int r;
+
assert(s);
assert(connection);
assert(message);
- return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+ dbus_error_init(&error);
+
+ if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Terminate")) {
+
+ r = session_stop(s);
+ if (r < 0)
+ return bus_send_error_reply(connection, message, NULL, r);
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ goto oom;
+
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Activate")) {
+
+ r = session_activate(s);
+ if (r < 0)
+ return bus_send_error_reply(connection, message, NULL, r);
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ goto oom;
+
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Lock") ||
+ dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Unlock")) {
+ bool b;
+ DBusMessage *sig;
+
+ sig = dbus_message_new_signal(dbus_message_get_path(message), "org.freedesktop.login1.Session", dbus_message_get_member(message));
+ if (!sig)
+ goto oom;
+
+ b = dbus_connection_send(connection, sig, NULL);
+ dbus_message_unref(sig);
+
+ if (!b)
+ goto oom;
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ goto oom;
+
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "SetIdleHint")) {
+ dbus_bool_t b;
+
+ if (!dbus_message_get_args(
+ message,
+ &error,
+ DBUS_TYPE_BOOLEAN, &b,
+ DBUS_TYPE_INVALID))
+ return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+ session_set_idle_hint(s, b);
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ goto oom;
+
+ } else
+ return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+
+ if (reply) {
+ if (!dbus_connection_send(connection, reply, NULL))
+ goto oom;
+
+ dbus_message_unref(reply);
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+
+oom:
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
static DBusHandlerResult session_message_handler(
diff --git a/src/logind-session.c b/src/logind-session.c
index 89fe02c..0d34037 100644
--- a/src/logind-session.c
+++ b/src/logind-session.c
@@ -595,6 +595,16 @@ dont_know:
return 0;
}
+void session_set_idle_hint(Session *s, bool b) {
+ assert(s);
+
+ if (s->idle_hint == b)
+ return;
+
+ s->idle_hint = b;
+ dual_timestamp_get(&s->idle_hint_timestamp);
+}
+
int session_check_gc(Session *s) {
int r;
diff --git a/src/logind-session.h b/src/logind-session.h
index 7682393..9f58165 100644
--- a/src/logind-session.h
+++ b/src/logind-session.h
@@ -86,6 +86,7 @@ void session_add_to_gc_queue(Session *s);
int session_activate(Session *s);
bool session_is_active(Session *s);
int session_get_idle_hint(Session *s, dual_timestamp *t);
+void session_set_idle_hint(Session *s, bool b);
int session_start(Session *s);
int session_stop(Session *s);
int session_save(Session *s);
commit a185c5aa2d8bef98716f8cf160da263c17e588b2
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Jun 17 15:59:18 2011 +0200
logind: implement idle hint logic
diff --git a/src/logind-dbus.c b/src/logind-dbus.c
index 90db941..42374d7 100644
--- a/src/logind-dbus.c
+++ b/src/logind-dbus.c
@@ -19,6 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <errno.h>
+#include <string.h>
+
#include "logind.h"
#include "dbus-common.h"
@@ -62,6 +65,9 @@
" <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
" <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
" </method>\n" \
+ " <method name=\"ActivateSession\">\n" \
+ " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
+ " </method>\n" \
" <method name=\"TerminateSession\">\n" \
" <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
" </method>\n" \
@@ -102,6 +108,9 @@
" <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
" <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
" <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
+ " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
" </interface>\n"
#define INTROSPECTION_BEGIN \
@@ -119,6 +128,39 @@
BUS_GENERIC_INTERFACES_LIST \
"org.freedesktop.login1.Manager\0"
+static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
+ Manager *m = data;
+ bool b;
+
+ assert(i);
+ assert(property);
+ assert(m);
+
+ b = manager_get_idle_hint(m, NULL);
+ if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
+ Manager *m = data;
+ dual_timestamp t;
+ uint64_t u;
+
+ assert(i);
+ assert(property);
+ assert(m);
+
+ manager_get_idle_hint(m, &t);
+ u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
+
+ if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
+ return -ENOMEM;
+
+ return 0;
+}
+
static DBusHandlerResult manager_message_handler(
DBusConnection *connection,
DBusMessage *message,
@@ -127,13 +169,16 @@ static DBusHandlerResult manager_message_handler(
Manager *m = userdata;
const BusProperty properties[] = {
- { "org.freedesktop.login1.Manager", "ControlGroupHierarchy", bus_property_append_string, "s", m->cgroup_path },
- { "org.freedesktop.login1.Manager", "Controllers", bus_property_append_strv, "as", m->controllers },
- { "org.freedesktop.login1.Manager", "ResetControllers", bus_property_append_strv, "as", m->reset_controllers },
- { "org.freedesktop.login1.Manager", "NAutoVTs", bus_property_append_unsigned, "u", &m->n_autovts },
- { "org.freedesktop.login1.Manager", "KillOnlyUsers", bus_property_append_strv, "as", m->kill_only_users },
- { "org.freedesktop.login1.Manager", "KillExcludeUsers", bus_property_append_strv, "as", m->kill_exclude_users },
- { "org.freedesktop.login1.Manager", "KillUserProcesses", bus_property_append_bool, "b", &m->kill_user_processes },
+ { "org.freedesktop.login1.Manager", "ControlGroupHierarchy", bus_property_append_string, "s", m->cgroup_path },
+ { "org.freedesktop.login1.Manager", "Controllers", bus_property_append_strv, "as", m->controllers },
+ { "org.freedesktop.login1.Manager", "ResetControllers", bus_property_append_strv, "as", m->reset_controllers },
+ { "org.freedesktop.login1.Manager", "NAutoVTs", bus_property_append_unsigned, "u", &m->n_autovts },
+ { "org.freedesktop.login1.Manager", "KillOnlyUsers", bus_property_append_strv, "as", m->kill_only_users },
+ { "org.freedesktop.login1.Manager", "KillExcludeUsers", bus_property_append_strv, "as", m->kill_exclude_users },
+ { "org.freedesktop.login1.Manager", "KillUserProcesses", bus_property_append_bool, "b", &m->kill_user_processes },
+ { "org.freedesktop.login1.Manager", "IdleHint", bus_manager_append_idle_hint, "b", m },
+ { "org.freedesktop.login1.Manager", "IdleSinceHint", bus_manager_append_idle_hint_since, "t", m },
+ { "org.freedesktop.login1.Manager", "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", m },
{ NULL, NULL, NULL, NULL, NULL }
};
diff --git a/src/logind-seat-dbus.c b/src/logind-seat-dbus.c
index 4937d65..32171ce 100644
--- a/src/logind-seat-dbus.c
+++ b/src/logind-seat-dbus.c
@@ -20,6 +20,7 @@
***/
#include <errno.h>
+#include <string.h>
#include "logind.h"
#include "logind-seat.h"
@@ -36,6 +37,9 @@
" <property name=\"ActiveSession\" type=\"so\" access=\"read\"/>\n" \
" <property name=\"CanActivateSessions\" type=\"b\" access=\"read\"/>\n" \
" <property name=\"Sessions\" type=\"a(so)\" access=\"read\"/>\n" \
+ " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
+ " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
" </interface>\n" \
#define INTROSPECTION \
@@ -129,7 +133,6 @@ static int bus_seat_append_sessions(DBusMessageIter *i, const char *property, vo
return 0;
}
-
static int bus_seat_append_can_activate(DBusMessageIter *i, const char *property, void *data) {
Seat *s = data;
dbus_bool_t b;
@@ -138,7 +141,7 @@ static int bus_seat_append_can_activate(DBusMessageIter *i, const char *property
assert(property);
assert(s);
- b = s->manager->vtconsole == s;
+ b = seat_is_vtconsole(s);
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
return -ENOMEM;
@@ -146,6 +149,39 @@ static int bus_seat_append_can_activate(DBusMessageIter *i, const char *property
return 0;
}
+static int bus_seat_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
+ Seat *s = data;
+ bool b;
+
+ assert(i);
+ assert(property);
+ assert(s);
+
+ b = seat_get_idle_hint(s, NULL);
+ if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int bus_seat_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
+ Seat *s = data;
+ dual_timestamp t;
+ uint64_t k;
+
+ assert(i);
+ assert(property);
+ assert(s);
+
+ seat_get_idle_hint(s, &t);
+ k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
+
+ if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &k))
+ return -ENOMEM;
+
+ return 0;
+}
+
static int get_seat_for_path(Manager *m, const char *path, Seat **_s) {
Seat *s;
char *id;
@@ -181,14 +217,73 @@ static DBusHandlerResult seat_message_dispatch(
{ "org.freedesktop.login1.Seat", "ActiveSession", bus_seat_append_active, "(so)", s },
{ "org.freedesktop.login1.Seat", "CanActivateSessions", bus_seat_append_can_activate, "b", s },
{ "org.freedesktop.login1.Seat", "Sessions", bus_seat_append_sessions, "a(so)", s },
+ { "org.freedesktop.login1.Seat", "IdleHint", bus_seat_append_idle_hint, "b", s },
+ { "org.freedesktop.login1.Seat", "IdleSinceHint", bus_seat_append_idle_hint_since, "t", s },
+ { "org.freedesktop.login1.Seat", "IdleSinceHintMonotonic", bus_seat_append_idle_hint_since, "t", s },
{ NULL, NULL, NULL, NULL, NULL }
};
+ DBusError error;
+ DBusMessage *reply = NULL;
+ int r;
+
assert(s);
assert(connection);
assert(message);
- return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+ dbus_error_init(&error);
+
+ if (dbus_message_is_method_call(message, "org.freedesktop.login1.Seat", "Terminate")) {
+
+ r = seat_stop_sessions(s);
+ if (r < 0)
+ return bus_send_error_reply(connection, message, NULL, r);
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ goto oom;
+
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Seat", "ActivateSession")) {
+ const char *name;
+ Session *session;
+
+ if (!dbus_message_get_args(
+ message,
+ &error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+ return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+ session = hashmap_get(s->manager->sessions, name);
+ if (!session || session->seat != s)
+ return bus_send_error_reply(connection, message, &error, -ENOENT);
+
+ r = session_activate(session);
+ if (r < 0)
+ return bus_send_error_reply(connection, message, NULL, r);
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ goto oom;
+ } else
+ return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+
+ if (reply) {
+ if (!dbus_connection_send(connection, reply, NULL))
+ goto oom;
+
+ dbus_message_unref(reply);
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+
+oom:
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
static DBusHandlerResult seat_message_handler(
diff --git a/src/logind-seat.c b/src/logind-seat.c
index 2ba3060..751f59a 100644
--- a/src/logind-seat.c
+++ b/src/logind-seat.c
@@ -99,7 +99,7 @@ int seat_save(Seat *s) {
fprintf(f,
"# This is private data. Do not parse.\n"
"IS_VTCONSOLE=%i\n",
- s->manager->vtconsole == s);
+ seat_is_vtconsole(s));
if (s->active) {
assert(s->active->user);
@@ -158,6 +158,8 @@ finish:
int seat_load(Seat *s) {
assert(s);
+ /* There isn't actually anything to read here ... */
+
return 0;
}
@@ -191,7 +193,7 @@ static int seat_preallocate_vts(Seat *s) {
if (s->manager->n_autovts <= 0)
return 0;
- if (s->manager->vtconsole != s)
+ if (!seat_is_vtconsole(s))
return 0;
for (i = 1; i < s->manager->n_autovts; i++) {
@@ -230,7 +232,7 @@ int seat_active_vt_changed(Seat *s, int vtnr) {
assert(s);
assert(vtnr >= 1);
- if (s->manager->vtconsole != s)
+ if (!seat_is_vtconsole(s))
return -EINVAL;
log_debug("VT changed to %i", vtnr);
@@ -260,7 +262,7 @@ int seat_read_active_vt(Seat *s) {
assert(s);
- if (s->manager->vtconsole != s)
+ if (!seat_is_vtconsole(s))
return 0;
lseek(s->manager->console_active_fd, SEEK_SET, 0);
@@ -316,8 +318,7 @@ int seat_start(Seat *s) {
}
int seat_stop(Seat *s) {
- Session *session;
- int r = 0, k;
+ int r = 0;
assert(s);
@@ -326,24 +327,96 @@ int seat_stop(Seat *s) {
log_info("Removed seat %s.", s->id);
+ seat_stop_sessions(s);
+
+ unlink(s->state_file);
+ seat_add_to_gc_queue(s);
+
+ s->started = false;
+
+ return r;
+}
+
+int seat_stop_sessions(Seat *s) {
+ Session *session;
+ int r = 0, k;
+
+ assert(s);
+
LIST_FOREACH(sessions_by_seat, session, s->sessions) {
k = session_stop(session);
if (k < 0)
r = k;
}
- unlink(s->state_file);
- seat_add_to_gc_queue(s);
+ return r;
+}
- s->started = false;
+int seat_attach_session(Seat *s, Session *session) {
+ assert(s);
+ assert(session);
+ assert(!session->seat);
- return r;
+ if (!seat_is_vtconsole(s)) {
+ if (s->sessions)
+ return -EEXIST;
+
+ assert(!s->active);
+ s->active = session;
+ }
+
+ session->seat = s;
+ LIST_PREPEND(Session, sessions_by_seat, s->sessions, session);
+
+ return 0;
+}
+
+bool seat_is_vtconsole(Seat *s) {
+ assert(s);
+
+ return s->manager->vtconsole == s;
+}
+
+int seat_get_idle_hint(Seat *s, dual_timestamp *t) {
+ Session *session;
+ bool idle_hint = true;
+ dual_timestamp ts = { 0, 0 };
+
+ assert(s);
+
+ LIST_FOREACH(sessions_by_seat, session, s->sessions) {
+ dual_timestamp k;
+ int ih;
+
+ ih = session_get_idle_hint(session, &k);
+ if (ih < 0)
+ return ih;
+
+ if (!ih) {
+ if (!idle_hint) {
+ if (k.monotonic < ts.monotonic)
+ ts = k;
+ } else {
+ idle_hint = false;
+ ts = k;
+ }
+ } else if (idle_hint) {
+
+ if (k.monotonic > ts.monotonic)
+ ts = k;
+ }
+ }
+
+ if (t)
+ *t = ts;
+
+ return idle_hint;
}
int seat_check_gc(Seat *s) {
assert(s);
- if (s->manager->vtconsole == s)
+ if (seat_is_vtconsole(s))
return 1;
return !!s->devices;
diff --git a/src/logind-seat.h b/src/logind-seat.h
index b045bde..dfbb2a2 100644
--- a/src/logind-seat.h
+++ b/src/logind-seat.h
@@ -57,8 +57,14 @@ int seat_apply_acls(Seat *s, Session *old_active);
int seat_active_vt_changed(Seat *s, int vtnr);
int seat_read_active_vt(Seat *s);
+int seat_attach_session(Seat *s, Session *session);
+
+bool seat_is_vtconsole(Seat *s);
+int seat_get_idle_hint(Seat *s, dual_timestamp *t);
+
int seat_start(Seat *s);
int seat_stop(Seat *s);
+int seat_stop_sessions(Seat *s);
int seat_check_gc(Seat *s);
void seat_add_to_gc_queue(Seat *s);
diff --git a/src/logind-session-dbus.c b/src/logind-session-dbus.c
index 539384b..8b5b3ad 100644
--- a/src/logind-session-dbus.c
+++ b/src/logind-session-dbus.c
@@ -20,6 +20,7 @@
***/
#include <errno.h>
+#include <string.h>
#include "logind.h"
#include "logind-session.h"
@@ -156,6 +157,39 @@ static int bus_session_append_active(DBusMessageIter *i, const char *property, v
return 0;
}
+static int bus_session_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
+ Session *s = data;
+ bool b;
+
+ assert(i);
+ assert(property);
+ assert(s);
+
+ b = session_get_idle_hint(s, NULL);
+ if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int bus_session_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
+ Session *s = data;
+ dual_timestamp t;
+ uint64_t u;
+
+ assert(i);
+ assert(property);
+ assert(s);
+
+ session_get_idle_hint(s, &t);
+ u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
+
+ if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
+ return -ENOMEM;
+
+ return 0;
+}
+
static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_type, session_type, SessionType);
static int get_session_for_path(Manager *m, const char *path, Session **_s) {
@@ -189,24 +223,29 @@ static DBusHandlerResult session_message_dispatch(
DBusMessage *message) {
const BusProperty properties[] = {
- { "org.freedesktop.login1.Session", "Id", bus_property_append_string, "s", s->id },
- { "org.freedesktop.login1.Session", "User", bus_session_append_user, "(uo)", s },
- { "org.freedesktop.login1.Session", "Name", bus_property_append_string, "s", s->user->name },
- { "org.freedesktop.login1.Session", "ControlGroupPath", bus_property_append_string, "s", s->cgroup_path },
- { "org.freedesktop.login1.Session", "VTNr", bus_property_append_uint32, "u", &s->vtnr },
- { "org.freedesktop.login1.Session", "Seat", bus_session_append_seat, "(so)", s },
- { "org.freedesktop.login1.Session", "TTY", bus_property_append_string, "s", s->tty },
- { "org.freedesktop.login1.Session", "Display", bus_property_append_string, "s", s->display },
- { "org.freedesktop.login1.Session", "Remote", bus_property_append_bool, "b", &s->remote },
- { "org.freedesktop.login1.Session", "RemoteUser", bus_property_append_string, "s", s->remote_user },
- { "org.freedesktop.login1.Session", "RemoteHost", bus_property_append_string, "s", s->remote_host },
- { "org.freedesktop.login1.Session", "Leader", bus_property_append_pid, "u", &s->leader },
- { "org.freedesktop.login1.Session", "Audit", bus_property_append_uint32, "u", &s->audit_id },
- { "org.freedesktop.login1.Session", "Type", bus_session_append_type, "s", &s->type },
- { "org.freedesktop.login1.Session", "Active", bus_session_append_active, "b", s },
- { "org.freedesktop.login1.Session", "Controllers", bus_property_append_strv, "as", s->controllers },
- { "org.freedesktop.login1.Session", "ResetControllers", bus_property_append_strv, "as", s->reset_controllers },
- { "org.freedesktop.login1.Session", "KillProcesses", bus_property_append_bool, "b", &s->kill_processes },
+ { "org.freedesktop.login1.Session", "Id", bus_property_append_string, "s", s->id },
+ { "org.freedesktop.login1.Session", "User", bus_session_append_user, "(uo)", s },
+ { "org.freedesktop.login1.Session", "Name", bus_property_append_string, "s", s->user->name },
+ { "org.freedesktop.login1.Session", "Timestamp", bus_property_append_usec, "t", &s->timestamp.realtime },
+ { "org.freedesktop.login1.Session", "TimestampMonotonic", bus_property_append_usec, "t", &s->timestamp.monotonic },
+ { "org.freedesktop.login1.Session", "ControlGroupPath", bus_property_append_string, "s", s->cgroup_path },
+ { "org.freedesktop.login1.Session", "VTNr", bus_property_append_uint32, "u", &s->vtnr },
+ { "org.freedesktop.login1.Session", "Seat", bus_session_append_seat, "(so)", s },
+ { "org.freedesktop.login1.Session", "TTY", bus_property_append_string, "s", s->tty },
+ { "org.freedesktop.login1.Session", "Display", bus_property_append_string, "s", s->display },
+ { "org.freedesktop.login1.Session", "Remote", bus_property_append_bool, "b", &s->remote },
+ { "org.freedesktop.login1.Session", "RemoteUser", bus_property_append_string, "s", s->remote_user },
+ { "org.freedesktop.login1.Session", "RemoteHost", bus_property_append_string, "s", s->remote_host },
+ { "org.freedesktop.login1.Session", "Leader", bus_property_append_pid, "u", &s->leader },
+ { "org.freedesktop.login1.Session", "Audit", bus_property_append_uint32, "u", &s->audit_id },
+ { "org.freedesktop.login1.Session", "Type", bus_session_append_type, "s", &s->type },
+ { "org.freedesktop.login1.Session", "Active", bus_session_append_active, "b", s },
+ { "org.freedesktop.login1.Session", "Controllers", bus_property_append_strv, "as", s->controllers },
+ { "org.freedesktop.login1.Session", "ResetControllers", bus_property_append_strv, "as", s->reset_controllers },
+ { "org.freedesktop.login1.Session", "KillProcesses", bus_property_append_bool, "b", &s->kill_processes },
+ { "org.freedesktop.login1.Session", "IdleHint", bus_session_append_idle_hint, "b", s },
+ { "org.freedesktop.login1.Session", "IdleSinceHint", bus_session_append_idle_hint_since, "t", s },
+ { "org.freedesktop.login1.Session", "IdleSinceHintMonotonic", bus_session_append_idle_hint_since, "t", s },
{ NULL, NULL, NULL, NULL, NULL }
};
diff --git a/src/logind-session.c b/src/logind-session.c
index 6b3b277..89fe02c 100644
--- a/src/logind-session.c
+++ b/src/logind-session.c
@@ -28,6 +28,8 @@
#include "util.h"
#include "cgroup-util.h"
+#define IDLE_THRESHOLD_USEC (5*USEC_PER_MINUTE)
+
Session* session_new(Manager *m, User *u, const char *id) {
Session *s;
@@ -153,7 +155,7 @@ int session_save(Session *s) {
"REMOTE_USER=%s\n",
s->remote_user);
- if (s->seat && s->seat->manager->vtconsole == s->seat)
+ if (s->seat && seat_is_vtconsole(s->seat))
fprintf(f,
"VTNR=%i\n",
s->vtnr);
@@ -187,9 +189,87 @@ finish:
}
int session_load(Session *s) {
+ char *remote = NULL,
+ *kill_processes = NULL,
+ *seat = NULL,
+ *vtnr = NULL,
+ *leader = NULL,
+ *audit_id = NULL;
+
+ int k, r;
+
assert(s);
- return 0;
+ r = parse_env_file(s->state_file, NEWLINE,
+ "REMOTE", &remote,
+ "KILL_PROCESSES", &kill_processes,
+ "CGROUP", &s->cgroup_path,
+ "SEAT", &seat,
+ "TTY", &s->tty,
+ "DISPLAY", &s->display,
+ "REMOTE_HOST", &s->remote_host,
+ "REMOTE_USER", &s->remote_user,
+ "VTNR", &vtnr,
+ "LEADER", &leader,
+ "AUDIT_ID", &audit_id,
+ NULL);
+
+ if (r < 0)
+ goto finish;
+
+ if (remote) {
+ k = parse_boolean(remote);
+ if (k >= 0)
+ s->remote = k;
+ }
+
+ if (kill_processes) {
+ k = parse_boolean(kill_processes);
+ if (k >= 0)
+ s->kill_processes = k;
+ }
+
+ if (seat) {
+ Seat *o;
+
+ o = hashmap_get(s->manager->seats, seat);
+ if (o)
+ seat_attach_session(o, s);
+ }
+
+ if (vtnr && s->seat && seat_is_vtconsole(s->seat)) {
+ int v;
+
+ k = safe_atoi(vtnr, &v);
+ if (k >= 0 && v >= 1)
+ s->vtnr = v;
+ }
+
+ if (leader) {
+ pid_t pid;
+
+ k = parse_pid(leader, &pid);
+ if (k >= 0 && pid >= 1)
+ s->leader = pid;
+ }
+
+ if (audit_id) {
+ uint32_t l;
+
+ k = safe_atou32(audit_id, &l);
+ if (k >= 0 && l >= l)
+ s->audit_id = l;
+ }
+
+finish:
+ free(remote);
+ free(kill_processes);
+ free(seat);
+ free(vtnr);
+ free(leader);
+ free(audit_id);
+
+ return r;
}
int session_activate(Session *s) {
@@ -207,7 +287,7 @@ int session_activate(Session *s) {
if (s->seat->active == s)
return 0;
- assert(s->manager->vtconsole == s->seat);
+ assert(seat_is_vtconsole(s->seat));
r = chvt(s->vtnr);
if (r < 0)
@@ -462,6 +542,59 @@ bool session_is_active(Session *s) {
return s->seat->active == s;
}
+int session_get_idle_hint(Session *s, dual_timestamp *t) {
+ char *p;
+ struct stat st;
+ usec_t u, n;
+ bool b;
+ int k;
+
+ assert(s);
+
+ if (s->idle_hint) {
+ if (t)
+ *t = s->idle_hint_timestamp;
+
+ return s->idle_hint;
+ }
+
+ if (isempty(s->tty))
+ goto dont_know;
+
+ if (s->tty[0] != '/') {
+ p = strappend("/dev/", s->tty);
+ if (!p)
+ return -ENOMEM;
+ } else
+ p = NULL;
+
+ if (!startswith(p ? p : s->tty, "/dev/")) {
+ free(p);
+ goto dont_know;
+ }
+
+ k = lstat(p ? p : s->tty, &st);
+ free(p);
+
+ if (k < 0)
+ goto dont_know;
+
+ u = timespec_load(&st.st_atim);
+ n = now(CLOCK_REALTIME);
+ b = u + IDLE_THRESHOLD_USEC < n;
+
+ if (t)
+ dual_timestamp_from_realtime(t, u + b ? IDLE_THRESHOLD_USEC : 0);
+
+ return b;
+
+dont_know:
+ if (t)
+ *t = s->idle_hint_timestamp;
+
+ return 0;
+}
+
int session_check_gc(Session *s) {
int r;
diff --git a/src/logind-session.h b/src/logind-session.h
index 60ac1c5..7682393 100644
--- a/src/logind-session.h
+++ b/src/logind-session.h
@@ -67,6 +67,9 @@ struct Session {
char *cgroup_path;
char **controllers, **reset_controllers;
+ bool idle_hint;
+ dual_timestamp idle_hint_timestamp;
+
bool kill_processes;
bool in_gc_queue:1;
@@ -82,6 +85,7 @@ int session_check_gc(Session *s);
void session_add_to_gc_queue(Session *s);
int session_activate(Session *s);
bool session_is_active(Session *s);
+int session_get_idle_hint(Session *s, dual_timestamp *t);
int session_start(Session *s);
int session_stop(Session *s);
int session_save(Session *s);
diff --git a/src/logind-user-dbus.c b/src/logind-user-dbus.c
index 7c8bb27..3be2c05 100644
--- a/src/logind-user-dbus.c
+++ b/src/logind-user-dbus.c
@@ -20,6 +20,7 @@
***/
#include <errno.h>
+#include <string.h>
#include "logind.h"
#include "logind-user.h"
@@ -31,12 +32,17 @@
" <property name=\"UID\" type=\"u\" access=\"read\"/>\n" \
" <property name=\"GID\" type=\"u\" access=\"read\"/>\n" \
" <property name=\"Name\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Timestamp\" type=\"t\" access=\"read\"/>\n" \
+ " <property name=\"TimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
" <property name=\"RuntimePath\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"Service\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"ControlGroupPath\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Service\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"Display\" type=\"(so)\" access=\"read\"/>\n" \
" <property name=\"State\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"Sessions\" type=\"a(so)\" access=\"read\"/>\n" \
+ " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
+ " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
" </interface>\n" \
#define INTROSPECTION \
@@ -146,6 +152,39 @@ static int bus_user_append_sessions(DBusMessageIter *i, const char *property, vo
return 0;
}
+static int bus_user_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
+ User *u = data;
+ bool b;
+
+ assert(i);
+ assert(property);
+ assert(u);
+
+ b = user_get_idle_hint(u, NULL);
+ if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int bus_user_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
+ User *u = data;
+ dual_timestamp t;
+ uint64_t k;
+
+ assert(i);
+ assert(property);
+ assert(u);
+
+ user_get_idle_hint(u, &t);
+ k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
+
+ if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &k))
+ return -ENOMEM;
+
+ return 0;
+}
+
static int get_user_for_path(Manager *m, const char *path, User **_u) {
User *u;
unsigned long lu;
@@ -176,23 +215,59 @@ static DBusHandlerResult user_message_dispatch(
DBusMessage *message) {
const BusProperty properties[] = {
- { "org.freedesktop.login1.User", "UID", bus_property_append_uid, "u", &u->uid },
- { "org.freedesktop.login1.User", "GID", bus_property_append_gid, "u", &u->gid },
- { "org.freedesktop.login1.User", "Name", bus_property_append_string, "s", u->name },
- { "org.freedesktop.login1.User", "RuntimePath", bus_property_append_string, "s", u->runtime_path },
- { "org.freedesktop.login1.User", "ControlGroupPath", bus_property_append_string, "s", u->cgroup_path },
- { "org.freedesktop.login1.User", "Service", bus_property_append_string, "s", u->service },
- { "org.freedesktop.login1.User", "Display", bus_user_append_display, "(so)", u },
- { "org.freedesktop.login1.User", "State", bus_user_append_state, "s", u },
- { "org.freedesktop.login1.User", "Sessions", bus_user_append_sessions, "a(so)", u },
+ { "org.freedesktop.login1.User", "UID", bus_property_append_uid, "u", &u->uid },
+ { "org.freedesktop.login1.User", "GID", bus_property_append_gid, "u", &u->gid },
+ { "org.freedesktop.login1.User", "Name", bus_property_append_string, "s", u->name },
+ { "org.freedesktop.login1.User", "Timestamp", bus_property_append_usec, "t", &u->timestamp.realtime },
+ { "org.freedesktop.login1.User", "TimestampMonotonic", bus_property_append_usec, "t", &u->timestamp.monotonic },
+ { "org.freedesktop.login1.User", "RuntimePath", bus_property_append_string, "s", u->runtime_path },
+ { "org.freedesktop.login1.User", "ControlGroupPath", bus_property_append_string, "s", u->cgroup_path },
+ { "org.freedesktop.login1.User", "Service", bus_property_append_string, "s", u->service },
+ { "org.freedesktop.login1.User", "Display", bus_user_append_display, "(so)", u },
+ { "org.freedesktop.login1.User", "State", bus_user_append_state, "s", u },
+ { "org.freedesktop.login1.User", "Sessions", bus_user_append_sessions, "a(so)", u },
+ { "org.freedesktop.login1.User", "IdleHint", bus_user_append_idle_hint, "b", u },
+ { "org.freedesktop.login1.User", "IdleSinceHint", bus_user_append_idle_hint_since, "t", u },
+ { "org.freedesktop.login1.User", "IdleSinceHintMonotonic", bus_user_append_idle_hint_since, "t", u },
{ NULL, NULL, NULL, NULL, NULL }
};
+ DBusError error;
+ DBusMessage *reply = NULL;
+ int r;
+
assert(u);
assert(connection);
assert(message);
- return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+ if (dbus_message_is_method_call(message, "org.freedesktop.login1.User", "Terminate")) {
+
+ r = user_stop(u);
+ if (r < 0)
+ return bus_send_error_reply(connection, message, NULL, r);
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ goto oom;
+ } else
+ return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+
+ if (reply) {
+ if (!dbus_connection_send(connection, reply, NULL))
+ goto oom;
+
+ dbus_message_unref(reply);
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+
+oom:
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
static DBusHandlerResult user_message_handler(
diff --git a/src/logind-user.c b/src/logind-user.c
index 7d6df8d..206064f 100644
--- a/src/logind-user.c
+++ b/src/logind-user.c
@@ -156,7 +156,7 @@ int user_load(User *u) {
assert(u);
- r = parse_env_file(u->state_file, "r",
+ r = parse_env_file(u->state_file, NEWLINE,
"CGROUP", &u->cgroup_path,
"RUNTIME", &u->runtime_path,
"SERVICE", &u->service,
@@ -386,6 +386,42 @@ int user_stop(User *u) {
return r;
}
+int user_get_idle_hint(User *u, dual_timestamp *t) {
+ Session *s;
+ bool idle_hint = true;
+ dual_timestamp ts = { 0, 0 };
+
+ assert(u);
+
+ LIST_FOREACH(sessions_by_user, s, u->sessions) {
+ dual_timestamp k;
+ int ih;
+
+ ih = session_get_idle_hint(s, &k);
+ if (ih < 0)
+ return ih;
+
+ if (!ih) {
+ if (!idle_hint) {
+ if (k.monotonic < ts.monotonic)
+ ts = k;
+ } else {
+ idle_hint = false;
+ ts = k;
+ }
+ } else if (idle_hint) {
+
+ if (k.monotonic > ts.monotonic)
+ ts = k;
+ }
+ }
+
+ if (t)
+ *t = ts;
+
+ return idle_hint;
+}
+
int user_check_gc(User *u) {
int r;
char *p;
diff --git a/src/logind-user.h b/src/logind-user.h
index 7f58aa2..c891119 100644
--- a/src/logind-user.h
+++ b/src/logind-user.h
@@ -67,6 +67,7 @@ void user_add_to_gc_queue(User *u);
int user_start(User *u);
int user_stop(User *u);
UserState user_get_state(User *u);
+int user_get_idle_hint(User *u, dual_timestamp *t);
int user_save(User *u);
int user_load(User *u);
diff --git a/src/logind.c b/src/logind.c
index a628028..d72a5bf 100644
--- a/src/logind.c
+++ b/src/logind.c
@@ -853,6 +853,44 @@ void manager_gc(Manager *m) {
}
}
+int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
+ Session *s;
+ bool idle_hint = true;
+ dual_timestamp ts = { 0, 0 };
+ Iterator i;
+
+ assert(m);
+
+ HASHMAP_FOREACH(s, m->sessions, i) {
+ dual_timestamp k;
+ int ih;
+
+ ih = session_get_idle_hint(s, &k);
+ if (ih < 0)
+ return ih;
+
+ if (!ih) {
+ if (!idle_hint) {
+ if (k.monotonic < ts.monotonic)
+ ts = k;
+ } else {
+ idle_hint = false;
+ ts = k;
+ }
+ } else if (idle_hint) {
+
+ if (k.monotonic > ts.monotonic)
+ ts = k;
+ }
+ }
+
+ if (t)
+ *t = ts;
+
+ return idle_hint;
+}
+
+
int manager_startup(Manager *m) {
int r;
Seat *seat;
diff --git a/src/logind.h b/src/logind.h
index fdc780f..e18a357 100644
--- a/src/logind.h
+++ b/src/logind.h
@@ -108,6 +108,8 @@ int manager_spawn_autovt(Manager *m, int vtnr);
void manager_gc(Manager *m);
+int manager_get_idle_hint(Manager *m, dual_timestamp *t);
+
bool x11_display_is_local(const char *display);
extern const DBusObjectPathVTable bus_manager_vtable;
diff --git a/src/util.c b/src/util.c
index 2047ebd..08529cc 100644
--- a/src/util.c
+++ b/src/util.c
@@ -108,6 +108,28 @@ dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
return ts;
}
+dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
+ int64_t delta;
+ assert(ts);
+
+ ts->realtime = u;
+
+ if (u == 0)
+ ts->monotonic = 0;
+ else {
+ delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
+
+ ts->monotonic = now(CLOCK_MONOTONIC);
+
+ if ((int64_t) ts->monotonic > delta)
+ ts->monotonic -= delta;
+ else
+ ts->monotonic = 0;
+ }
+
+ return ts;
+}
+
usec_t timespec_load(const struct timespec *ts) {
assert(ts);
diff --git a/src/util.h b/src/util.h
index 3863a08..76e1d4f 100644
--- a/src/util.h
+++ b/src/util.h
@@ -75,6 +75,7 @@ typedef struct dual_timestamp {
usec_t now(clockid_t clock);
dual_timestamp* dual_timestamp_get(dual_timestamp *ts);
+dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u);
#define dual_timestamp_is_set(ts) ((ts)->realtime > 0)
commit 91f9dcaf9270fe465525638cc08bd94590273349
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Jun 17 00:15:02 2011 +0200
dbus: add dbus introspection extraction
diff --git a/Makefile.am b/Makefile.am
index 0439957..a2d7397 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -203,13 +203,15 @@ dist_dbuspolicy_DATA = \
src/org.freedesktop.systemd1.conf \
src/org.freedesktop.hostname1.conf \
src/org.freedesktop.locale1.conf \
- src/org.freedesktop.timedate1.conf
+ src/org.freedesktop.timedate1.conf \
+ src/org.freedesktop.login1.conf
dist_dbussystemservice_DATA = \
src/org.freedesktop.systemd1.service \
src/org.freedesktop.hostname1.service \
src/org.freedesktop.locale1.service \
- src/org.freedesktop.timedate1.service
+ src/org.freedesktop.timedate1.service \
+ src/org.freedesktop.login1.service
dist_udevrules_DATA = \
src/99-systemd.rules
@@ -227,7 +229,10 @@ dbusinterface_DATA = \
org.freedesktop.systemd1.Automount.xml \
org.freedesktop.systemd1.Snapshot.xml \
org.freedesktop.systemd1.Swap.xml \
- org.freedesktop.systemd1.Path.xml
+ org.freedesktop.systemd1.Path.xml \
+ org.freedesktop.hostname1.xml \
+ org.freedesktop.locale1.xml \
+ org.freedesktop.timedate1.xml
dist_bashcompletion_DATA = \
src/systemctl-bash-completion.sh
@@ -316,6 +321,7 @@ nodist_systemunit_DATA = \
units/systemd-hostnamed.service \
units/systemd-localed.service \
units/systemd-timedated.service \
+ units/systemd-logind.service \
units/systemd-kmsg-syslogd.service \
units/systemd-modules-load.service \
units/systemd-vconsole-setup.service \
@@ -365,6 +371,7 @@ EXTRA_DIST = \
units/systemd-hostnamed.service.in \
units/systemd-localed.service.in \
units/systemd-timedated.service.in \
+ units/systemd-logind.service.in \
units/systemd-kmsg-syslogd.service.in \
units/systemd-modules-load.service.in \
units/systemd-vconsole-setup.service.in \
@@ -455,7 +462,8 @@ nodist_polkitpolicy_DATA = \
dist_polkitpolicy_DATA = \
src/org.freedesktop.hostname1.policy \
src/org.freedesktop.locale1.policy \
- src/org.freedesktop.timedate1.policy
+ src/org.freedesktop.timedate1.policy \
+ src/org.freedesktop.login1.policy
noinst_LTLIBRARIES = \
libsystemd-basic.la \
@@ -1388,6 +1396,21 @@ org.freedesktop.systemd1.%.xml: systemd
$(STRINGS) $@.tmp | $(AWK) -f $(srcdir)/introspect.awk | \
$(DBUS_PREPROCESS) -o $@ - && rm $@.tmp
+org.freedesktop.hostname1.xml: systemd-hostnamed
+ $(AM_V_GEN)$(OBJCOPY) -O binary -j introspect.hostname1 $< $@.tmp && \
+ $(STRINGS) $@.tmp | $(AWK) -f $(srcdir)/introspect.awk | \
+ $(DBUS_PREPROCESS) -o $@ - && rm $@.tmp
+
+org.freedesktop.locale1.xml: systemd-localed
+ $(AM_V_GEN)$(OBJCOPY) -O binary -j introspect.locale1 $< $@.tmp && \
+ $(STRINGS) $@.tmp | $(AWK) -f $(srcdir)/introspect.awk | \
+ $(DBUS_PREPROCESS) -o $@ - && rm $@.tmp
+
+org.freedesktop.timedate1.xml: systemd-timedated
+ $(AM_V_GEN)$(OBJCOPY) -O binary -j introspect.timedate1 $< $@.tmp && \
+ $(STRINGS) $@.tmp | $(AWK) -f $(srcdir)/introspect.awk | \
+ $(DBUS_PREPROCESS) -o $@ - && rm $@.tmp
+
CLEANFILES += \
$(dbusinterface_DATA)
@@ -1492,7 +1515,8 @@ endif
$(LN_S) reboot.target ctrl-alt-del.target && \
$(LN_S) systemd-hostnamed.service dbus-org.freedesktop.hostname1.service && \
$(LN_S) systemd-localed.service dbus-org.freedesktop.locale1.service && \
- $(LN_S) systemd-timedate.service dbus-org.freedesktop.timedate1.service )
+ $(LN_S) systemd-timedated.service dbus-org.freedesktop.timedate1.service && \
+ $(LN_S) systemd-logind.service dbus-org.freedesktop.login1.service )
( cd $(DESTDIR)$(systemunitdir)/multi-user.target.wants && \
rm -f getty.target systemd-user-sessions.service systemd-ask-password-wall.path && \
$(LN_S) ../getty.target getty.target && \
diff --git a/org.freedesktop.hostname1.xml b/org.freedesktop.hostname1.xml
new file mode 100644
index 0000000..e2d81a3
--- /dev/null
+++ b/org.freedesktop.hostname1.xml
@@ -0,0 +1,26 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.freedesktop.hostname1">
+ <property name="Hostname" type="s" access="read"/>
+ <property name="StaticHostname" type="s" access="read"/>
+ <property name="PrettyHostname" type="s" access="read"/>
+ <property name="IconName" type="s" access="read"/>
+ <method name="SetHostname">
+ <arg name="name" type="s" direction="in"/>
+ <arg name="user_interaction" type="b" direction="in"/>
+ </method>
+ <method name="SetStaticHostname">
+ <arg name="name" type="s" direction="in"/>
+ <arg name="user_interaction" type="b" direction="in"/>
+ </method>
+ <method name="SetPrettyHostname">
+ <arg name="name" type="s" direction="in"/>
+ <arg name="user_interaction" type="b" direction="in"/>
+ </method>
+ <method name="SetIconName">
+ <arg name="name" type="s" direction="in"/>
+ <arg name="user_interaction" type="b" direction="in"/>
+ </method>
+ </interface>
+</node>
diff --git a/org.freedesktop.locale1.xml b/org.freedesktop.locale1.xml
new file mode 100644
index 0000000..ca24e84
--- /dev/null
+++ b/org.freedesktop.locale1.xml
@@ -0,0 +1,11 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.freedesktop.locale1">
+ <property name="Locale" type="as" access="read"/>
+ <method name="SetLocale">
+ <arg name="locale" type="as" direction="in"/>
+ <arg name="user_interaction" type="b" direction="in"/>
+ </method>
+ </interface>
+</node>
diff --git a/org.freedesktop.timedate1.xml b/org.freedesktop.timedate1.xml
new file mode 100644
index 0000000..3799a65
--- /dev/null
+++ b/org.freedesktop.timedate1.xml
@@ -0,0 +1,22 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.freedesktop.timedate1">
+ <property name="Timezone" type="s" access="read"/>
+ <property name="LocalRTC" type="b" access="read"/>
+ <method name="SetTime">
+ <arg name="usec_utc" type="x" direction="in"/>
+ <arg name="relative" type="b" direction="in"/>
+ <arg name="user_interaction" type="b" direction="in"/>
+ </method>
+ <method name="SetTimezone">
+ <arg name="timezone" type="s" direction="in"/>
+ <arg name="user_interaction" type="b" direction="in"/>
+ </method>
+ <method name="SetLocalRTC">
+ <arg name="local_rtc" type="b" direction="in"/>
+ <arg name="fix_system" type="b" direction="in"/>
+ <arg name="user_interaction" type="b" direction="in"/>
+ </method>
+ </interface>
+</node>
diff --git a/src/hostnamed.c b/src/hostnamed.c
index f579e11..d05c902 100644
--- a/src/hostnamed.c
+++ b/src/hostnamed.c
@@ -31,9 +31,7 @@
#include "dbus-common.h"
#include "polkit.h"
-#define INTROSPECTION \
- DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
- "<node>\n" \
+#define INTERFACE \
" <interface name=\"org.freedesktop.hostname1\">\n" \
" <property name=\"Hostname\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"StaticHostname\" type=\"s\" access=\"read\"/>\n" \
@@ -55,7 +53,12 @@
" <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
" <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
" </method>\n" \
- " </interface>\n" \
+ " </interface>\n"
+
+#define INTROSPECTION \
+ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
+ "<node>\n" \
+ INTERFACE \
BUS_PROPERTIES_INTERFACE \
BUS_INTROSPECTABLE_INTERFACE \
BUS_PEER_INTERFACE \
@@ -65,6 +68,8 @@
BUS_GENERIC_INTERFACES_LIST \
"org.freedesktop.hostname1\0"
+const char hostname_interface[] _introspect_("hostname1") = INTERFACE;
+
enum {
PROP_HOSTNAME,
PROP_STATIC_HOSTNAME,
@@ -547,6 +552,14 @@ int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
+ if (argc == 2 && streq(argv[1], "--introspect")) {
+ fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+ "<node>\n", stdout);
+ fputs(hostname_interface, stdout);
+ fputs("</node>\n", stdout);
+ return 0;
+ }
+
if (argc != 1) {
log_error("This program takes no arguments.");
r = -EINVAL;
diff --git a/src/localed.c b/src/localed.c
index 0fbe747..353e88e 100644
--- a/src/localed.c
+++ b/src/localed.c
@@ -30,16 +30,19 @@
#include "dbus-common.h"
#include "polkit.h"
-#define INTROSPECTION \
- DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
- "<node>\n" \
+#define INTERFACE \
" <interface name=\"org.freedesktop.locale1\">\n" \
" <property name=\"Locale\" type=\"as\" access=\"read\"/>\n" \
" <method name=\"SetLocale\">\n" \
" <arg name=\"locale\" type=\"as\" direction=\"in\"/>\n" \
" <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
" </method>\n" \
- " </interface>\n" \
+ " </interface>\n"
+
+#define INTROSPECTION \
+ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
+ "<node>\n" \
+ INTERFACE \
BUS_PROPERTIES_INTERFACE \
BUS_INTROSPECTABLE_INTERFACE \
BUS_PEER_INTERFACE \
@@ -49,6 +52,8 @@
BUS_GENERIC_INTERFACES_LIST \
"org.freedesktop.locale1\0"
+const char locale_interface[] _introspect_("locale1") = INTERFACE;
+
enum {
/* We don't list LC_ALL here on purpose. People should be
* using LANG instead. */
@@ -563,6 +568,14 @@ int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
+ if (argc == 2 && streq(argv[1], "--introspect")) {
+ fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+ "<node>\n", stdout);
+ fputs(locale_interface, stdout);
+ fputs("</node>\n", stdout);
+ return 0;
+ }
+
if (argc != 1) {
log_error("This program takes no arguments.");
r = -EINVAL;
diff --git a/src/logind.h b/src/logind.h
index 95db35d..fdc780f 100644
--- a/src/logind.h
+++ b/src/logind.h
@@ -38,6 +38,7 @@
* PAM rewrite
* spawn user systemd
* dbus API
+ * direct client API
*
* non-local X11 server
* reboot/shutdown halt management
diff --git a/src/org.freedesktop.login1.policy b/src/org.freedesktop.login1.policy
new file mode 100644
index 0000000..b81e488
--- /dev/null
+++ b/src/org.freedesktop.login1.policy
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?> <!--*-nxml-*-->
+<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
+
+<!--
+ This file is part of systemd.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+-->
+
+<policyconfig>
+
+ <vendor>The systemd Project</vendor>
+ <vendor_url>http://www.freedesktop.org/wiki/Software/systemd</vendor_url>
+
+ <action id="org.freedesktop.login1.enable-user-linger">
+ <description>Allow non-logged-in users to run programs</description>
+ <message>Authentication is required to allow a non-logged-in user to run programs</message>
+ <defaults>
+ <allow_any>auth_admin_keep</allow_any>
+ <allow_inactive>auth_admin_keep</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ </action>
+
+</policyconfig>
diff --git a/src/org.freedesktop.login1.service b/src/org.freedesktop.login1.service
new file mode 100644
index 0000000..4a64177
--- /dev/null
+++ b/src/org.freedesktop.login1.service
@@ -0,0 +1,12 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+[D-BUS Service]
+Name=org.freedesktop.login1
+Exec=/bin/false
+User=root
+SystemdService=dbus-org.freedesktop.login1.service
diff --git a/src/timedated.c b/src/timedated.c
index daa3d9c..a6ec262 100644
--- a/src/timedated.c
+++ b/src/timedated.c
@@ -33,9 +33,7 @@
#define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n"
#define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n"
-#define INTROSPECTION \
- DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
- "<node>\n" \
+#define INTERFACE \
" <interface name=\"org.freedesktop.timedate1\">\n" \
" <property name=\"Timezone\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"LocalRTC\" type=\"b\" access=\"read\"/>\n" \
@@ -50,10 +48,15 @@
" </method>\n" \
" <method name=\"SetLocalRTC\">\n" \
" <arg name=\"local_rtc\" type=\"b\" direction=\"in\"/>\n" \
- " <arg name=\"fix_system\" type=\"b\" direction=\"in\"/>\n" \
+ " <arg name=\"fix_system\" type=\"b\" direction=\"in\"/>\n" \
" <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
" </method>\n" \
- " </interface>\n" \
+ " </interface>\n"
+
+#define INTROSPECTION \
+ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
+ "<node>\n" \
+ INTERFACE \
BUS_PROPERTIES_INTERFACE \
BUS_INTROSPECTABLE_INTERFACE \
BUS_PEER_INTERFACE \
@@ -63,6 +66,8 @@
BUS_GENERIC_INTERFACES_LIST \
"org.freedesktop.locale1\0"
+const char timedate_interface[] _introspect_("timedate1") = INTERFACE;
+
static char *zone = NULL;
static bool local_rtc = false;
@@ -566,6 +571,14 @@ int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
+ if (argc == 2 && streq(argv[1], "--introspect")) {
+ fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+ "<node>\n", stdout);
+ fputs(timedate_interface, stdout);
+ fputs("</node>\n", stdout);
+ return 0;
+ }
+
if (argc != 1) {
log_error("This program takes no arguments.");
r = -EINVAL;
diff --git a/units/.gitignore b/units/.gitignore
index 9634440..8da3804 100644
--- a/units/.gitignore
+++ b/units/.gitignore
@@ -1,3 +1,4 @@
+systemd-logind.service
systemd-localed.service
systemd-timedated.service
systemd-hostnamed.service
diff --git a/units/systemd-logind.service.in b/units/systemd-logind.service.in
new file mode 100644
index 0000000..52c4acf
--- /dev/null
+++ b/units/systemd-logind.service.in
@@ -0,0 +1,17 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+# See systemd.special(7) for details
+
+[Unit]
+Description=Login Service
+
+[Service]
+ExecStart=@rootlibexecdir@/systemd-logind
+Type=dbus
+BusName=org.freedesktop.login1
+CapabilityBoundingSet=
commit 05a4abb9146eebd75f5d9b9cac38f183818a9f6d
Author: Lennart Poettering <lennart at poettering.net>
Date: Thu Jun 16 22:15:43 2011 +0200
timedated: rename a few things for clarification
diff --git a/src/timedated.c b/src/timedated.c
index ad7b881..daa3d9c 100644
--- a/src/timedated.c
+++ b/src/timedated.c
@@ -50,7 +50,7 @@
" </method>\n" \
" <method name=\"SetLocalRTC\">\n" \
" <arg name=\"local_rtc\" type=\"b\" direction=\"in\"/>\n" \
- " <arg name=\"correct_system\" type=\"b\" direction=\"in\"/>\n" \
+ " <arg name=\"fix_system\" type=\"b\" direction=\"in\"/>\n" \
" <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
" </method>\n" \
" </interface>\n" \
@@ -347,14 +347,14 @@ static DBusHandlerResult timedate_message_handler(
} else if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetLocalRTC")) {
dbus_bool_t lrtc;
- dbus_bool_t correct_system;
+ dbus_bool_t fix_system;
dbus_bool_t interactive;
if (!dbus_message_get_args(
message,
&error,
DBUS_TYPE_BOOLEAN, &lrtc,
- DBUS_TYPE_BOOLEAN, &correct_system,
+ DBUS_TYPE_BOOLEAN, &fix_system,
DBUS_TYPE_BOOLEAN, &interactive,
DBUS_TYPE_INVALID))
return bus_send_error_reply(connection, message, &error, -EINVAL);
@@ -384,7 +384,7 @@ static DBusHandlerResult timedate_message_handler(
/* 3. Synchronize clocks */
assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
- if (correct_system) {
+ if (fix_system) {
struct tm tm;
/* Sync system clock from RTC; first,
@@ -422,7 +422,7 @@ static DBusHandlerResult timedate_message_handler(
hwclock_set_time(tm);
}
- log_info("Changed local RTC setting to '%s'.", yes_no(local_rtc));
+ log_error("RTC configured to %s time.", local_rtc ? "local" : "UTC");
changed = bus_properties_changed_new(
"/org/freedesktop/timedate1",
commit 2076cf883110bd6fc0f87b619005baf2117d6b95
Author: Lennart Poettering <lennart at poettering.net>
Date: Thu Jun 16 21:52:11 2011 +0200
timedated: sync clock down to RTC where necessary
diff --git a/TODO b/TODO
index 99b7707..aab4431 100644
--- a/TODO
+++ b/TODO
@@ -74,6 +74,10 @@ Features:
* support wildcard expansion in EnvironmentFile= and friends
+* add JoinControllers= to system.conf to mount certain cgroup
+ controllers together in order to guarantee atomic creation/addition
+ of cgroups
+
* avoid DefaultStandardOutput=syslog to have any effect on StandardInput=socket services
* fix alsa mixer restore to not print error when no config is stored
diff --git a/src/main.c b/src/main.c
index 11379f6..0452033 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1050,11 +1050,14 @@ int main(int argc, char *argv[]) {
if (label_init() < 0)
goto finish;
- if (hwclock_is_localtime()) {
+ if (hwclock_is_localtime() > 0) {
int min;
min = hwclock_apply_localtime_delta();
- log_info("Hwclock configured in localtime, applying delta of %i minutes to system time", min);
+ if (min < 0)
+ log_error("Failed to apply local time delta: %s", strerror(-min));
+ else
+ log_info("RTC configured in localtime, applying delta of %i minutes to system time.", min);
}
} else {
arg_running_as = MANAGER_USER;
diff --git a/src/timedated.c b/src/timedated.c
index 4749648..ad7b881 100644
--- a/src/timedated.c
+++ b/src/timedated.c
@@ -50,6 +50,7 @@
" </method>\n" \
" <method name=\"SetLocalRTC\">\n" \
" <arg name=\"local_rtc\" type=\"b\" direction=\"in\"/>\n" \
+ " <arg name=\"correct_system\" type=\"b\" direction=\"in\"/>\n" \
" <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
" </method>\n" \
" </interface>\n" \
@@ -151,7 +152,6 @@ static void verify_timezone(void) {
static int read_data(void) {
int r;
- FILE *f;
free_data();
@@ -161,25 +161,7 @@ static int read_data(void) {
verify_timezone();
- f = fopen("/etc/adjtime", "r");
- if (f) {
- char line[LINE_MAX];
- bool b;
-
- b = fgets(line, sizeof(line), f) &&
- fgets(line, sizeof(line), f) &&
- fgets(line, sizeof(line), f);
-
- fclose(f);
-
- if (!b)
- return -EIO;
-
- truncate_nl(line);
- local_rtc = streq(line, "LOCAL");
-
- } else if (errno != ENOENT)
- return -errno;
+ local_rtc = hwclock_is_localtime() > 0;
return 0;
}
@@ -333,12 +315,26 @@ static DBusHandlerResult timedate_message_handler(
free(zone);
zone = t;
+ /* 1. Write new configuration file */
r = write_data_timezone();
if (r < 0) {
log_error("Failed to set timezone: %s", strerror(-r));
return bus_send_error_reply(connection, message, NULL, r);
}
+ if (local_rtc) {
+ struct timespec ts;
+ struct tm *tm;
+
+ /* 2. Teach kernel new timezone */
+ hwclock_apply_localtime_delta();
+
+ /* 3. Sync RTC from system clock, with the new delta */
+ assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
+ assert_se(tm = localtime(&ts.tv_sec));
+ hwclock_set_time(tm);
+ }
+
log_info("Changed timezone to '%s'.", zone);
changed = bus_properties_changed_new(
@@ -351,29 +347,81 @@ static DBusHandlerResult timedate_message_handler(
} else if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetLocalRTC")) {
dbus_bool_t lrtc;
+ dbus_bool_t correct_system;
dbus_bool_t interactive;
if (!dbus_message_get_args(
message,
&error,
DBUS_TYPE_BOOLEAN, &lrtc,
+ DBUS_TYPE_BOOLEAN, &correct_system,
DBUS_TYPE_BOOLEAN, &interactive,
DBUS_TYPE_INVALID))
return bus_send_error_reply(connection, message, &error, -EINVAL);
if (lrtc != local_rtc) {
+ struct timespec ts;
+
r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-local-rtc", interactive, &error);
if (r < 0)
return bus_send_error_reply(connection, message, &error, r);
local_rtc = lrtc;
+ /* 1. Write new configuration file */
r = write_data_local_rtc();
if (r < 0) {
log_error("Failed to set RTC to local/UTC: %s", strerror(-r));
return bus_send_error_reply(connection, message, NULL, r);
}
+ /* 2. Teach kernel new timezone */
+ if (local_rtc)
+ hwclock_apply_localtime_delta();
+ else
+ hwclock_reset_localtime_delta();
+
+ /* 3. Synchronize clocks */
+ assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
+
+ if (correct_system) {
+ struct tm tm;
+
+ /* Sync system clock from RTC; first,
+ * initialize the timezone fields of
+ * struct tm. */
+ if (local_rtc)
+ tm = *localtime(&ts.tv_sec);
+ else
+ tm = *gmtime(&ts.tv_sec);
+
+ /* Override the main fields of
+ * struct tm, but not the timezone
+ * fields */
+ if (hwclock_get_time(&tm) >= 0) {
+
+ /* And set the system clock
+ * with this */
+ if (local_rtc)
+ ts.tv_sec = mktime(&tm);
+ else
+ ts.tv_sec = timegm(&tm);
+
+ clock_settime(CLOCK_REALTIME, &ts);
+ }
+
+ } else {
+ struct tm *tm;
+
+ /* Sync RTC from system clock */
+ if (local_rtc)
+ tm = localtime(&ts.tv_sec);
+ else
+ tm = gmtime(&ts.tv_sec);
+
+ hwclock_set_time(tm);
+ }
+
log_info("Changed local RTC setting to '%s'.", yes_no(local_rtc));
changed = bus_properties_changed_new(
@@ -403,6 +451,7 @@ static DBusHandlerResult timedate_message_handler(
if (!relative || utc != 0) {
struct timespec ts;
+ struct tm* tm;
r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-time", interactive, &error);
if (r < 0)
@@ -413,11 +462,20 @@ static DBusHandlerResult timedate_message_handler(
else
timespec_store(&ts, utc);
+ /* Set system clock */
if (clock_settime(CLOCK_REALTIME, &ts) < 0) {
log_error("Failed to set local time: %m");
return bus_send_error_reply(connection, message, NULL, -errno);
}
+ /* Sync down to RTC */
+ if (local_rtc)
+ tm = localtime(&ts.tv_sec);
+ else
+ tm = gmtime(&ts.tv_sec);
+
+ hwclock_set_time(tm);
+
log_info("Changed local time to %s", ctime(&ts.tv_sec));
}
diff --git a/src/util.c b/src/util.c
index dfb153b..2047ebd 100644
--- a/src/util.c
+++ b/src/util.c
@@ -4785,40 +4785,50 @@ finish:
return r;
}
-bool hwclock_is_localtime(void) {
+int hwclock_is_localtime(void) {
FILE *f;
- char line[LINE_MAX];
bool local = false;
/*
* The third line of adjtime is "UTC" or "LOCAL" or nothing.
* # /etc/adjtime
- * 0.0 0 0.0
+ * 0.0 0 0
* 0
* UTC
*/
f = fopen("/etc/adjtime", "re");
if (f) {
- if (fgets(line, sizeof(line), f) &&
- fgets(line, sizeof(line), f) &&
- fgets(line, sizeof(line), f) ) {
- if (!strcmp(line, "LOCAL\n"))
- local = true;
- }
+ char line[LINE_MAX];
+ bool b;
+
+ b = fgets(line, sizeof(line), f) &&
+ fgets(line, sizeof(line), f) &&
+ fgets(line, sizeof(line), f);
+
fclose(f);
- }
+
+ if (!b)
+ return -EIO;
+
+
+ truncate_nl(line);
+ local = streq(line, "LOCAL");
+
+ } else if (errno != -ENOENT)
+ return -errno;
+
return local;
}
int hwclock_apply_localtime_delta(void) {
const struct timeval *tv_null = NULL;
- struct timeval tv;
+ struct timespec ts;
struct tm *tm;
int minuteswest;
struct timezone tz;
- gettimeofday(&tv, NULL);
- tm = localtime(&tv.tv_sec);
+ assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
+ assert_se(tm = localtime(&ts.tv_sec));
minuteswest = tm->tm_gmtoff / 60;
tz.tz_minuteswest = -minuteswest;
@@ -4831,20 +4841,43 @@ int hwclock_apply_localtime_delta(void) {
*/
if (settimeofday(tv_null, &tz) < 0)
return -errno;
- else
- return minuteswest;
+
+ return minuteswest;
+}
+
+int hwclock_reset_localtime_delta(void) {
+ const struct timeval *tv_null = NULL;
+ struct timezone tz;
+
+ tz.tz_minuteswest = 0;
+ tz.tz_dsttime = 0; /* DST_NONE*/
+
+ if (settimeofday(tv_null, &tz) < 0)
+ return -errno;
+
+ return 0;
}
int hwclock_get_time(struct tm *tm) {
int fd;
int err = 0;
+ assert(tm);
+
fd = open("/dev/rtc0", O_RDONLY|O_CLOEXEC);
if (fd < 0)
return -errno;
+
+ /* This leaves the timezone fields of struct tm
+ * uninitialized! */
if (ioctl(fd, RTC_RD_TIME, tm) < 0)
err = -errno;
- close(fd);
+
+ /* We don't now daylight saving, so we reset this in order not
+ * to confused mktime(). */
+ tm->tm_isdst = -1;
+
+ close_nointr_nofail(fd);
return err;
}
@@ -4853,12 +4886,16 @@ int hwclock_set_time(const struct tm *tm) {
int fd;
int err = 0;
+ assert(tm);
+
fd = open("/dev/rtc0", O_RDONLY|O_CLOEXEC);
if (fd < 0)
return -errno;
+
if (ioctl(fd, RTC_SET_TIME, tm) < 0)
err = -errno;
- close(fd);
+
+ close_nointr_nofail(fd);
return err;
}
diff --git a/src/util.h b/src/util.h
index bd98b65..3863a08 100644
--- a/src/util.h
+++ b/src/util.h
@@ -431,12 +431,11 @@ int fchmod_umask(int fd, mode_t mode);
int conf_files_list(char ***strv, const char *suffix, const char *dir, ...);
-bool hwclock_is_localtime(void);
+int hwclock_is_localtime(void);
int hwclock_apply_localtime_delta(void);
-
+int hwclock_reset_localtime_delta(void);
int hwclock_get_time(struct tm *tm);
-
int hwclock_set_time(const struct tm *tm);
#define NULSTR_FOREACH(i, l) \
commit d3fc81bd6a5a046b22600ac1204df220c93d2c15
Author: Lennart Poettering <lennart at poettering.net>
Date: Wed Jun 15 15:39:10 2011 +0200
update TODO
diff --git a/TODO b/TODO
index 71ad077..99b7707 100644
--- a/TODO
+++ b/TODO
@@ -27,6 +27,10 @@ Features:
* kernel: add device_type = "fb", "fbcon" to class "graphics"
+* readahead: use BTRFS_IOC_DEFRAG_RANGE instead of BTRFS_IOC_DEFRAG ioctl, with START_IO
+
+* readahead: check whether a btrfs volume includes ssd by checking mount flag "ssd"
+
* hostnamed: make file updates atomic
* support sd_notify() style notificatio when reload is finished (RELOADED=1)
commit f401e48c2db22ff9d1a05885b5599bebf19c2707
Author: Lennart Poettering <lennart at poettering.net>
Date: Wed Jun 15 15:37:39 2011 +0200
mechanisms: add mechanisms to change system locale and clock
diff --git a/.gitignore b/.gitignore
index 7bd22c5..92b8f73 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
+systemd-localed
+systemd-timedated
systemd-uaccess
systemd-logind
systemd-hostnamed
diff --git a/Makefile.am b/Makefile.am
index 0bc5169..0439957 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -159,6 +159,8 @@ rootlibexec_PROGRAMS = \
systemd-detect-virt \
systemd-sysctl \
systemd-hostnamed \
+ systemd-localed \
+ systemd-timedated \
systemd-logind \
systemd-uaccess
@@ -199,11 +201,15 @@ dist_pkgsysconf_DATA = \
dist_dbuspolicy_DATA = \
src/org.freedesktop.systemd1.conf \
- src/org.freedesktop.hostname1.conf
+ src/org.freedesktop.hostname1.conf \
+ src/org.freedesktop.locale1.conf \
+ src/org.freedesktop.timedate1.conf
dist_dbussystemservice_DATA = \
src/org.freedesktop.systemd1.service \
- src/org.freedesktop.hostname1.service
+ src/org.freedesktop.hostname1.service \
+ src/org.freedesktop.locale1.service \
+ src/org.freedesktop.timedate1.service
dist_udevrules_DATA = \
src/99-systemd.rules
@@ -308,6 +314,8 @@ nodist_systemunit_DATA = \
units/systemd-logger.service \
units/systemd-shutdownd.service \
units/systemd-hostnamed.service \
+ units/systemd-localed.service \
+ units/systemd-timedated.service \
units/systemd-kmsg-syslogd.service \
units/systemd-modules-load.service \
units/systemd-vconsole-setup.service \
@@ -355,6 +363,8 @@ EXTRA_DIST = \
units/systemd-logger.service.in \
units/systemd-shutdownd.service.in \
units/systemd-hostnamed.service.in \
+ units/systemd-localed.service.in \
+ units/systemd-timedated.service.in \
units/systemd-kmsg-syslogd.service.in \
units/systemd-modules-load.service.in \
units/systemd-vconsole-setup.service.in \
@@ -443,7 +453,9 @@ nodist_polkitpolicy_DATA = \
src/org.freedesktop.systemd1.policy
dist_polkitpolicy_DATA = \
- src/org.freedesktop.hostname1.policy
+ src/org.freedesktop.hostname1.policy \
+ src/org.freedesktop.locale1.policy \
+ src/org.freedesktop.timedate1.policy
noinst_LTLIBRARIES = \
libsystemd-basic.la \
@@ -797,7 +809,8 @@ systemd_shutdownd_LDADD = \
systemd_hostnamed_SOURCES = \
src/hostnamed.c \
- src/dbus-common.c
+ src/dbus-common.c \
+ src/polkit.c
systemd_hostnamed_CFLAGS = \
$(AM_CFLAGS) \
@@ -808,6 +821,34 @@ systemd_hostnamed_LDADD = \
libsystemd-daemon.la \
$(DBUS_LIBS)
+systemd_localed_SOURCES = \
+ src/localed.c \
+ src/dbus-common.c \
+ src/polkit.c
+
+systemd_localed_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(DBUS_CFLAGS)
+
+systemd_localed_LDADD = \
+ libsystemd-basic.la \
+ libsystemd-daemon.la \
+ $(DBUS_LIBS)
+
+systemd_timedated_SOURCES = \
+ src/timedated.c \
+ src/dbus-common.c \
+ src/polkit.c
+
+systemd_timedated_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(DBUS_CFLAGS)
+
+systemd_timedated_LDADD = \
+ libsystemd-basic.la \
+ libsystemd-daemon.la \
+ $(DBUS_LIBS)
+
systemd_logind_SOURCES = \
src/logind.c \
src/logind-dbus.c \
@@ -1449,7 +1490,9 @@ endif
rm -f default.target ctrl-alt-del.target dbus-org.freedesktop.hostname1.service && \
$(LN_S) graphical.target default.target && \
$(LN_S) reboot.target ctrl-alt-del.target && \
- $(LN_S) systemd-hostnamed.service dbus-org.freedesktop.hostname1.service )
+ $(LN_S) systemd-hostnamed.service dbus-org.freedesktop.hostname1.service && \
+ $(LN_S) systemd-localed.service dbus-org.freedesktop.locale1.service && \
+ $(LN_S) systemd-timedate.service dbus-org.freedesktop.timedate1.service )
( cd $(DESTDIR)$(systemunitdir)/multi-user.target.wants && \
rm -f getty.target systemd-user-sessions.service systemd-ask-password-wall.path && \
$(LN_S) ../getty.target getty.target && \
diff --git a/src/hostnamed.c b/src/hostnamed.c
index 68c5715..f579e11 100644
--- a/src/hostnamed.c
+++ b/src/hostnamed.c
@@ -29,6 +29,7 @@
#include "util.h"
#include "strv.h"
#include "dbus-common.h"
+#include "polkit.h"
#define INTROSPECTION \
DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
@@ -256,168 +257,6 @@ static int write_data_other(void) {
return r;
}
-/* This mimics dbus_bus_get_unix_user() */
-static pid_t get_unix_process_id(
- DBusConnection *connection,
- const char *name,
- DBusError *error) {
-
- DBusMessage *m = NULL, *reply = NULL;
- uint32_t pid = 0;
-
- m = dbus_message_new_method_call(
- DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- DBUS_INTERFACE_DBUS,
- "GetConnectionUnixProcessID");
- if (!m) {
- dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
- goto finish;
- }
-
- if (!dbus_message_append_args(
- m,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_INVALID)) {
- dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
- goto finish;
- }
-
- reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error);
- if (!reply)
- goto finish;
-
- if (dbus_set_error_from_message(error, reply))
- goto finish;
-
- if (!dbus_message_get_args(
- reply, error,
- DBUS_TYPE_UINT32, &pid,
- DBUS_TYPE_INVALID))
- goto finish;
-
-finish:
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
- return (pid_t) pid;
-}
-
-static int verify_polkit(
- DBusConnection *c,
- DBusMessage *request,
- const char *action,
- bool interactive,
- DBusError *error) {
-
- DBusMessage *m = NULL, *reply = NULL;
- const char *unix_process = "unix-process", *pid = "pid", *starttime = "start-time", *cancel_id = "";
- const char *sender;
- uint32_t flags = interactive ? 1 : 0;
- pid_t pid_raw;
- uint32_t pid_u32;
- unsigned long long starttime_raw;
- uint64_t starttime_u64;
- DBusMessageIter iter_msg, iter_struct, iter_array, iter_dict, iter_variant;
- int r;
- dbus_bool_t authorized = FALSE;
-
- assert(c);
- assert(request);
-
- sender = dbus_message_get_sender(request);
- if (!sender)
- return -EINVAL;
-
- pid_raw = get_unix_process_id(c, sender, error);
- if (pid_raw == 0)
- return -EINVAL;
-
- r = get_starttime_of_pid(pid_raw, &starttime_raw);
- if (r < 0)
- return r;
-
- m = dbus_message_new_method_call(
- "org.freedesktop.PolicyKit1",
- "/org/freedesktop/PolicyKit1/Authority",
- "org.freedesktop.PolicyKit1.Authority",
- "CheckAuthorization");
- if (!m)
- return -ENOMEM;
-
- dbus_message_iter_init_append(m, &iter_msg);
-
- pid_u32 = (uint32_t) pid_raw;
- starttime_u64 = (uint64_t) starttime_raw;
-
- if (!dbus_message_iter_open_container(&iter_msg, DBUS_TYPE_STRUCT, NULL, &iter_struct) ||
- !dbus_message_iter_append_basic(&iter_struct, DBUS_TYPE_STRING, &unix_process) ||
- !dbus_message_iter_open_container(&iter_struct, DBUS_TYPE_ARRAY, "{sv}", &iter_array) ||
- !dbus_message_iter_open_container(&iter_array, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict) ||
- !dbus_message_iter_append_basic(&iter_dict, DBUS_TYPE_STRING, &pid) ||
- !dbus_message_iter_open_container(&iter_dict, DBUS_TYPE_VARIANT, "u", &iter_variant) ||
- !dbus_message_iter_append_basic(&iter_variant, DBUS_TYPE_UINT32, &pid_u32) ||
- !dbus_message_iter_close_container(&iter_dict, &iter_variant) ||
- !dbus_message_iter_close_container(&iter_array, &iter_dict) ||
- !dbus_message_iter_open_container(&iter_array, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict) ||
- !dbus_message_iter_append_basic(&iter_dict, DBUS_TYPE_STRING, &starttime) ||
- !dbus_message_iter_open_container(&iter_dict, DBUS_TYPE_VARIANT, "t", &iter_variant) ||
- !dbus_message_iter_append_basic(&iter_variant, DBUS_TYPE_UINT64, &starttime_u64) ||
- !dbus_message_iter_close_container(&iter_dict, &iter_variant) ||
- !dbus_message_iter_close_container(&iter_array, &iter_dict) ||
- !dbus_message_iter_close_container(&iter_struct, &iter_array) ||
- !dbus_message_iter_close_container(&iter_msg, &iter_struct) ||
- !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_STRING, &action) ||
- !dbus_message_iter_open_container(&iter_msg, DBUS_TYPE_ARRAY, "{ss}", &iter_array) ||
- !dbus_message_iter_close_container(&iter_msg, &iter_array) ||
- !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_UINT32, &flags) ||
- !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_STRING, &cancel_id)) {
- r = -ENOMEM;
- goto finish;
- }
-
- reply = dbus_connection_send_with_reply_and_block(c, m, -1, error);
- if (!reply) {
- r = -EIO;
- goto finish;
- }
-
- if (dbus_set_error_from_message(error, reply)) {
- r = -EIO;
- goto finish;
- }
-
- if (!dbus_message_iter_init(reply, &iter_msg) ||
- dbus_message_iter_get_arg_type(&iter_msg) != DBUS_TYPE_STRUCT) {
- r = -EIO;
- goto finish;
- }
-
- dbus_message_iter_recurse(&iter_msg, &iter_struct);
-
- if (dbus_message_iter_get_arg_type(&iter_struct) != DBUS_TYPE_BOOLEAN) {
- r = -EIO;
- goto finish;
- }
-
- dbus_message_iter_get_basic(&iter_struct, &authorized);
-
- r = authorized ? 0 : -EPERM;
-
-finish:
-
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
- return r;
-}
-
static int bus_hostname_append_icon_name(DBusMessageIter *i, const char *property, void *userdata) {
const char *name;
diff --git a/src/localed.c b/src/localed.c
new file mode 100644
index 0000000..0fbe747
--- /dev/null
+++ b/src/localed.c
@@ -0,0 +1,599 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "strv.h"
+#include "dbus-common.h"
+#include "polkit.h"
+
+#define INTROSPECTION \
+ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
+ "<node>\n" \
+ " <interface name=\"org.freedesktop.locale1\">\n" \
+ " <property name=\"Locale\" type=\"as\" access=\"read\"/>\n" \
+ " <method name=\"SetLocale\">\n" \
+ " <arg name=\"locale\" type=\"as\" direction=\"in\"/>\n" \
+ " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
+ " </method>\n" \
+ " </interface>\n" \
+ BUS_PROPERTIES_INTERFACE \
+ BUS_INTROSPECTABLE_INTERFACE \
+ BUS_PEER_INTERFACE \
+ "</node>\n"
+
+#define INTERFACES_LIST \
+ BUS_GENERIC_INTERFACES_LIST \
+ "org.freedesktop.locale1\0"
+
+enum {
+ /* We don't list LC_ALL here on purpose. People should be
+ * using LANG instead. */
+
+ PROP_LANG,
+ PROP_LC_CTYPE,
+ PROP_LC_NUMERIC,
+ PROP_LC_TIME,
+ PROP_LC_COLLATE,
+ PROP_LC_MONETARY,
+ PROP_LC_MESSAGES,
+ PROP_LC_PAPER,
+ PROP_LC_NAME,
+ PROP_LC_ADDRESS,
+ PROP_LC_TELEPHONE,
+ PROP_LC_MEASUREMENT,
+ PROP_LC_IDENTIFICATION,
+ _PROP_MAX
+};
+
+static const char * const names[_PROP_MAX] = {
+ [PROP_LANG] = "LANG",
+ [PROP_LC_CTYPE] = "LC_CTYPE",
+ [PROP_LC_NUMERIC] = "LC_NUMERIC",
+ [PROP_LC_TIME] = "LC_TIME",
+ [PROP_LC_COLLATE] = "LC_COLLATE",
+ [PROP_LC_MONETARY] = "LC_MONETARY",
+ [PROP_LC_MESSAGES] = "LC_MESSAGES",
+ [PROP_LC_PAPER] = "LC_PAPER",
+ [PROP_LC_NAME] = "LC_NAME",
+ [PROP_LC_ADDRESS] = "LC_ADDRESS",
+ [PROP_LC_TELEPHONE] = "LC_TELEPHONE",
+ [PROP_LC_MEASUREMENT] = "LC_MEASUREMENT",
+ [PROP_LC_IDENTIFICATION] = "LC_IDENTIFICATION"
+};
+
+static char *data[_PROP_MAX] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+static void free_data(void) {
+ int p;
+
+ for (p = 0; p < _PROP_MAX; p++) {
+ free(data[p]);
+ data[p] = NULL;
+ }
+}
+
+static void simplify(void) {
+ int p;
+
+ for (p = 1; p < _PROP_MAX; p++)
+ if (isempty(data[p]) || streq_ptr(data[PROP_LANG], data[p])) {
+ free(data[p]);
+ data[p] = NULL;
+ }
+}
+
+static int read_data(void) {
+ int r;
+
+ free_data();
+
+ r = parse_env_file("/etc/locale.conf", NEWLINE,
+ "LANG", &data[PROP_LANG],
+ "LC_CTYPE", &data[PROP_LC_CTYPE],
+ "LC_NUMERIC", &data[PROP_LC_NUMERIC],
+ "LC_TIME", &data[PROP_LC_TIME],
+ "LC_COLLATE", &data[PROP_LC_COLLATE],
+ "LC_MONETARY", &data[PROP_LC_MONETARY],
+ "LC_MESSAGES", &data[PROP_LC_MESSAGES],
+ "LC_PAPER", &data[PROP_LC_PAPER],
+ "LC_NAME", &data[PROP_LC_NAME],
+ "LC_ADDRESS", &data[PROP_LC_ADDRESS],
+ "LC_TELEPHONE", &data[PROP_LC_TELEPHONE],
+ "LC_MEASUREMENT", &data[PROP_LC_MEASUREMENT],
+ "LC_IDENTIFICATION", &data[PROP_LC_IDENTIFICATION],
+ NULL);
+
+ if (r == -ENOENT) {
+ int p;
+
+ /* Fill in what we got passed from systemd. */
+
+ for (p = 0; p < _PROP_MAX; p++) {
+ char *e, *d;
+
+ assert(names[p]);
+
+ e = getenv(names[p]);
+ if (e) {
+ d = strdup(e);
+ if (!d)
+ return -ENOMEM;
+ } else
+ d = NULL;
+
+ free(data[p]);
+ data[p] = d;
+ }
+
+ r = 0;
+ }
+
+ simplify();
+ return r;
+}
+
+static int write_data(void) {
+ int r, p;
+ char **l = NULL;
+
+ r = load_env_file("/etc/locale.conf", &l);
+ if (r < 0 && r != -ENOENT)
+ return r;
+
+ for (p = 0; p < _PROP_MAX; p++) {
+ char *t, **u;
+
+ assert(names[p]);
+
+ if (isempty(data[p])) {
+ l = strv_env_unset(l, names[p]);
+ continue;
+ }
+
+ if (asprintf(&t, "%s=%s", names[p], data[p]) < 0) {
+ strv_free(l);
+ return -ENOMEM;
+ }
+
+ u = strv_env_set(l, t);
+ free(t);
+ strv_free(l);
+
+ if (!u)
+ return -ENOMEM;
+
+ l = u;
+ }
+
+ if (strv_isempty(l)) {
+
+ if (unlink("/etc/locale.conf") < 0)
+ return errno == ENOENT ? 0 : -errno;
+
+ return 0;
+ }
+
+ r = write_env_file("/etc/locale.conf", l);
+ strv_free(l);
+
+ return r;
+}
+
+static void push_data(DBusConnection *bus) {
+ char **l_set = NULL, **l_unset = NULL, **t;
+ int c_set = 0, c_unset = 0, p;
+ DBusError error;
+ DBusMessage *m = NULL, *reply = NULL;
+ DBusMessageIter iter, sub;
+
+ dbus_error_init(&error);
+
+ assert(bus);
+
+ l_set = new0(char*, _PROP_MAX);
+ l_unset = new0(char*, _PROP_MAX);
+ if (!l_set || !l_unset) {
+ log_error("Out of memory");
+ goto finish;
+ }
+
+ for (p = 0; p < _PROP_MAX; p++) {
+ assert(names[p]);
+
+ if (isempty(data[p]))
+ l_unset[c_set++] = (char*) names[p];
+ else {
+ char *s;
+
+ if (asprintf(&s, "%s=%s", names[p], data[p]) < 0) {
+ log_error("Out of memory");
+ goto finish;
+ }
+
+ l_set[c_unset++] = s;
+ }
+ }
+
+ assert(c_set + c_unset == _PROP_MAX);
+ m = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment");
+ if (!m) {
+ log_error("Could not allocate message.");
+ goto finish;
+ }
+
+ dbus_message_iter_init_append(m, &iter);
+
+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
+ log_error("Out of memory.");
+ goto finish;
+ }
+
+ STRV_FOREACH(t, l_unset)
+ if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, t)) {
+ log_error("Out of memory.");
+ goto finish;
+ }
+
+ if (!dbus_message_iter_close_container(&iter, &sub) ||
+ !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
+ log_error("Out of memory.");
+ goto finish;
+ }
+
+ STRV_FOREACH(t, l_set)
+ if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, t)) {
+ log_error("Out of memory.");
+ goto finish;
+ }
+
+ if (!dbus_message_iter_close_container(&iter, &sub)) {
+ log_error("Out of memory.");
+ goto finish;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+ if (!reply) {
+ log_error("Failed to set locale information: %s", bus_error_message(&error));
+ goto finish;
+ }
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ strv_free(l_set);
+ free(l_unset);
+}
+
+static int append_locale(DBusMessageIter *i, const char *property, void *userdata) {
+ int r, c = 0, p;
+ char **l;
+
+ l = new0(char*, _PROP_MAX+1);
+ if (!l)
+ return -ENOMEM;
+
+ for (p = 0; p < _PROP_MAX; p++) {
+ char *t;
+
+ if (isempty(data[p]))
+ continue;
+
+ if (asprintf(&t, "%s=%s", names[p], data[p]) < 0) {
+ strv_free(l);
+ return -ENOMEM;
+ }
+
+ l[c++] = t;
+ }
+
+ r = bus_property_append_strv(i, property, (void*) l);
+ strv_free(l);
+
+ return r;
+}
+
+static DBusHandlerResult locale_message_handler(
+ DBusConnection *connection,
+ DBusMessage *message,
+ void *userdata) {
+
+ const BusProperty properties[] = {
+ { "org.freedesktop.locale1", "Locale", append_locale, "as", NULL},
+ { NULL, NULL, NULL, NULL, NULL }
+ };
+
+ DBusMessage *reply = NULL, *changed = NULL;
+ DBusError error;
+ int r;
+
+ assert(connection);
+ assert(message);
+
+ dbus_error_init(&error);
+
+ if (dbus_message_is_method_call(message, "org.freedesktop.locale1", "SetLocale")) {
+ char **l = NULL, **i;
+ dbus_bool_t interactive;
+ DBusMessageIter iter;
+ bool modified = false;
+ bool passed[_PROP_MAX];
+ int p;
+
+ if (!dbus_message_iter_init(message, &iter))
+ return bus_send_error_reply(connection, message, NULL, -EINVAL);
+
+ r = bus_parse_strv_iter(&iter, &l);
+ if (r < 0) {
+ if (r == -ENOMEM)
+ goto oom;
+
+ return bus_send_error_reply(connection, message, NULL, r);
+ }
+
+ if (!dbus_message_iter_next(&iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
+ strv_free(l);
+ return bus_send_error_reply(connection, message, NULL, -EINVAL);
+ }
+
+ dbus_message_iter_get_basic(&iter, &interactive);
+
+ zero(passed);
+
+ /* Check whether a variable changed and if so valid */
+ STRV_FOREACH(i, l) {
+ bool valid = false;
+
+ for (p = 0; p < _PROP_MAX; p++) {
+ size_t k;
+
+ k = strlen(names[p]);
+ if (startswith(*i, names[p]) && (*i)[k] == '=') {
+ valid = true;
+ passed[p] = true;
+
+ if (!streq_ptr(*i + k + 1, data[p]))
+ modified = true;
+
+ break;
+ }
+ }
+
+ if (!valid) {
+ strv_free(l);
+ return bus_send_error_reply(connection, message, NULL, -EINVAL);
+ }
+ }
+
+ /* Check whether a variable is unset */
+ if (!modified) {
+ for (p = 0; p < _PROP_MAX; p++)
+ if (!isempty(data[p]) && !passed[p]) {
+ modified = true;
+ break;
+ }
+ }
+
+ if (modified) {
+
+ r = verify_polkit(connection, message, "org.freedesktop.locale1.set-locale", interactive, &error);
+ if (r < 0) {
+ strv_free(l);
+ return bus_send_error_reply(connection, message, &error, r);
+ }
+
+ STRV_FOREACH(i, l) {
+ for (p = 0; p < _PROP_MAX; p++) {
+ size_t k;
+
+ k = strlen(names[p]);
+ if (startswith(*i, names[p]) && (*i)[k] == '=') {
+ char *t;
+
+ t = strdup(*i + k + 1);
+ if (!t) {
+ strv_free(l);
+ goto oom;
+ }
+
+ free(data[p]);
+ data[p] = t;
+
+ break;
+ }
+ }
+ }
+
+ for (p = 0; p < _PROP_MAX; p++) {
+ if (passed[p])
+ continue;
+
+ free(data[p]);
+ data[p] = NULL;
+ }
+
+ simplify();
+
+ r = write_data();
+ if (r < 0) {
+ log_error("Failed to set locale: %s", strerror(-r));
+ return bus_send_error_reply(connection, message, NULL, r);
+ }
+
+ push_data(connection);
+
+ log_info("Changed locale information.");
+
+ changed = bus_properties_changed_new(
+ "/org/freedesktop/locale1",
+ "org.freedesktop.locale1",
+ "Locale\0");
+ if (!changed)
+ goto oom;
+ }
+
+ } else
+ return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+
+ if (!(reply = dbus_message_new_method_return(message)))
+ goto oom;
+
+ if (!dbus_connection_send(connection, reply, NULL))
+ goto oom;
+
+ dbus_message_unref(reply);
+ reply = NULL;
+
+ if (changed) {
+
+ if (!dbus_connection_send(connection, changed, NULL))
+ goto oom;
+
+ dbus_message_unref(changed);
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+
+oom:
+ if (reply)
+ dbus_message_unref(reply);
+
+ if (changed)
+ dbus_message_unref(changed);
+
+ dbus_error_free(&error);
+
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+}
+
+static int connect_bus(DBusConnection **_bus) {
+ static const DBusObjectPathVTable locale_vtable = {
+ .message_function = locale_message_handler
+ };
+ DBusError error;
+ DBusConnection *bus = NULL;
+ int r;
+
+ assert(_bus);
+
+ dbus_error_init(&error);
+
+ bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
+ if (!bus) {
+ log_error("Failed to get system D-Bus connection: %s", error.message);
+ r = -ECONNREFUSED;
+ goto fail;
+ }
+
+ if (!dbus_connection_register_object_path(bus, "/org/freedesktop/locale1", &locale_vtable, NULL)) {
+ log_error("Not enough memory");
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ if (dbus_bus_request_name(bus, "org.freedesktop.locale1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) < 0) {
+ log_error("Failed to register name on bus: %s", error.message);
+ r = -EEXIST;
+ goto fail;
+ }
+
+ if (_bus)
+ *_bus = bus;
+
+ return 0;
+
+fail:
+ dbus_connection_close(bus);
+ dbus_connection_unref(bus);
+
+ dbus_error_free(&error);
+
+ return r;
+}
+
+int main(int argc, char *argv[]) {
+ int r;
+ DBusConnection *bus = NULL;
+
+ log_set_target(LOG_TARGET_AUTO);
+ log_parse_environment();
+ log_open();
+
+ if (argc != 1) {
+ log_error("This program takes no arguments.");
+ r = -EINVAL;
+ goto finish;
+ }
+
+ umask(0022);
+
+ r = read_data();
+ if (r < 0) {
+ log_error("Failed to read locale data: %s", strerror(-r));
+ goto finish;
+ }
+
+ r = connect_bus(&bus);
+ if (r < 0)
+ goto finish;
+
+ while (dbus_connection_read_write_dispatch(bus, -1))
+ ;
+
+ r = 0;
+
+finish:
+ free_data();
+
+ if (bus) {
+ dbus_connection_flush(bus);
+ dbus_connection_close(bus);
+ dbus_connection_unref(bus);
+ }
+
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/src/logind-seat-dbus.c b/src/logind-seat-dbus.c
index 63b1bd5..4937d65 100644
--- a/src/logind-seat-dbus.c
+++ b/src/logind-seat-dbus.c
@@ -29,8 +29,12 @@
#define BUS_SEAT_INTERFACE \
" <interface name=\"org.freedesktop.login1.Seat\">\n" \
" <method name=\"Terminate\"/>\n" \
+ " <method name=\"ActivateSession\">\n" \
+ " <arg name=\"id\" type=\"s\"/>\n" \
+ " </method>\n" \
" <property name=\"Id\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"Active\" type=\"so\" access=\"read\"/>\n" \
+ " <property name=\"ActiveSession\" type=\"so\" access=\"read\"/>\n" \
+ " <property name=\"CanActivateSessions\" type=\"b\" access=\"read\"/>\n" \
" <property name=\"Sessions\" type=\"a(so)\" access=\"read\"/>\n" \
" </interface>\n" \
@@ -125,6 +129,23 @@ static int bus_seat_append_sessions(DBusMessageIter *i, const char *property, vo
return 0;
}
+
+static int bus_seat_append_can_activate(DBusMessageIter *i, const char *property, void *data) {
+ Seat *s = data;
+ dbus_bool_t b;
+
+ assert(i);
+ assert(property);
+ assert(s);
+
+ b = s->manager->vtconsole == s;
+
+ if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+ return -ENOMEM;
+
+ return 0;
+}
+
static int get_seat_for_path(Manager *m, const char *path, Seat **_s) {
Seat *s;
char *id;
@@ -156,9 +177,10 @@ static DBusHandlerResult seat_message_dispatch(
DBusMessage *message) {
const BusProperty properties[] = {
- { "org.freedesktop.login1.Seat", "Id", bus_property_append_string, "s", s->id },
- { "org.freedesktop.login1.Seat", "Active", bus_seat_append_active, "(so)", s },
- { "org.freedesktop.login1.Seat", "Sessions", bus_seat_append_sessions, "a(so)", s },
+ { "org.freedesktop.login1.Seat", "Id", bus_property_append_string, "s", s->id },
+ { "org.freedesktop.login1.Seat", "ActiveSession", bus_seat_append_active, "(so)", s },
+ { "org.freedesktop.login1.Seat", "CanActivateSessions", bus_seat_append_can_activate, "b", s },
+ { "org.freedesktop.login1.Seat", "Sessions", bus_seat_append_sessions, "a(so)", s },
{ NULL, NULL, NULL, NULL, NULL }
};
diff --git a/src/logind-session-dbus.c b/src/logind-session-dbus.c
index 41af658..539384b 100644
--- a/src/logind-session-dbus.c
+++ b/src/logind-session-dbus.c
@@ -30,9 +30,16 @@
" <interface name=\"org.freedesktop.login1.Session\">\n" \
" <method name=\"Terminate\"/>\n" \
" <method name=\"Activate\"/>\n" \
+ " <method name=\"Lock\"/>\n" \
+ " <method name=\"Unlock\"/>\n" \
+ " <method name=\"SetIdleHint\">\n" \
+ " <arg name=\"b\" type=\"b\"/>\n" \
+ " </method>\n" \
" <property name=\"Id\" type=\"u\" access=\"read\"/>\n" \
" <property name=\"User\" type=\"(uo)\" access=\"read\"/>\n" \
" <property name=\"Name\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Timestamp\" type=\"t\" access=\"read\"/>\n" \
+ " <property name=\"TimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
" <property name=\"ControlGroupPath\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"VTNr\" type=\"u\" access=\"read\"/>\n" \
" <property name=\"Seat\" type=\"(so)\" access=\"read\"/>\n" \
@@ -48,6 +55,9 @@
" <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
" <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
" <property name=\"KillProcesses\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
+ " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
" </interface>\n"
#define INTROSPECTION \
diff --git a/src/logind.h b/src/logind.h
index e4b7a3c..95db35d 100644
--- a/src/logind.h
+++ b/src/logind.h
@@ -35,11 +35,9 @@
/* TODO:
*
* recreate VTs when disallocated
- * udev rules
* PAM rewrite
* spawn user systemd
* dbus API
- * don't allow everybody to take logind name
*
* non-local X11 server
* reboot/shutdown halt management
diff --git a/src/org.freedesktop.locale1.conf b/src/org.freedesktop.locale1.conf
new file mode 100644
index 0000000..6827331
--- /dev/null
+++ b/src/org.freedesktop.locale1.conf
@@ -0,0 +1,27 @@
+<?xml version="1.0"?> <!--*-nxml-*-->
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+
+<!--
+ This file is part of systemd.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+-->
+
+<busconfig>
+
+ <policy user="root">
+ <allow own="org.freedesktop.locale1"/>
+ <allow send_destination="org.freedesktop.locale1"/>
+ <allow receive_sender="org.freedesktop.locale1"/>
+ </policy>
+
+ <policy context="default">
+ <allow send_destination="org.freedesktop.locale1"/>
+ <allow receive_sender="org.freedesktop.locale1"/>
+ </policy>
+
+</busconfig>
diff --git a/src/org.freedesktop.locale1.policy b/src/org.freedesktop.locale1.policy
new file mode 100644
index 0000000..6c755fd
--- /dev/null
+++ b/src/org.freedesktop.locale1.policy
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?> <!--*-nxml-*-->
+<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
+
+<!--
+ This file is part of systemd.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+-->
+
+<policyconfig>
+
+ <vendor>The systemd Project</vendor>
+ <vendor_url>http://www.freedesktop.org/wiki/Software/systemd</vendor_url>
+
+ <action id="org.freedesktop.locale1.set-locale">
+ <description>Set system locale</description>
+ <message>Authentication is required to set the system locale.</message>
+ <defaults>
+ <allow_any>auth_admin_keep</allow_any>
+ <allow_inactive>auth_admin_keep</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ </action>
+
+</policyconfig>
diff --git a/src/org.freedesktop.locale1.service b/src/org.freedesktop.locale1.service
new file mode 100644
index 0000000..29bd582
--- /dev/null
+++ b/src/org.freedesktop.locale1.service
@@ -0,0 +1,12 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+[D-BUS Service]
+Name=org.freedesktop.locale1
+Exec=/bin/false
+User=root
+SystemdService=dbus-org.freedesktop.locale1.service
diff --git a/src/org.freedesktop.login1.conf b/src/org.freedesktop.login1.conf
index 20008ea..ebc499d 100644
--- a/src/org.freedesktop.login1.conf
+++ b/src/org.freedesktop.login1.conf
@@ -20,7 +20,6 @@
</policy>
<policy context="default">
- <allow own="org.freedesktop.login1"/>
<allow send_destination="org.freedesktop.login1"/>
<allow receive_sender="org.freedesktop.login1"/>
</policy>
diff --git a/src/org.freedesktop.timedate1.conf b/src/org.freedesktop.timedate1.conf
new file mode 100644
index 0000000..c9c221b
--- /dev/null
+++ b/src/org.freedesktop.timedate1.conf
@@ -0,0 +1,27 @@
+<?xml version="1.0"?> <!--*-nxml-*-->
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+
+<!--
+ This file is part of systemd.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+-->
+
+<busconfig>
+
+ <policy user="root">
+ <allow own="org.freedesktop.timedate1"/>
+ <allow send_destination="org.freedesktop.timedate1"/>
+ <allow receive_sender="org.freedesktop.timedate1"/>
+ </policy>
+
+ <policy context="default">
+ <allow send_destination="org.freedesktop.timedate1"/>
+ <allow receive_sender="org.freedesktop.timedate1"/>
+ </policy>
+
+</busconfig>
diff --git a/src/org.freedesktop.timedate1.policy b/src/org.freedesktop.timedate1.policy
new file mode 100644
index 0000000..5010efd
--- /dev/null
+++ b/src/org.freedesktop.timedate1.policy
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?> <!--*-nxml-*-->
+<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
+
+<!--
+ This file is part of systemd.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+-->
+
+<policyconfig>
+
+ <vendor>The systemd Project</vendor>
+ <vendor_url>http://www.freedesktop.org/wiki/Software/systemd</vendor_url>
+
+ <action id="org.freedesktop.timedate1.set-time">
+ <description>Set system time</description>
+ <message>Authentication is required to set the system time.</message>
+ <defaults>
+ <allow_any>auth_admin_keep</allow_any>
+ <allow_inactive>auth_admin_keep</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ </action>
+
+ <action id="org.freedesktop.timedate1.set-timezone">
+ <description>Set system timezone</description>
+ <message>Authentication is required to set the system timezone.</message>
+ <defaults>
+ <allow_any>auth_admin_keep</allow_any>
+ <allow_inactive>auth_admin_keep</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ </action>
+
+ <action id="org.freedesktop.timedate1.set-local-rtc">
+ <description>Set RTC to local timezone or UTC</description>
+ <message>Authentication is required to control whether
+ the RTC stores the local or UTC time.</message>
+ <defaults>
+ <allow_any>auth_admin_keep</allow_any>
+ <allow_inactive>auth_admin_keep</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ </action>
+
+</policyconfig>
diff --git a/src/org.freedesktop.timedate1.service b/src/org.freedesktop.timedate1.service
new file mode 100644
index 0000000..c3120b6
--- /dev/null
+++ b/src/org.freedesktop.timedate1.service
@@ -0,0 +1,12 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+[D-BUS Service]
+Name=org.freedesktop.timedate1
+Exec=/bin/false
+User=root
+SystemdService=dbus-org.freedesktop.timedate1.service
diff --git a/src/polkit.c b/src/polkit.c
new file mode 100644
index 0000000..5b67480
--- /dev/null
+++ b/src/polkit.c
@@ -0,0 +1,190 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/types.h>
+
+#include <errno.h>
+
+#include "util.h"
+#include "dbus-common.h"
+#include "polkit.h"
+
+/* This mimics dbus_bus_get_unix_user() */
+static pid_t get_unix_process_id(
+ DBusConnection *connection,
+ const char *name,
+ DBusError *error) {
+
+ DBusMessage *m = NULL, *reply = NULL;
+ uint32_t pid = 0;
+
+ m = dbus_message_new_method_call(
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ "GetConnectionUnixProcessID");
+ if (!m) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
+ goto finish;
+ }
+
+ if (!dbus_message_append_args(
+ m,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID)) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
+ goto finish;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error);
+ if (!reply)
+ goto finish;
+
+ if (dbus_set_error_from_message(error, reply))
+ goto finish;
+
+ if (!dbus_message_get_args(
+ reply, error,
+ DBUS_TYPE_UINT32, &pid,
+ DBUS_TYPE_INVALID))
+ goto finish;
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ return (pid_t) pid;
+}
+
+int verify_polkit(
+ DBusConnection *c,
+ DBusMessage *request,
+ const char *action,
+ bool interactive,
+ DBusError *error) {
+
+ DBusMessage *m = NULL, *reply = NULL;
+ const char *unix_process = "unix-process", *pid = "pid", *starttime = "start-time", *cancel_id = "";
+ const char *sender;
+ uint32_t flags = interactive ? 1 : 0;
+ pid_t pid_raw;
+ uint32_t pid_u32;
+ unsigned long long starttime_raw;
+ uint64_t starttime_u64;
+ DBusMessageIter iter_msg, iter_struct, iter_array, iter_dict, iter_variant;
+ int r;
+ dbus_bool_t authorized = FALSE;
+
+ assert(c);
+ assert(request);
+
+ sender = dbus_message_get_sender(request);
+ if (!sender)
+ return -EINVAL;
+
+ pid_raw = get_unix_process_id(c, sender, error);
+ if (pid_raw == 0)
+ return -EINVAL;
+
+ r = get_starttime_of_pid(pid_raw, &starttime_raw);
+ if (r < 0)
+ return r;
+
+ m = dbus_message_new_method_call(
+ "org.freedesktop.PolicyKit1",
+ "/org/freedesktop/PolicyKit1/Authority",
+ "org.freedesktop.PolicyKit1.Authority",
+ "CheckAuthorization");
+ if (!m)
+ return -ENOMEM;
+
+ dbus_message_iter_init_append(m, &iter_msg);
+
+ pid_u32 = (uint32_t) pid_raw;
+ starttime_u64 = (uint64_t) starttime_raw;
+
+ if (!dbus_message_iter_open_container(&iter_msg, DBUS_TYPE_STRUCT, NULL, &iter_struct) ||
+ !dbus_message_iter_append_basic(&iter_struct, DBUS_TYPE_STRING, &unix_process) ||
+ !dbus_message_iter_open_container(&iter_struct, DBUS_TYPE_ARRAY, "{sv}", &iter_array) ||
+ !dbus_message_iter_open_container(&iter_array, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict) ||
+ !dbus_message_iter_append_basic(&iter_dict, DBUS_TYPE_STRING, &pid) ||
+ !dbus_message_iter_open_container(&iter_dict, DBUS_TYPE_VARIANT, "u", &iter_variant) ||
+ !dbus_message_iter_append_basic(&iter_variant, DBUS_TYPE_UINT32, &pid_u32) ||
+ !dbus_message_iter_close_container(&iter_dict, &iter_variant) ||
+ !dbus_message_iter_close_container(&iter_array, &iter_dict) ||
+ !dbus_message_iter_open_container(&iter_array, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict) ||
+ !dbus_message_iter_append_basic(&iter_dict, DBUS_TYPE_STRING, &starttime) ||
+ !dbus_message_iter_open_container(&iter_dict, DBUS_TYPE_VARIANT, "t", &iter_variant) ||
+ !dbus_message_iter_append_basic(&iter_variant, DBUS_TYPE_UINT64, &starttime_u64) ||
+ !dbus_message_iter_close_container(&iter_dict, &iter_variant) ||
+ !dbus_message_iter_close_container(&iter_array, &iter_dict) ||
+ !dbus_message_iter_close_container(&iter_struct, &iter_array) ||
+ !dbus_message_iter_close_container(&iter_msg, &iter_struct) ||
+ !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_STRING, &action) ||
+ !dbus_message_iter_open_container(&iter_msg, DBUS_TYPE_ARRAY, "{ss}", &iter_array) ||
+ !dbus_message_iter_close_container(&iter_msg, &iter_array) ||
+ !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_UINT32, &flags) ||
+ !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_STRING, &cancel_id)) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(c, m, -1, error);
+ if (!reply) {
+ r = -EIO;
+ goto finish;
+ }
+
+ if (dbus_set_error_from_message(error, reply)) {
+ r = -EIO;
+ goto finish;
+ }
+
+ if (!dbus_message_iter_init(reply, &iter_msg) ||
+ dbus_message_iter_get_arg_type(&iter_msg) != DBUS_TYPE_STRUCT) {
+ r = -EIO;
+ goto finish;
+ }
+
+ dbus_message_iter_recurse(&iter_msg, &iter_struct);
+
+ if (dbus_message_iter_get_arg_type(&iter_struct) != DBUS_TYPE_BOOLEAN) {
+ r = -EIO;
+ goto finish;
+ }
+
+ dbus_message_iter_get_basic(&iter_struct, &authorized);
+
+ r = authorized ? 0 : -EPERM;
+
+finish:
+
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ return r;
+}
diff --git a/src/polkit.h b/src/polkit.h
new file mode 100644
index 0000000..fc4e771
--- /dev/null
+++ b/src/polkit.h
@@ -0,0 +1,35 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foopolkithfoo
+#define foopolkithfoo
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <dbus/dbus.h>
+
+int verify_polkit(
+ DBusConnection *c,
+ DBusMessage *request,
+ const char *action,
+ bool interactive,
+ DBusError *error);
+
+#endif
diff --git a/src/timedated.c b/src/timedated.c
new file mode 100644
index 0000000..4749648
--- /dev/null
+++ b/src/timedated.c
@@ -0,0 +1,544 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "strv.h"
+#include "dbus-common.h"
+#include "polkit.h"
+
+#define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n"
+#define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n"
+
+#define INTROSPECTION \
+ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
+ "<node>\n" \
+ " <interface name=\"org.freedesktop.timedate1\">\n" \
+ " <property name=\"Timezone\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"LocalRTC\" type=\"b\" access=\"read\"/>\n" \
+ " <method name=\"SetTime\">\n" \
+ " <arg name=\"usec_utc\" type=\"x\" direction=\"in\"/>\n" \
+ " <arg name=\"relative\" type=\"b\" direction=\"in\"/>\n" \
+ " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
+ " </method>\n" \
+ " <method name=\"SetTimezone\">\n" \
+ " <arg name=\"timezone\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
+ " </method>\n" \
+ " <method name=\"SetLocalRTC\">\n" \
+ " <arg name=\"local_rtc\" type=\"b\" direction=\"in\"/>\n" \
+ " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
+ " </method>\n" \
+ " </interface>\n" \
+ BUS_PROPERTIES_INTERFACE \
+ BUS_INTROSPECTABLE_INTERFACE \
+ BUS_PEER_INTERFACE \
+ "</node>\n"
+
+#define INTERFACES_LIST \
+ BUS_GENERIC_INTERFACES_LIST \
+ "org.freedesktop.locale1\0"
+
+static char *zone = NULL;
+static bool local_rtc = false;
+
+static void free_data(void) {
+ free(zone);
+ zone = NULL;
+
+ local_rtc = false;
+}
+
+static bool valid_timezone(const char *name) {
+ const char *p;
+ char *t;
+ bool slash = false;
+ int r;
+ struct stat st;
+
+ assert(name);
+
+ if (*name == '/' || *name == 0)
+ return false;
+
+ for (p = name; *p; p++) {
+ if (!(*p >= '0' && *p <= '9') &&
+ !(*p >= 'a' && *p <= 'z') &&
+ !(*p >= 'A' && *p <= 'Z') &&
+ !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
+ return false;
+
+ if (*p == '/') {
+
+ if (slash)
+ return false;
+
+ slash = true;
+ } else
+ slash = false;
+ }
+
+ if (slash)
+ return false;
+
+ t = strappend("/usr/share/zoneinfo/", name);
+ if (!t)
+ return false;
+
+ r = stat(t, &st);
+ free(t);
+
+ if (r < 0)
+ return false;
+
+ if (!S_ISREG(st.st_mode))
+ return false;
+
+ return true;
+}
+
+static void verify_timezone(void) {
+ char *p, *a = NULL, *b = NULL;
+ size_t l, q;
+ int j, k;
+
+ if (!zone)
+ return;
+
+ p = strappend("/usr/share/zoneinfo/", zone);
+ if (!p) {
+ log_error("Out of memory");
+ return;
+ }
+
+ j = read_full_file("/etc/localtime", &a, &l);
+ k = read_full_file(p, &b, &q);
+
+ free(p);
+
+ if (j < 0 || k < 0 || l != q || memcmp(a, b, l)) {
+ log_warning("/etc/localtime and /etc/timezone out of sync.");
+ free(zone);
+ zone = NULL;
+ }
+
+ free(a);
+ free(b);
+}
+
+static int read_data(void) {
+ int r;
+ FILE *f;
+
+ free_data();
+
+ r = read_one_line_file("/etc/timezone", &zone);
+ if (r < 0 && r != -ENOENT)
+ return r;
+
+ verify_timezone();
+
+ f = fopen("/etc/adjtime", "r");
+ if (f) {
+ char line[LINE_MAX];
+ bool b;
+
+ b = fgets(line, sizeof(line), f) &&
+ fgets(line, sizeof(line), f) &&
+ fgets(line, sizeof(line), f);
+
+ fclose(f);
+
+ if (!b)
+ return -EIO;
+
+ truncate_nl(line);
+ local_rtc = streq(line, "LOCAL");
+
+ } else if (errno != ENOENT)
+ return -errno;
+
+ return 0;
+}
+
+static int write_data_timezone(void) {
+ int r = 0;
+ char *p;
+
+ if (!zone) {
+ if (unlink("/etc/timezone") < 0 && errno != ENOENT)
+ r = -errno;
+
+ if (unlink("/etc/localtime") < 0 && errno != ENOENT)
+ r = -errno;
+
+ return r;
+ }
+
+ p = strappend("/usr/share/zoneinfo/", zone);
+ if (!p) {
+ log_error("Out of memory");
+ return -ENOMEM;
+ }
+
+ r = symlink_or_copy_atomic(p, "/etc/localtime");
+ free(p);
+
+ if (r < 0)
+ return r;
+
+ r = write_one_line_file_atomic("/etc/timezone", zone);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static int write_data_local_rtc(void) {
+ int r;
+ char *s, *w;
+
+ r = read_full_file("/etc/adjtime", &s, NULL);
+ if (r < 0) {
+ if (r != -ENOENT)
+ return r;
+
+ if (!local_rtc)
+ return 0;
+
+ w = strdup(NULL_ADJTIME_LOCAL);
+ if (!w)
+ return -ENOMEM;
+ } else {
+ char *p, *e;
+ size_t a, b;
+
+ p = strchr(s, '\n');
+ if (!p) {
+ free(s);
+ return -EIO;
+ }
+
+ p = strchr(p+1, '\n');
+ if (!p) {
+ free(s);
+ return -EIO;
+ }
+
+ p++;
+ e = strchr(p, '\n');
+ if (!p) {
+ free(s);
+ return -EIO;
+ }
+
+ a = p - s;
+ b = strlen(e);
+
+ w = new(char, a + (local_rtc ? 5 : 3) + b + 1);
+ if (!w) {
+ free(s);
+ return -ENOMEM;
+ }
+
+ *(char*) mempcpy(stpcpy(mempcpy(w, s, a), local_rtc ? "LOCAL" : "UTC"), e, b) = 0;
+
+ if (streq(w, NULL_ADJTIME_UTC)) {
+ free(w);
+
+ if (unlink("/etc/adjtime") < 0) {
+ if (errno != ENOENT)
+ return -errno;
+ }
+
+ return 0;
+ }
+ }
+
+ r = write_one_line_file_atomic("/etc/adjtime", w);
+ free(w);
+
+ return r;
+}
+
+static DBusHandlerResult timedate_message_handler(
+ DBusConnection *connection,
+ DBusMessage *message,
+ void *userdata) {
+
+ const BusProperty properties[] = {
+ { "org.freedesktop.timedate1", "Timezone", bus_property_append_string, "s", zone },
+ { "org.freedesktop.timedate1", "LocalRTC", bus_property_append_bool, "b", &local_rtc },
+ { NULL, NULL, NULL, NULL, NULL }
+ };
+
+ DBusMessage *reply = NULL, *changed = NULL;
+ DBusError error;
+ int r;
+
+ assert(connection);
+ assert(message);
+
+ dbus_error_init(&error);
+
+ if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetTimezone")) {
+ const char *z;
+ dbus_bool_t interactive;
+
+ if (!dbus_message_get_args(
+ message,
+ &error,
+ DBUS_TYPE_STRING, &z,
+ DBUS_TYPE_BOOLEAN, &interactive,
+ DBUS_TYPE_INVALID))
+ return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+ if (!valid_timezone(z))
+ return bus_send_error_reply(connection, message, NULL, -EINVAL);
+
+ if (!streq_ptr(z, zone)) {
+ char *t;
+
+ r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-timezone", interactive, &error);
+ if (r < 0)
+ return bus_send_error_reply(connection, message, &error, r);
+
+ t = strdup(z);
+ if (!t)
+ goto oom;
+
+ free(zone);
+ zone = t;
+
+ r = write_data_timezone();
+ if (r < 0) {
+ log_error("Failed to set timezone: %s", strerror(-r));
+ return bus_send_error_reply(connection, message, NULL, r);
+ }
+
+ log_info("Changed timezone to '%s'.", zone);
+
+ changed = bus_properties_changed_new(
+ "/org/freedesktop/timedate1",
+ "org.freedesktop.timedate1",
+ "Timezone\0");
+ if (!changed)
+ goto oom;
+ }
+
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetLocalRTC")) {
+ dbus_bool_t lrtc;
+ dbus_bool_t interactive;
+
+ if (!dbus_message_get_args(
+ message,
+ &error,
+ DBUS_TYPE_BOOLEAN, &lrtc,
+ DBUS_TYPE_BOOLEAN, &interactive,
+ DBUS_TYPE_INVALID))
+ return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+ if (lrtc != local_rtc) {
+ r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-local-rtc", interactive, &error);
+ if (r < 0)
+ return bus_send_error_reply(connection, message, &error, r);
+
+ local_rtc = lrtc;
+
+ r = write_data_local_rtc();
+ if (r < 0) {
+ log_error("Failed to set RTC to local/UTC: %s", strerror(-r));
+ return bus_send_error_reply(connection, message, NULL, r);
+ }
+
+ log_info("Changed local RTC setting to '%s'.", yes_no(local_rtc));
+
+ changed = bus_properties_changed_new(
+ "/org/freedesktop/timedate1",
+ "org.freedesktop.timedate1",
+ "LocalRTC\0");
+ if (!changed)
+ goto oom;
+ }
+
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetTime")) {
+ int64_t utc;
+ dbus_bool_t relative;
+ dbus_bool_t interactive;
+
+ if (!dbus_message_get_args(
+ message,
+ &error,
+ DBUS_TYPE_INT64, &utc,
+ DBUS_TYPE_BOOLEAN, &relative,
+ DBUS_TYPE_BOOLEAN, &interactive,
+ DBUS_TYPE_INVALID))
+ return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+ if (!relative && utc <= 0)
+ return bus_send_error_reply(connection, message, NULL, -EINVAL);
+
+ if (!relative || utc != 0) {
+ struct timespec ts;
+
+ r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-time", interactive, &error);
+ if (r < 0)
+ return bus_send_error_reply(connection, message, &error, r);
+
+ if (relative)
+ timespec_store(&ts, now(CLOCK_REALTIME) + utc);
+ else
+ timespec_store(&ts, utc);
+
+ if (clock_settime(CLOCK_REALTIME, &ts) < 0) {
+ log_error("Failed to set local time: %m");
+ return bus_send_error_reply(connection, message, NULL, -errno);
+ }
+
+ log_info("Changed local time to %s", ctime(&ts.tv_sec));
+ }
+
+ } else
+ return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+
+ if (!(reply = dbus_message_new_method_return(message)))
+ goto oom;
+
+ if (!dbus_connection_send(connection, reply, NULL))
+ goto oom;
+
+ dbus_message_unref(reply);
+ reply = NULL;
+
+ if (changed) {
+
+ if (!dbus_connection_send(connection, changed, NULL))
+ goto oom;
+
+ dbus_message_unref(changed);
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+
+oom:
+ if (reply)
+ dbus_message_unref(reply);
+
+ if (changed)
+ dbus_message_unref(changed);
+
+ dbus_error_free(&error);
+
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+}
+
+static int connect_bus(DBusConnection **_bus) {
+ static const DBusObjectPathVTable timedate_vtable = {
+ .message_function = timedate_message_handler
+ };
+ DBusError error;
+ DBusConnection *bus = NULL;
+ int r;
+
+ assert(_bus);
+
+ dbus_error_init(&error);
+
+ bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
+ if (!bus) {
+ log_error("Failed to get system D-Bus connection: %s", error.message);
+ r = -ECONNREFUSED;
+ goto fail;
+ }
+
+ if (!dbus_connection_register_object_path(bus, "/org/freedesktop/timedate1", &timedate_vtable, NULL)) {
+ log_error("Not enough memory");
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ if (dbus_bus_request_name(bus, "org.freedesktop.timedate1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) < 0) {
+ log_error("Failed to register name on bus: %s", error.message);
+ r = -EEXIST;
+ goto fail;
+ }
+
+ if (_bus)
+ *_bus = bus;
+
+ return 0;
+
+fail:
+ dbus_connection_close(bus);
+ dbus_connection_unref(bus);
+
+ dbus_error_free(&error);
+
+ return r;
+}
+
+int main(int argc, char *argv[]) {
+ int r;
+ DBusConnection *bus = NULL;
+
+ log_set_target(LOG_TARGET_AUTO);
+ log_parse_environment();
+ log_open();
+
+ if (argc != 1) {
+ log_error("This program takes no arguments.");
+ r = -EINVAL;
+ goto finish;
+ }
+
+ umask(0022);
+
+ r = read_data();
+ if (r < 0) {
+ log_error("Failed to read timezone data: %s", strerror(-r));
+ goto finish;
+ }
+
+ r = connect_bus(&bus);
+ if (r < 0)
+ goto finish;
+
+ while (dbus_connection_read_write_dispatch(bus, -1))
+ ;
+
+ r = 0;
+
+finish:
+ free_data();
+
+ if (bus) {
+ dbus_connection_flush(bus);
+ dbus_connection_close(bus);
+ dbus_connection_unref(bus);
+ }
+
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/units/.gitignore b/units/.gitignore
index f969466..9634440 100644
--- a/units/.gitignore
+++ b/units/.gitignore
@@ -1,3 +1,5 @@
+systemd-localed.service
+systemd-timedated.service
systemd-hostnamed.service
console-shell.service
systemd-sysctl.service
diff --git a/units/systemd-localed.service.in b/units/systemd-localed.service.in
new file mode 100644
index 0000000..4be65df
--- /dev/null
+++ b/units/systemd-localed.service.in
@@ -0,0 +1,17 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+# See systemd.special(7) for details
+
+[Unit]
+Description=Locale Service
+
+[Service]
+ExecStart=@rootlibexecdir@/systemd-localed
+Type=dbus
+BusName=org.freedesktop.locale1
+CapabilityBoundingSet=
diff --git a/units/systemd-timedated.service.in b/units/systemd-timedated.service.in
new file mode 100644
index 0000000..90ff443
--- /dev/null
+++ b/units/systemd-timedated.service.in
@@ -0,0 +1,17 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+# See systemd.special(7) for details
+
+[Unit]
+Description=Time & Date Service
+
+[Service]
+ExecStart=@rootlibexecdir@/systemd-timedated
+Type=dbus
+BusName=org.freedesktop.timedate1
+CapabilityBoundingSet=CAP_SYS_TIME
commit 34ca941cec76bbfdfd02c705b76bc1b53ea2bcd1
Author: Lennart Poettering <lennart at poettering.net>
Date: Wed Jun 15 15:35:23 2011 +0200
util: make a couple of files we write atomic
diff --git a/src/hostnamed.c b/src/hostnamed.c
index cf2172f..68c5715 100644
--- a/src/hostnamed.c
+++ b/src/hostnamed.c
@@ -201,7 +201,7 @@ static int write_data_static_hostname(void) {
return 0;
}
- return write_one_line_file("/etc/hostname", data[PROP_STATIC_HOSTNAME]);
+ return write_one_line_file_atomic("/etc/hostname", data[PROP_STATIC_HOSTNAME]);
}
static int write_data_other(void) {
diff --git a/src/shutdownd.c b/src/shutdownd.c
index 8f765b4..1381941 100644
--- a/src/shutdownd.c
+++ b/src/shutdownd.c
@@ -320,7 +320,7 @@ int main(int argc, char *argv[]) {
log_info("Creating /run/nologin, blocking further logins...");
- if ((e = write_one_line_file("/run/nologin", "System is going down.")) < 0)
+ if ((e = write_one_line_file_atomic("/run/nologin", "System is going down.")) < 0)
log_error("Failed to create /run/nologin: %s", strerror(-e));
else
unlink_nologin = true;
diff --git a/src/user-sessions.c b/src/user-sessions.c
index e045b88..ffb8657 100644
--- a/src/user-sessions.c
+++ b/src/user-sessions.c
@@ -67,7 +67,7 @@ int main(int argc, char*argv[]) {
int r, q;
char *cgroup_user_tree = NULL;
- if ((r = write_one_line_file("/run/nologin", "System is going down.")) < 0)
+ if ((r = write_one_line_file_atomic("/run/nologin", "System is going down.")) < 0)
log_error("Failed to create /run/nologin: %s", strerror(-r));
if ((q = cg_get_user_path(&cgroup_user_tree)) < 0) {
diff --git a/src/util.c b/src/util.c
index 81d247c..dfb153b 100644
--- a/src/util.c
+++ b/src/util.c
@@ -567,6 +567,7 @@ int write_one_line_file(const char *fn, const char *line) {
if (!(f = fopen(fn, "we")))
return -errno;
+ errno = 0;
if (fputs(line, f) < 0) {
r = -errno;
goto finish;
@@ -590,6 +591,64 @@ finish:
return r;
}
+int fchmod_umask(int fd, mode_t m) {
+ mode_t u;
+ int r;
+
+ u = umask(0777);
+ r = fchmod(fd, m & (~u)) < 0 ? -errno : 0;
+ umask(u);
+
+ return r;
+}
+
+int write_one_line_file_atomic(const char *fn, const char *line) {
+ FILE *f;
+ int r;
+ char *p;
+
+ assert(fn);
+ assert(line);
+
+ r = fopen_temporary(fn, &f, &p);
+ if (r < 0)
+ return r;
+
+ fchmod_umask(fileno(f), 0644);
+
+ errno = 0;
+ if (fputs(line, f) < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ if (!endswith(line, "\n"))
+ fputc('\n', f);
+
+ fflush(f);
+
+ if (ferror(f)) {
+ if (errno != 0)
+ r = -errno;
+ else
+ r = -EIO;
+ } else {
+ if (rename(p, fn) < 0)
+ r = -errno;
+ else
+ r = 0;
+ }
+
+finish:
+ if (r < 0)
+ unlink(p);
+
+ fclose(f);
+ free(p);
+
+ return r;
+}
+
int read_one_line_file(const char *fn, char **line) {
FILE *f;
int r;
@@ -621,7 +680,7 @@ finish:
return r;
}
-int read_full_file(const char *fn, char **contents) {
+int read_full_file(const char *fn, char **contents, size_t *size) {
FILE *f;
int r;
size_t n, l;
@@ -636,6 +695,12 @@ int read_full_file(const char *fn, char **contents) {
goto finish;
}
+ /* Safety check */
+ if (st.st_size > 4*1024*1024) {
+ r = -E2BIG;
+ goto finish;
+ }
+
n = st.st_size > 0 ? st.st_size : LINE_MAX;
l = 0;
@@ -680,6 +745,9 @@ int read_full_file(const char *fn, char **contents) {
*contents = buf;
buf = NULL;
+ if (size)
+ *size = l;
+
r = 0;
finish:
@@ -699,7 +767,7 @@ int parse_env_file(
assert(fname);
assert(separator);
- if ((r = read_full_file(fname, &contents)) < 0)
+ if ((r = read_full_file(fname, &contents, NULL)) < 0)
return r;
p = contents;
@@ -838,15 +906,17 @@ finish:
}
int write_env_file(const char *fname, char **l) {
-
- char **i;
+ char **i, *p;
FILE *f;
int r;
- f = fopen(fname, "we");
- if (!f)
- return -errno;
+ r = fopen_temporary(fname, &f, &p);
+ if (r < 0)
+ return r;
+ fchmod_umask(fileno(f), 0644);
+
+ errno = 0;
STRV_FOREACH(i, l) {
fputs(*i, f);
fputc('\n', f);
@@ -854,8 +924,23 @@ int write_env_file(const char *fname, char **l) {
fflush(f);
- r = ferror(f) ? -errno : 0;
+ if (ferror(f)) {
+ if (errno != 0)
+ r = -errno;
+ else
+ r = -EIO;
+ } else {
+ if (rename(p, fname) < 0)
+ r = -errno;
+ else
+ r = 0;
+ }
+
+ if (r < 0)
+ unlink(p);
+
fclose(f);
+ free(p);
return r;
}
@@ -4778,6 +4863,152 @@ int hwclock_set_time(const struct tm *tm) {
return err;
}
+int copy_file(const char *from, const char *to) {
+ int r, fdf, fdt;
+
+ assert(from);
+ assert(to);
+
+ fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (fdf < 0)
+ return -errno;
+
+ fdt = open(to, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY, 0644);
+ if (fdt < 0) {
+ close_nointr_nofail(fdf);
+ return -errno;
+ }
+
+ for (;;) {
+ char buf[PIPE_BUF];
+ ssize_t n, k;
+
+ n = read(fdf, buf, sizeof(buf));
+ if (n < 0) {
+ r = -errno;
+
+ close_nointr_nofail(fdf);
+ close_nointr(fdt);
+ unlink(to);
+
+ return r;
+ }
+
+ if (n == 0)
+ break;
+
+ errno = 0;
+ k = loop_write(fdt, buf, n, false);
+ if (n != k) {
+ r = k < 0 ? k : (errno ? -errno : -EIO);
+
+ close_nointr_nofail(fdf);
+ close_nointr(fdt);
+
+ unlink(to);
+ return r;
+ }
+ }
+
+ close_nointr_nofail(fdf);
+ r = close_nointr(fdt);
+
+ if (r < 0) {
+ unlink(to);
+ return r;
+ }
+
+ return 0;
+}
+
+int symlink_or_copy(const char *from, const char *to) {
+ char *pf = NULL, *pt = NULL;
+ struct stat a, b;
+ int r;
+
+ assert(from);
+ assert(to);
+
+ if (parent_of_path(from, &pf) < 0 ||
+ parent_of_path(to, &pt) < 0) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ if (stat(pf, &a) < 0 ||
+ stat(pt, &b) < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ if (a.st_dev != b.st_dev) {
+ free(pf);
+ free(pt);
+
+ return copy_file(from, to);
+ }
+
+ if (symlink(from, to) < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ r = 0;
+
+finish:
+ free(pf);
+ free(pt);
+
+ return r;
+}
+
+int symlink_or_copy_atomic(const char *from, const char *to) {
+ char *t, *x;
+ const char *fn;
+ size_t k;
+ unsigned long long ull;
+ unsigned i;
+ int r;
+
+ assert(from);
+ assert(to);
+
+ t = new(char, strlen(to) + 1 + 16 + 1);
+ if (!t)
+ return -ENOMEM;
+
+ fn = file_name_from_path(to);
+ k = fn-to;
+ memcpy(t, to, k);
+ t[k] = '.';
+ x = stpcpy(t+k+1, fn);
+
+ ull = random_ull();
+ for (i = 0; i < 16; i++) {
+ *(x++) = hexchar(ull & 0xF);
+ ull >>= 4;
+ }
+
+ *x = 0;
+
+ r = symlink_or_copy(from, t);
+ if (r < 0) {
+ unlink(t);
+ free(t);
+ return r;
+ }
+
+ if (rename(t, to) < 0) {
+ r = -errno;
+ unlink(t);
+ free(t);
+ return r;
+ }
+
+ free(t);
+ return r;
+}
+
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",
diff --git a/src/util.h b/src/util.h
index 15dfe17..bd98b65 100644
--- a/src/util.h
+++ b/src/util.h
@@ -200,8 +200,9 @@ pid_t get_parent_of_pid(pid_t pid, pid_t *ppid);
int get_starttime_of_pid(pid_t pid, unsigned long long *st);
int write_one_line_file(const char *fn, const char *line);
+int write_one_line_file_atomic(const char *fn, const char *line);
int read_one_line_file(const char *fn, char **line);
-int read_full_file(const char *fn, char **contents);
+int read_full_file(const char *fn, char **contents, size_t *size);
int parse_env_file(const char *fname, const char *separator, ...) _sentinel_;
int load_env_file(const char *fname, char ***l);
@@ -422,6 +423,22 @@ int terminal_vhangup(const char *name);
int vt_disallocate(const char *name);
+int copy_file(const char *from, const char *to);
+int symlink_or_copy(const char *from, const char *to);
+int symlink_or_copy_atomic(const char *from, const char *to);
+
+int fchmod_umask(int fd, mode_t mode);
+
+int conf_files_list(char ***strv, const char *suffix, const char *dir, ...);
+
+bool hwclock_is_localtime(void);
+
+int hwclock_apply_localtime_delta(void);
+
+int hwclock_get_time(struct tm *tm);
+
+int hwclock_set_time(const struct tm *tm);
+
#define NULSTR_FOREACH(i, l) \
for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
@@ -454,14 +471,4 @@ int signal_from_string(const char *s);
int signal_from_string_try_harder(const char *s);
-int conf_files_list(char ***strv, const char *suffix, const char *dir, ...);
-
-bool hwclock_is_localtime(void);
-
-int hwclock_apply_localtime_delta(void);
-
-int hwclock_get_time(struct tm *tm);
-
-int hwclock_set_time(const struct tm *tm);
-
#endif
commit 5f4b19f4bc4b6e747ca19f53ef33a167ecf9ac0b
Author: Lennart Poettering <lennart at poettering.net>
Date: Wed Jun 15 15:34:19 2011 +0200
service: check whether sysv scripts where changed
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 9f71492..ffc2573 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -646,7 +646,7 @@
removed. If the list of capabilities
is prefixed with ~ all but the listed
capabilities will be included, the
- effect of this assignment
+ effect of the assignment
inverted. Note that this option does
not actually set or unset any
capabilities in the effective,
diff --git a/src/service.c b/src/service.c
index 62027f3..4ee7900 100644
--- a/src/service.c
+++ b/src/service.c
@@ -470,6 +470,7 @@ static int service_load_sysv_path(Service *s, const char *path) {
LSB_DESCRIPTION
} state = NORMAL;
char *short_description = NULL, *long_description = NULL, *chkconfig_description = NULL, *description;
+ struct stat st;
assert(s);
assert(path);
@@ -481,12 +482,26 @@ static int service_load_sysv_path(Service *s, const char *path) {
goto finish;
}
+ zero(st);
+ if (fstat(fileno(f), &st) < 0) {
+ r = -errno;
+ goto finish;
+ }
+
free(s->sysv_path);
if (!(s->sysv_path = strdup(path))) {
r = -ENOMEM;
goto finish;
}
+ s->sysv_mtime = timespec_load(&st.st_mtim);
+
+ if (null_or_empty(&st)) {
+ u->meta.load_state = UNIT_MASKED;
+ r = 0;
+ goto finish;
+ }
+
while (!feof(f)) {
char l[LINE_MAX], *t;
@@ -3212,6 +3227,29 @@ static void service_reset_failed(Unit *u) {
s->failure = false;
}
+static bool service_need_daemon_reload(Unit *u) {
+ Service *s = SERVICE(u);
+
+ assert(s);
+
+#ifdef HAVE_SYSV_COMPAT
+ if (s->sysv_path) {
+ struct stat st;
+
+ zero(st);
+ if (stat(s->sysv_path, &st) < 0)
+ /* What, cannot access this anymore? */
+ return true;
+
+ if (s->sysv_mtime > 0 &&
+ timespec_load(&st.st_mtim) != s->sysv_mtime)
+ return true;
+ }
+#endif
+
+ return false;
+}
+
static int service_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) {
Service *s = SERVICE(u);
int r = 0;
@@ -3361,6 +3399,8 @@ const UnitVTable service_vtable = {
.reset_failed = service_reset_failed,
+ .need_daemon_reload = service_need_daemon_reload,
+
.cgroup_notify_empty = service_cgroup_notify_event,
.notify_message = service_notify_message,
diff --git a/src/service.h b/src/service.h
index 55b9513..e28f74b 100644
--- a/src/service.h
+++ b/src/service.h
@@ -144,6 +144,7 @@ struct Service {
char *sysv_path;
char *sysv_runlevels;
+ usec_t sysv_mtime;
#endif
char *bus_name;
diff --git a/src/unit.c b/src/unit.c
index 057431c..87b7edf 100644
--- a/src/unit.c
+++ b/src/unit.c
@@ -2305,21 +2305,25 @@ void unit_status_printf(Unit *u, const char *format, ...) {
}
bool unit_need_daemon_reload(Unit *u) {
- struct stat st;
-
assert(u);
- if (!u->meta.fragment_path)
- return false;
+ if (u->meta.fragment_path) {
+ struct stat st;
- zero(st);
- if (stat(u->meta.fragment_path, &st) < 0)
- /* What, cannot access this anymore? */
- return true;
+ zero(st);
+ if (stat(u->meta.fragment_path, &st) < 0)
+ /* What, cannot access this anymore? */
+ return true;
- return
- u->meta.fragment_mtime &&
- timespec_load(&st.st_mtim) != u->meta.fragment_mtime;
+ if (u->meta.fragment_mtime > 0 &&
+ timespec_load(&st.st_mtim) != u->meta.fragment_mtime)
+ return true;
+ }
+
+ if (UNIT_VTABLE(u)->need_daemon_reload)
+ return UNIT_VTABLE(u)->need_daemon_reload(u);
+
+ return false;
}
void unit_reset_failed(Unit *u) {
diff --git a/src/unit.h b/src/unit.h
index 1c8cf63..79f1510 100644
--- a/src/unit.h
+++ b/src/unit.h
@@ -317,6 +317,9 @@ struct UnitVTable {
void (*sigchld_event)(Unit *u, pid_t pid, int code, int status);
void (*timer_event)(Unit *u, uint64_t n_elapsed, Watch *w);
+ /* Check whether unit needs a daemon reload */
+ bool (*need_daemon_reload)(Unit *u);
+
/* Reset failed state if we are in failed state */
void (*reset_failed)(Unit *u);
commit 8d0e38a2b966799af884e78a54fd6a2dffa44788
Author: Lennart Poettering <lennart at poettering.net>
Date: Wed Jun 15 15:31:54 2011 +0200
dbus: introduce UnsetAndSetEnvironment()
diff --git a/TODO b/TODO
index 8e43b38..71ad077 100644
--- a/TODO
+++ b/TODO
@@ -27,6 +27,10 @@ Features:
* kernel: add device_type = "fb", "fbcon" to class "graphics"
+* hostnamed: make file updates atomic
+
+* support sd_notify() style notificatio when reload is finished (RELOADED=1)
+
* verify that the AF_UNIX sockets of a service in the fs still exist
when we start a service in order to avoid confusion when a user
assumes starting a service is enough to make it accessible
@@ -46,8 +50,6 @@ Features:
* move /selinux to /sys/fs/selinux
-* unset cgroup agents on shutdown
-
* add prefix match to sysctl, tmpfiles, ...
* send out "finished" signal when we are finished booting
@@ -154,8 +156,6 @@ Features:
* Support --test based on current system state
-* systemctl enable as D-Bus call
-
* consider services with any kind of link in /etc/systemd/system enabled
* show failure error string in "systemctl status"
diff --git a/src/dbus-common.c b/src/dbus-common.c
index cb43bbd..e439a42 100644
--- a/src/dbus-common.c
+++ b/src/dbus-common.c
@@ -737,3 +737,62 @@ unsigned bus_events_to_flags(uint32_t events) {
return flags;
}
+
+int bus_parse_strv(DBusMessage *m, char ***_l) {
+ DBusMessageIter iter;
+
+ assert(m);
+ assert(_l);
+
+ if (!dbus_message_iter_init(m, &iter))
+ return -EINVAL;
+
+ return bus_parse_strv_iter(&iter, _l);
+}
+
+int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) {
+ DBusMessageIter sub;
+ unsigned n = 0, i = 0;
+ char **l;
+
+ assert(iter);
+ assert(_l);
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRING)
+ return -EINVAL;
+
+ dbus_message_iter_recurse(iter, &sub);
+
+ while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+ n++;
+ dbus_message_iter_next(&sub);
+ }
+
+ if (!(l = new(char*, n+1)))
+ return -ENOMEM;
+
+ dbus_message_iter_recurse(iter, &sub);
+
+ while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+ const char *s;
+
+ assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
+ dbus_message_iter_get_basic(&sub, &s);
+
+ if (!(l[i++] = strdup(s))) {
+ strv_free(l);
+ return -ENOMEM;
+ }
+
+ dbus_message_iter_next(&sub);
+ }
+
+ assert(i == n);
+ l[i] = NULL;
+
+ if (_l)
+ *_l = l;
+
+ return 0;
+}
diff --git a/src/dbus-common.h b/src/dbus-common.h
index e321a2c..9368f75 100644
--- a/src/dbus-common.h
+++ b/src/dbus-common.h
@@ -158,4 +158,7 @@ DBusMessage* bus_properties_changed_new(const char *path, const char *interface,
uint32_t bus_flags_to_events(DBusWatch *bus_watch);
unsigned bus_events_to_flags(uint32_t events);
+int bus_parse_strv(DBusMessage *m, char ***_l);
+int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l);
+
#endif
diff --git a/src/dbus-manager.c b/src/dbus-manager.c
index 797e53d..cc2b4d0 100644
--- a/src/dbus-manager.c
+++ b/src/dbus-manager.c
@@ -128,6 +128,10 @@
" </method>\n" \
" <method name=\"UnsetEnvironment\">\n" \
" <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
+ " </method>\n" \
+ " <method name=\"UnsetAndSetEnvironment\">\n" \
+ " <arg name=\"unset\" type=\"as\" direction=\"in\"/>\n" \
+ " <arg name=\"set\" type=\"as\" direction=\"in\"/>\n" \
" </method>\n"
#define BUS_MANAGER_INTERFACE_SIGNALS \
@@ -1035,6 +1039,58 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
strv_free(m->environment);
m->environment = e;
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
+ char **l_set = NULL, **l_unset = NULL, **e = NULL, **f = NULL;
+ DBusMessageIter iter;
+
+ if (!dbus_message_iter_init(message, &iter))
+ return bus_send_error_reply(connection, message, NULL, -EINVAL);
+
+ r = bus_parse_strv_iter(&iter, &l_unset);
+ if (r < 0) {
+ if (r == -ENOMEM)
+ goto oom;
+
+ return bus_send_error_reply(connection, message, NULL, r);
+ }
+
+ if (!dbus_message_iter_next(&iter)) {
+ strv_free(l_unset);
+ return bus_send_error_reply(connection, message, NULL, -EINVAL);
+ }
+
+ r = bus_parse_strv_iter(&iter, &l_set);
+ if (r < 0) {
+ strv_free(l_unset);
+ if (r == -ENOMEM)
+ goto oom;
+
+ return bus_send_error_reply(connection, message, NULL, r);
+ }
+
+ e = strv_env_delete(m->environment, 1, l_unset);
+ strv_free(l_unset);
+
+ if (!e) {
+ strv_free(l_set);
+ goto oom;
+ }
+
+ f = strv_env_merge(2, e, l_set);
+ strv_free(l_set);
+ strv_free(e);
+
+ if (!f)
+ goto oom;
+
+ if (!(reply = dbus_message_new_method_return(message))) {
+ strv_free(f);
+ goto oom;
+ }
+
+ strv_free(m->environment);
+ m->environment = f;
+
} else
return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, properties);
diff --git a/src/dbus.c b/src/dbus.c
index e153c35..2a379a2 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -1212,55 +1212,6 @@ int bus_broadcast(Manager *m, DBusMessage *message) {
return oom ? -ENOMEM : 0;
}
-int bus_parse_strv(DBusMessage *m, char ***_l) {
- DBusMessageIter iter, sub;
- unsigned n = 0, i = 0;
- char **l;
-
- assert(m);
- assert(_l);
-
- if (!dbus_message_iter_init(m, &iter) ||
- dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
- dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
- return -EINVAL;
-
- dbus_message_iter_recurse(&iter, &sub);
-
- while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
- n++;
- dbus_message_iter_next(&sub);
- }
-
- if (!(l = new(char*, n+1)))
- return -ENOMEM;
-
- assert_se(dbus_message_iter_init(m, &iter));
- dbus_message_iter_recurse(&iter, &sub);
-
- while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
- const char *s;
-
- assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
- dbus_message_iter_get_basic(&sub, &s);
-
- if (!(l[i++] = strdup(s))) {
- strv_free(l);
- return -ENOMEM;
- }
-
- dbus_message_iter_next(&sub);
- }
-
- assert(i == n);
- l[i] = NULL;
-
- if (_l)
- *_l = l;
-
- return 0;
-}
-
bool bus_has_subscriber(Manager *m) {
Iterator i;
DBusConnection *c;
diff --git a/src/dbus.h b/src/dbus.h
index 8387ffa..c47e782 100644
--- a/src/dbus.h
+++ b/src/dbus.h
@@ -38,8 +38,6 @@ int bus_query_pid(Manager *m, const char *name);
int bus_broadcast(Manager *m, DBusMessage *message);
-int bus_parse_strv(DBusMessage *m, char ***_l);
-
bool bus_has_subscriber(Manager *m);
bool bus_connection_has_subscriber(Manager *m, DBusConnection *c);
diff --git a/src/service.c b/src/service.c
index 1f74868..62027f3 100644
--- a/src/service.c
+++ b/src/service.c
@@ -280,10 +280,10 @@ static int sysv_translate_facility(const char *name, const char *filename, char
/* LSB defined facilities */
"local_fs", SPECIAL_LOCAL_FS_TARGET,
#ifndef TARGET_MANDRIVA
- /* Due to unfortunate name selection in Mandriva,
- * $network is provided by network-up which is ordered
- * after network which actually starts interfaces.
- * To break the loop, just ignore it */
+ /* Due to unfortunate name selection in Mandriva,
+ * $network is provided by network-up which is ordered
+ * after network which actually starts interfaces.
+ * To break the loop, just ignore it */
"network", SPECIAL_NETWORK_TARGET,
#endif
"named", SPECIAL_NSS_LOOKUP_TARGET,
diff --git a/src/util.c b/src/util.c
index b291e2f..81d247c 100644
--- a/src/util.c
+++ b/src/util.c
@@ -4692,6 +4692,7 @@ int conf_files_list(char ***strv, const char *suffix, const char *dir, ...) {
}
qsort(files, hashmap_size(fh), sizeof(char *), base_cmp);
+
finish:
strv_free(dirs);
hashmap_free(fh);
commit 48f82119ce55caa7671598fb1bd90df4eb00d150
Author: Lennart Poettering <lennart at poettering.net>
Date: Wed Jun 15 10:16:09 2011 +0200
util: return errno in close_nointr()
diff --git a/src/util.c b/src/util.c
index 156d32a..b291e2f 100644
--- a/src/util.c
+++ b/src/util.c
@@ -230,11 +230,12 @@ int close_nointr(int fd) {
for (;;) {
int r;
- if ((r = close(fd)) >= 0)
+ r = close(fd);
+ if (r >= 0)
return r;
if (errno != EINTR)
- return r;
+ return -errno;
}
}
commit 3f49d45a45c6c585098590174c3245d2d9bdde0a
Author: Lennart Poettering <lennart at poettering.net>
Date: Thu May 26 02:21:16 2011 +0200
logind: implement D-Bus properties
diff --git a/Makefile.am b/Makefile.am
index f455f21..0bc5169 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -810,10 +810,14 @@ systemd_hostnamed_LDADD = \
systemd_logind_SOURCES = \
src/logind.c \
+ src/logind-dbus.c \
src/logind-device.c \
src/logind-seat.c \
+ src/logind-seat-dbus.c \
src/logind-session.c \
+ src/logind-session-dbus.c \
src/logind-user.c \
+ src/logind-user-dbus.c \
src/logind-acl.c \
src/dbus-common.c \
src/dbus-loop.c \
diff --git a/src/70-uaccess.rules b/src/70-uaccess.rules
new file mode 100644
index 0000000..6932492
--- /dev/null
+++ b/src/70-uaccess.rules
@@ -0,0 +1,72 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+ACTION=="remove", GOTO="uaccess_end"
+ENV{MAJOR}=="", GOTO="uaccess_end"
+
+# PTP/MTP protocol devices, cameras, portable media players
+SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="", ENV{DEVTYPE}=="usb_device", IMPORT{program}="usb_id --export %p"
+SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="*:060101:*", TAG+="uaccess"
+
+# Digicams with proprietary protocol
+ENV{ID_GPHOTO2}=="*?", TAG+="uaccess"
+
+# SCSI and USB scanners
+ENV{libsane_matched}=="yes", TAG+="uaccess"
+
+# HPLIP devices (necessary for ink level check and HP tool maintenance)
+ENV{ID_HPLIP}=="1", TAG+="uaccess"
+
+# optical drives
+SUBSYSTEM=="block", ENV{ID_CDROM}=="1", TAG+="uaccess"
+SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="4|5", TAG+="uaccess"
+
+# Sound devices
+SUBSYSTEM=="sound", TAG+="uaccess"
+
+# ffado is an userspace driver for firewire sound cards
+SUBSYSTEM=="firewire", ENV{ID_FFADO}=="1", TAG+="uaccess"
+
+# Webcams, frame grabber, TV cards
+SUBSYSTEM=="video4linux", TAG+="uaccess"
+SUBSYSTEM=="dvb", TAG+="uaccess"
+
+# IIDC devices: industrial cameras and some webcams
+SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x00010*", TAG+="uaccess"
+SUBSYSTEM=="firewire", ATTR{units}=="*0x00b09d:0x00010*", TAG+="uaccess"
+# AV/C devices: camcorders, set-top boxes, TV sets, audio devices, and more
+SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x010001*", TAG+="uaccess"
+SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", TAG+="uaccess"
+
+# DRI video devices
+SUBSYSTEM=="drm", KERNEL=="card*", TAG+="uaccess"
+
+# KVM
+SUBSYSTEM=="misc", KERNEL=="kvm", TAG+="uaccess"
+
+# smart-card readers
+ENV{ID_SMARTCARD_READER}=="*?", TAG+="uaccess"
+
+# PDA devices
+ENV{ID_PDA}=="*?", TAG+="uaccess"
+
+# Programmable remote control
+ENV{ID_REMOTE_CONTROL}=="1", TAG+="uaccess"
+
+# joysticks
+SUBSYSTEM=="input", ENV{ID_INPUT_JOYSTICK}=="?*", TAG+="uaccess"
+
+# color measurement devices
+ENV{COLOR_MEASUREMENT_DEVICE}=="*?", TAG+="uaccess"
+
+# DDC/CI device, usually high-end monitors such as the DreamColor
+ENV{DDC_DEVICE}=="*?", TAG+="uaccess"
+
+# media player raw devices (for user-mode drivers, Android SDK, etc.)
+SUBSYSTEM=="usb", ENV{ID_MEDIA_PLAYER}=="?*", TAG+="uaccess"
+
+LABEL="uaccess_end"
diff --git a/src/71-seat.rules b/src/71-seat.rules
new file mode 100644
index 0000000..3969837
--- /dev/null
+++ b/src/71-seat.rules
@@ -0,0 +1,20 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+ACTION=="remove", GOTO="seat_end"
+
+TAG=="uaccess", TAG+="seat"
+SUBSYSTEM=="input", TAG+="seat"
+SUBSYSTEM=="graphics", KERNEL=="fb[0-9]*", TAG+="seat"
+SUBSYSTEM=="usb", ATTR{bDeviceClass}=="09", TAG+="seat"
+SUBSYSTEM=="usb", ATTR{idVendor}=="2230", ATTR{idProduct}=="0001", ENV{ID_AUTOSEAT}="1"
+
+IMPORT{parent}="ID_SEAT"
+ENV{ID_AUTOSEAT}=="1", ENV{ID_SEAT}=="", ENV{ID_SEAT}="seat-foo"
+ENV{ID_SEAT}!="", TAG+="seat-foo"
+
+LABEL="seat_end"
diff --git a/src/logind-dbus.c b/src/logind-dbus.c
new file mode 100644
index 0000000..90db941
--- /dev/null
+++ b/src/logind-dbus.c
@@ -0,0 +1,235 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "logind.h"
+#include "dbus-common.h"
+
+#define BUS_MANAGER_INTERFACE \
+ " <interface name=\"org.freedesktop.login1.Manager\">\n" \
+ " <method name=\"GetSeat\">\n" \
+ " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " <method name=\"GetUser\">\n" \
+ " <arg name=\"uid\" type=\"t\" direction=\"in\"/>\n" \
+ " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " <method name=\"GetSession\">\n" \
+ " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " <method name=\"ListSeats\">\n" \
+ " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " <method name=\"ListUsers\">\n" \
+ " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " <method name=\"ListSessions\">\n" \
+ " <arg name=\"users\" type=\"a(sussso)\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " <method name=\"CreateSession\">\n" \
+ " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
+ " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
+ " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
+ " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
+ " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
+ " <arg name=\"kill_processes\" type=\"as\" direction=\"in\"/>\n" \
+ " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
+ " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
+ " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " <method name=\"TerminateSession\">\n" \
+ " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
+ " </method>\n" \
+ " <method name=\"TerminateUser\">\n" \
+ " <arg name=\"uid\" type=\"t\" direction=\"in\"/>\n" \
+ " </method>\n" \
+ " <method name=\"TerminateSeat\">\n" \
+ " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
+ " </method>\n" \
+ " <signal name=\"SessionNew\">\n" \
+ " <arg name=\"id\" type=\"s\"/>\n" \
+ " <arg name=\"path\" type=\"o\"/>\n" \
+ " </signal>\n" \
+ " <signal name=\"SessionRemoved\">\n" \
+ " <arg name=\"id\" type=\"s\"/>\n" \
+ " <arg name=\"path\" type=\"o\"/>\n" \
+ " </signal>\n" \
+ " <signal name=\"UserNew\">\n" \
+ " <arg name=\"uid\" type=\"u\"/>\n" \
+ " <arg name=\"path\" type=\"o\"/>\n" \
+ " </signal>\n" \
+ " <signal name=\"UserRemoved\">\n" \
+ " <arg name=\"uid\" type=\"u\"/>\n" \
+ " <arg name=\"path\" type=\"o\"/>\n" \
+ " </signal>\n" \
+ " <signal name=\"SeatNew\">\n" \
+ " <arg name=\"id\" type=\"s\"/>\n" \
+ " <arg name=\"path\" type=\"o\"/>\n" \
+ " </signal>\n" \
+ " <signal name=\"SeatRemoved\">\n" \
+ " <arg name=\"id\" type=\"s\"/>\n" \
+ " <arg name=\"path\" type=\"o\"/>\n" \
+ " </signal>\n" \
+ " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
+ " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
+ " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
+ " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
+ " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
+ " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
+ " </interface>\n"
+
+#define INTROSPECTION_BEGIN \
+ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
+ "<node>\n" \
+ BUS_MANAGER_INTERFACE \
+ BUS_PROPERTIES_INTERFACE \
+ BUS_PEER_INTERFACE \
+ BUS_INTROSPECTABLE_INTERFACE
+
+#define INTROSPECTION_END \
+ "</node>\n"
+
+#define INTERFACES_LIST \
+ BUS_GENERIC_INTERFACES_LIST \
+ "org.freedesktop.login1.Manager\0"
+
+static DBusHandlerResult manager_message_handler(
+ DBusConnection *connection,
+ DBusMessage *message,
+ void *userdata) {
+
+ Manager *m = userdata;
+
+ const BusProperty properties[] = {
+ { "org.freedesktop.login1.Manager", "ControlGroupHierarchy", bus_property_append_string, "s", m->cgroup_path },
+ { "org.freedesktop.login1.Manager", "Controllers", bus_property_append_strv, "as", m->controllers },
+ { "org.freedesktop.login1.Manager", "ResetControllers", bus_property_append_strv, "as", m->reset_controllers },
+ { "org.freedesktop.login1.Manager", "NAutoVTs", bus_property_append_unsigned, "u", &m->n_autovts },
+ { "org.freedesktop.login1.Manager", "KillOnlyUsers", bus_property_append_strv, "as", m->kill_only_users },
+ { "org.freedesktop.login1.Manager", "KillExcludeUsers", bus_property_append_strv, "as", m->kill_exclude_users },
+ { "org.freedesktop.login1.Manager", "KillUserProcesses", bus_property_append_bool, "b", &m->kill_user_processes },
+ { NULL, NULL, NULL, NULL, NULL }
+ };
+
+ DBusError error;
+ DBusMessage *reply = NULL;
+
+ assert(connection);
+ assert(message);
+ assert(m);
+
+ dbus_error_init(&error);
+
+ if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
+ char *introspection = NULL;
+ FILE *f;
+ Iterator i;
+ Session *session;
+ Seat *seat;
+ User *user;
+ size_t size;
+ char *p;
+
+ if (!(reply = dbus_message_new_method_return(message)))
+ goto oom;
+
+ /* We roll our own introspection code here, instead of
+ * relying on bus_default_message_handler() because we
+ * need to generate our introspection string
+ * dynamically. */
+
+ if (!(f = open_memstream(&introspection, &size)))
+ goto oom;
+
+ fputs(INTROSPECTION_BEGIN, f);
+
+ HASHMAP_FOREACH(seat, m->seats, i) {
+ p = bus_path_escape(seat->id);
+
+ if (p) {
+ fprintf(f, "<node name=\"seat/%s\"/>", p);
+ free(p);
+ }
+ }
+
+ HASHMAP_FOREACH(user, m->users, i)
+ fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
+
+ HASHMAP_FOREACH(session, m->sessions, i) {
+ p = bus_path_escape(session->id);
+
+ if (p) {
+ fprintf(f, "<node name=\"session/%s\"/>", p);
+ free(p);
+ }
+ }
+
+ fputs(INTROSPECTION_END, f);
+
+ if (ferror(f)) {
+ fclose(f);
+ free(introspection);
+ goto oom;
+ }
+
+ fclose(f);
+
+ if (!introspection)
+ goto oom;
+
+ if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
+ free(introspection);
+ goto oom;
+ }
+
+ free(introspection);
+ } else
+ return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, properties);
+
+ if (reply) {
+ if (!dbus_connection_send(connection, reply, NULL))
+ goto oom;
+
+ dbus_message_unref(reply);
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+
+oom:
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+}
+
+const DBusObjectPathVTable bus_manager_vtable = {
+ .message_function = manager_message_handler
+};
diff --git a/src/logind-device.c b/src/logind-device.c
index 4e076c2..31afa4f 100644
--- a/src/logind-device.c
+++ b/src/logind-device.c
@@ -80,6 +80,6 @@ void device_attach(Device *d, Seat *s) {
if (d->seat)
device_detach(d);
- LIST_PREPEND(Device, devices, d->seat->devices, d);
d->seat = s;
+ LIST_PREPEND(Device, devices, s->devices, d);
}
diff --git a/src/logind-seat-dbus.c b/src/logind-seat-dbus.c
new file mode 100644
index 0000000..63b1bd5
--- /dev/null
+++ b/src/logind-seat-dbus.c
@@ -0,0 +1,218 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "logind.h"
+#include "logind-seat.h"
+#include "dbus-common.h"
+#include "util.h"
+
+#define BUS_SEAT_INTERFACE \
+ " <interface name=\"org.freedesktop.login1.Seat\">\n" \
+ " <method name=\"Terminate\"/>\n" \
+ " <property name=\"Id\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Active\" type=\"so\" access=\"read\"/>\n" \
+ " <property name=\"Sessions\" type=\"a(so)\" access=\"read\"/>\n" \
+ " </interface>\n" \
+
+#define INTROSPECTION \
+ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
+ "<node>\n" \
+ BUS_SEAT_INTERFACE \
+ BUS_PROPERTIES_INTERFACE \
+ BUS_PEER_INTERFACE \
+ BUS_INTROSPECTABLE_INTERFACE \
+ "</node>\n"
+
+#define INTERFACES_LIST \
+ BUS_GENERIC_INTERFACES_LIST \
+ "org.freedesktop.login1.Seat\0"
+
+static int bus_seat_append_active(DBusMessageIter *i, const char *property, void *data) {
+ DBusMessageIter sub;
+ Seat *s = data;
+ const char *id, *path;
+ char *p = NULL;
+
+ assert(i);
+ assert(property);
+ assert(s);
+
+ if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
+ return -ENOMEM;
+
+ if (s->active) {
+ id = s->active->id;
+ path = p = session_bus_path(s->active);
+
+ if (!p)
+ return -ENOMEM;
+ } else {
+ id = "";
+ path = "/";
+ }
+
+ if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
+ !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) {
+ free(p);
+ return -ENOMEM;
+ }
+
+ free(p);
+
+ if (!dbus_message_iter_close_container(i, &sub))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int bus_seat_append_sessions(DBusMessageIter *i, const char *property, void *data) {
+ DBusMessageIter sub, sub2;
+ Seat *s = data;
+ Session *session;
+
+ assert(i);
+ assert(property);
+ assert(s);
+
+ if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "so", &sub))
+ return -ENOMEM;
+
+ LIST_FOREACH(sessions_by_seat, session, s->sessions) {
+ char *p;
+
+ if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
+ return -ENOMEM;
+
+ p = session_bus_path(session);
+ if (!p)
+ return -ENOMEM;
+
+ if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
+ !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
+ free(p);
+ return -ENOMEM;
+ }
+
+ free(p);
+
+ if (!dbus_message_iter_close_container(&sub, &sub2))
+ return -ENOMEM;
+ }
+
+ if (!dbus_message_iter_close_container(i, &sub))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int get_seat_for_path(Manager *m, const char *path, Seat **_s) {
+ Seat *s;
+ char *id;
+
+ assert(m);
+ assert(path);
+ assert(_s);
+
+ if (!startswith(path, "/org/freedesktop/login1/seat/"))
+ return -EINVAL;
+
+ id = bus_path_unescape(path + 29);
+ if (!id)
+ return -ENOMEM;
+
+ s = hashmap_get(m->seats, id);
+ free(id);
+
+ if (!s)
+ return -ENOENT;
+
+ *_s = s;
+ return 0;
+}
+
+static DBusHandlerResult seat_message_dispatch(
+ Seat *s,
+ DBusConnection *connection,
+ DBusMessage *message) {
+
+ const BusProperty properties[] = {
+ { "org.freedesktop.login1.Seat", "Id", bus_property_append_string, "s", s->id },
+ { "org.freedesktop.login1.Seat", "Active", bus_seat_append_active, "(so)", s },
+ { "org.freedesktop.login1.Seat", "Sessions", bus_seat_append_sessions, "a(so)", s },
+ { NULL, NULL, NULL, NULL, NULL }
+ };
+
+ assert(s);
+ assert(connection);
+ assert(message);
+
+ return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+}
+
+static DBusHandlerResult seat_message_handler(
+ DBusConnection *connection,
+ DBusMessage *message,
+ void *userdata) {
+
+ Manager *m = userdata;
+ Seat *s;
+ int r;
+
+ r = get_seat_for_path(m, dbus_message_get_path(message), &s);
+ if (r < 0) {
+
+ if (r == -ENOMEM)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ if (r == -ENOENT) {
+ DBusError e;
+
+ dbus_error_init(&e);
+ dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown seat");
+ return bus_send_error_reply(connection, message, &e, r);
+ }
+
+ return bus_send_error_reply(connection, message, NULL, r);
+ }
+
+ return seat_message_dispatch(s, connection, message);
+}
+
+const DBusObjectPathVTable bus_seat_vtable = {
+ .message_function = seat_message_handler
+};
+
+char *seat_bus_path(Seat *s) {
+ char *t, *r;
+
+ assert(s);
+
+ t = bus_path_escape(s->id);
+ if (!t)
+ return NULL;
+
+ r = strappend("/org/freedesktop/login1/seat/", t);
+ free(t);
+
+ return r;
+}
diff --git a/src/logind-seat.c b/src/logind-seat.c
index ae89ec9..2ba3060 100644
--- a/src/logind-seat.c
+++ b/src/logind-seat.c
@@ -182,7 +182,8 @@ static int vt_allocate(int vtnr) {
}
static int seat_preallocate_vts(Seat *s) {
- int i, r = 0;
+ int r = 0;
+ unsigned i;
assert(s);
assert(s->manager);
@@ -295,6 +296,11 @@ int seat_read_active_vt(Seat *s) {
int seat_start(Seat *s) {
assert(s);
+ if (s->started)
+ return 0;
+
+ log_info("New seat %s.", s->id);
+
/* Initialize VT magic stuff */
seat_preallocate_vts(s);
@@ -304,6 +310,8 @@ int seat_start(Seat *s) {
/* Save seat data */
seat_save(s);
+ s->started = true;
+
return 0;
}
@@ -313,6 +321,11 @@ int seat_stop(Seat *s) {
assert(s);
+ if (!s->started)
+ return 0;
+
+ log_info("Removed seat %s.", s->id);
+
LIST_FOREACH(sessions_by_seat, session, s->sessions) {
k = session_stop(session);
if (k < 0)
@@ -322,6 +335,8 @@ int seat_stop(Seat *s) {
unlink(s->state_file);
seat_add_to_gc_queue(s);
+ s->started = false;
+
return r;
}
@@ -343,3 +358,30 @@ void seat_add_to_gc_queue(Seat *s) {
LIST_PREPEND(Seat, gc_queue, s->manager->seat_gc_queue, s);
s->in_gc_queue = true;
}
+
+static bool seat_name_valid_char(char c) {
+ return
+ (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') ||
+ c == '-' ||
+ c == '_';
+}
+
+bool seat_name_is_valid(const char *name) {
+ const char *p;
+
+ assert(name);
+
+ if (!startswith(name, "seat"))
+ return false;
+
+ if (!name[4])
+ return false;
+
+ for (p = name; *p; p++)
+ if (!seat_name_valid_char(*p))
+ return false;
+
+ return true;
+}
diff --git a/src/logind-seat.h b/src/logind-seat.h
index b1a8d61..b045bde 100644
--- a/src/logind-seat.h
+++ b/src/logind-seat.h
@@ -42,6 +42,7 @@ struct Seat {
LIST_HEAD(Session, sessions);
bool in_gc_queue:1;
+ bool started:1;
LIST_FIELDS(Seat, gc_queue);
};
@@ -62,4 +63,9 @@ int seat_stop(Seat *s);
int seat_check_gc(Seat *s);
void seat_add_to_gc_queue(Seat *s);
+bool seat_name_is_valid(const char *name);
+char *seat_bus_path(Seat *s);
+
+extern const DBusObjectPathVTable bus_seat_vtable;
+
#endif
diff --git a/src/logind-session-dbus.c b/src/logind-session-dbus.c
new file mode 100644
index 0000000..41af658
--- /dev/null
+++ b/src/logind-session-dbus.c
@@ -0,0 +1,256 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "logind.h"
+#include "logind-session.h"
+#include "dbus-common.h"
+#include "util.h"
+
+#define BUS_SESSION_INTERFACE \
+ " <interface name=\"org.freedesktop.login1.Session\">\n" \
+ " <method name=\"Terminate\"/>\n" \
+ " <method name=\"Activate\"/>\n" \
+ " <property name=\"Id\" type=\"u\" access=\"read\"/>\n" \
+ " <property name=\"User\" type=\"(uo)\" access=\"read\"/>\n" \
+ " <property name=\"Name\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"ControlGroupPath\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"VTNr\" type=\"u\" access=\"read\"/>\n" \
+ " <property name=\"Seat\" type=\"(so)\" access=\"read\"/>\n" \
+ " <property name=\"TTY\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Display\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Remote\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"RemoteHost\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"RemoteUser\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Leader\" type=\"u\" access=\"read\"/>\n" \
+ " <property name=\"Audit\" type=\"u\" access=\"read\"/>\n" \
+ " <property name=\"Type\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Active\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
+ " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
+ " <property name=\"KillProcesses\" type=\"b\" access=\"read\"/>\n" \
+ " </interface>\n"
+
+#define INTROSPECTION \
+ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
+ "<node>\n" \
+ BUS_SESSION_INTERFACE \
+ BUS_PROPERTIES_INTERFACE \
+ BUS_PEER_INTERFACE \
+ BUS_INTROSPECTABLE_INTERFACE \
+ "</node>\n"
+
+#define INTERFACES_LIST \
+ BUS_GENERIC_INTERFACES_LIST \
+ "org.freedesktop.login1.Session\0"
+
+static int bus_session_append_seat(DBusMessageIter *i, const char *property, void *data) {
+ DBusMessageIter sub;
+ Session *s = data;
+ const char *id, *path;
+ char *p = NULL;
+
+ assert(i);
+ assert(property);
+ assert(s);
+
+ if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
+ return -ENOMEM;
+
+ if (s->seat) {
+ id = s->seat->id;
+ path = p = seat_bus_path(s->seat);
+
+ if (!p)
+ return -ENOMEM;
+ } else {
+ id = "";
+ path = "/";
+ }
+
+ if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
+ !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) {
+ free(p);
+ return -ENOMEM;
+ }
+
+ free(p);
+
+ if (!dbus_message_iter_close_container(i, &sub))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int bus_session_append_user(DBusMessageIter *i, const char *property, void *data) {
+ DBusMessageIter sub;
+ Session *s = data;
+ char *p = NULL;
+
+ assert(i);
+ assert(property);
+ assert(s);
+
+ if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
+ return -ENOMEM;
+
+ p = user_bus_path(s->user);
+ if (!p)
+ return -ENOMEM;
+
+ if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &s->user->uid) ||
+ !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
+ free(p);
+ return -ENOMEM;
+ }
+
+ free(p);
+
+ if (!dbus_message_iter_close_container(i, &sub))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int bus_session_append_active(DBusMessageIter *i, const char *property, void *data) {
+ Session *s = data;
+ bool b;
+
+ assert(i);
+ assert(property);
+ assert(s);
+
+ b = session_is_active(s);
+ if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_type, session_type, SessionType);
+
+static int get_session_for_path(Manager *m, const char *path, Session **_s) {
+ Session *s;
+ char *id;
+
+ assert(m);
+ assert(path);
+ assert(_s);
+
+ if (!startswith(path, "/org/freedesktop/login1/session/"))
+ return -EINVAL;
+
+ id = bus_path_unescape(path + 32);
+ if (!id)
+ return -ENOMEM;
+
+ s = hashmap_get(m->sessions, id);
+ free(id);
+
+ if (!s)
+ return -ENOENT;
+
+ *_s = s;
+ return 0;
+}
+
+static DBusHandlerResult session_message_dispatch(
+ Session *s,
+ DBusConnection *connection,
+ DBusMessage *message) {
+
+ const BusProperty properties[] = {
+ { "org.freedesktop.login1.Session", "Id", bus_property_append_string, "s", s->id },
+ { "org.freedesktop.login1.Session", "User", bus_session_append_user, "(uo)", s },
+ { "org.freedesktop.login1.Session", "Name", bus_property_append_string, "s", s->user->name },
+ { "org.freedesktop.login1.Session", "ControlGroupPath", bus_property_append_string, "s", s->cgroup_path },
+ { "org.freedesktop.login1.Session", "VTNr", bus_property_append_uint32, "u", &s->vtnr },
+ { "org.freedesktop.login1.Session", "Seat", bus_session_append_seat, "(so)", s },
+ { "org.freedesktop.login1.Session", "TTY", bus_property_append_string, "s", s->tty },
+ { "org.freedesktop.login1.Session", "Display", bus_property_append_string, "s", s->display },
+ { "org.freedesktop.login1.Session", "Remote", bus_property_append_bool, "b", &s->remote },
+ { "org.freedesktop.login1.Session", "RemoteUser", bus_property_append_string, "s", s->remote_user },
+ { "org.freedesktop.login1.Session", "RemoteHost", bus_property_append_string, "s", s->remote_host },
+ { "org.freedesktop.login1.Session", "Leader", bus_property_append_pid, "u", &s->leader },
+ { "org.freedesktop.login1.Session", "Audit", bus_property_append_uint32, "u", &s->audit_id },
+ { "org.freedesktop.login1.Session", "Type", bus_session_append_type, "s", &s->type },
+ { "org.freedesktop.login1.Session", "Active", bus_session_append_active, "b", s },
+ { "org.freedesktop.login1.Session", "Controllers", bus_property_append_strv, "as", s->controllers },
+ { "org.freedesktop.login1.Session", "ResetControllers", bus_property_append_strv, "as", s->reset_controllers },
+ { "org.freedesktop.login1.Session", "KillProcesses", bus_property_append_bool, "b", &s->kill_processes },
+ { NULL, NULL, NULL, NULL, NULL }
+ };
+
+ assert(s);
+ assert(connection);
+ assert(message);
+
+ return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+}
+
+static DBusHandlerResult session_message_handler(
+ DBusConnection *connection,
+ DBusMessage *message,
+ void *userdata) {
+
+ Manager *m = userdata;
+ Session *s;
+ int r;
+
+ r = get_session_for_path(m, dbus_message_get_path(message), &s);
+ if (r < 0) {
+
+ if (r == -ENOMEM)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ if (r == -ENOENT) {
+ DBusError e;
+
+ dbus_error_init(&e);
+ dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown session");
+ return bus_send_error_reply(connection, message, &e, r);
+ }
+
+ return bus_send_error_reply(connection, message, NULL, r);
+ }
+
+ return session_message_dispatch(s, connection, message);
+}
+
+const DBusObjectPathVTable bus_session_vtable = {
+ .message_function = session_message_handler
+};
+
+char *session_bus_path(Session *s) {
+ char *t, *r;
+
+ assert(s);
+
+ t = bus_path_escape(s->id);
+ if (!t)
+ return NULL;
+
+ r = strappend("/org/freedesktop/login1/session/", t);
+ free(t);
+
+ return r;
+}
diff --git a/src/logind-session.c b/src/logind-session.c
index 8f1280d..6b3b277 100644
--- a/src/logind-session.c
+++ b/src/logind-session.c
@@ -83,6 +83,7 @@ void session_free(Session *s) {
free(s->tty);
free(s->display);
free(s->remote_host);
+ free(s->remote_user);
hashmap_remove(s->manager->sessions, s->id);
@@ -147,6 +148,11 @@ int session_save(Session *s) {
"REMOTE_HOST=%s\n",
s->remote_host);
+ if (s->remote_user)
+ fprintf(f,
+ "REMOTE_USER=%s\n",
+ s->remote_user);
+
if (s->seat && s->seat->manager->vtconsole == s->seat)
fprintf(f,
"VTNR=%i\n",
@@ -495,7 +501,7 @@ void session_add_to_gc_queue(Session *s) {
}
static const char* const session_type_table[_SESSION_TYPE_MAX] = {
- [SESSION_TERMINAL] = "terminal",
+ [SESSION_TTY] = "tty",
[SESSION_X11] = "x11"
};
diff --git a/src/logind-session.h b/src/logind-session.h
index 4c6e768..60ac1c5 100644
--- a/src/logind-session.h
+++ b/src/logind-session.h
@@ -31,7 +31,7 @@ typedef struct Session Session;
#include "logind-user.h"
typedef enum SessionType {
- SESSION_TERMINAL,
+ SESSION_TTY,
SESSION_X11,
_SESSION_TYPE_MAX,
_SESSION_TYPE_INVALID = -1
@@ -53,20 +53,21 @@ struct Session {
char *display;
bool remote;
+ char *remote_user;
char *remote_host;
int vtnr;
Seat *seat;
pid_t leader;
- uint64_t audit_id;
+ uint32_t audit_id;
int pipe_fd;
char *cgroup_path;
char **controllers, **reset_controllers;
- bool kill_processes:1;
+ bool kill_processes;
bool in_gc_queue:1;
LIST_FIELDS(Session, sessions_by_user);
@@ -86,6 +87,10 @@ int session_stop(Session *s);
int session_save(Session *s);
int session_load(Session *s);
+char *session_bus_path(Session *s);
+
+extern const DBusObjectPathVTable bus_session_vtable;
+
const char* session_type_to_string(SessionType t);
SessionType session_type_from_string(const char *s);
diff --git a/src/logind-user-dbus.c b/src/logind-user-dbus.c
new file mode 100644
index 0000000..7c8bb27
--- /dev/null
+++ b/src/logind-user-dbus.c
@@ -0,0 +1,240 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "logind.h"
+#include "logind-user.h"
+#include "dbus-common.h"
+
+#define BUS_USER_INTERFACE \
+ " <interface name=\"org.freedesktop.login1.User\">\n" \
+ " <method name=\"Terminate\"/>\n" \
+ " <property name=\"UID\" type=\"u\" access=\"read\"/>\n" \
+ " <property name=\"GID\" type=\"u\" access=\"read\"/>\n" \
+ " <property name=\"Name\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"RuntimePath\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Service\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"ControlGroupPath\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Display\" type=\"(so)\" access=\"read\"/>\n" \
+ " <property name=\"State\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Sessions\" type=\"a(so)\" access=\"read\"/>\n" \
+ " </interface>\n" \
+
+#define INTROSPECTION \
+ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
+ "<node>\n" \
+ BUS_USER_INTERFACE \
+ BUS_PROPERTIES_INTERFACE \
+ BUS_PEER_INTERFACE \
+ BUS_INTROSPECTABLE_INTERFACE \
+ "</node>\n"
+
+#define INTERFACES_LIST \
+ BUS_GENERIC_INTERFACES_LIST \
+ "org.freedesktop.login1.User\0"
+
+static int bus_user_append_display(DBusMessageIter *i, const char *property, void *data) {
+ DBusMessageIter sub;
+ User *u = data;
+ const char *id, *path;
+ char *p = NULL;
+
+ assert(i);
+ assert(property);
+ assert(u);
+
+ if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
+ return -ENOMEM;
+
+ if (u->display) {
+ id = u->display->id;
+ path = p = session_bus_path(u->display);
+
+ if (!p)
+ return -ENOMEM;
+ } else {
+ id = "";
+ path = "/";
+ }
+
+ if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
+ !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) {
+ free(p);
+ return -ENOMEM;
+ }
+
+ free(p);
+
+ if (!dbus_message_iter_close_container(i, &sub))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int bus_user_append_state(DBusMessageIter *i, const char *property, void *data) {
+ User *u = data;
+ const char *state;
+
+ assert(i);
+ assert(property);
+ assert(u);
+
+ state = user_state_to_string(user_get_state(u));
+
+ if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int bus_user_append_sessions(DBusMessageIter *i, const char *property, void *data) {
+ DBusMessageIter sub, sub2;
+ User *u = data;
+ Session *session;
+
+ assert(i);
+ assert(property);
+ assert(u);
+
+ if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "so", &sub))
+ return -ENOMEM;
+
+ LIST_FOREACH(sessions_by_user, session, u->sessions) {
+ char *p;
+
+ if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
+ return -ENOMEM;
+
+ p = session_bus_path(session);
+ if (!p)
+ return -ENOMEM;
+
+ if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
+ !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
+ free(p);
+ return -ENOMEM;
+ }
+
+ free(p);
+
+ if (!dbus_message_iter_close_container(&sub, &sub2))
+ return -ENOMEM;
+ }
+
+ if (!dbus_message_iter_close_container(i, &sub))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int get_user_for_path(Manager *m, const char *path, User **_u) {
+ User *u;
+ unsigned long lu;
+ int r;
+
+ assert(m);
+ assert(path);
+ assert(_u);
+
+ if (!startswith(path, "/org/freedesktop/login1/user/"))
+ return -EINVAL;
+
+ r = safe_atolu(path + 29, &lu);
+ if (r < 0)
+ return r;
+
+ u = hashmap_get(m->users, ULONG_TO_PTR(lu));
+ if (!u)
+ return -ENOENT;
+
+ *_u = u;
+ return 0;
+}
+
+static DBusHandlerResult user_message_dispatch(
+ User *u,
+ DBusConnection *connection,
+ DBusMessage *message) {
+
+ const BusProperty properties[] = {
+ { "org.freedesktop.login1.User", "UID", bus_property_append_uid, "u", &u->uid },
+ { "org.freedesktop.login1.User", "GID", bus_property_append_gid, "u", &u->gid },
+ { "org.freedesktop.login1.User", "Name", bus_property_append_string, "s", u->name },
+ { "org.freedesktop.login1.User", "RuntimePath", bus_property_append_string, "s", u->runtime_path },
+ { "org.freedesktop.login1.User", "ControlGroupPath", bus_property_append_string, "s", u->cgroup_path },
+ { "org.freedesktop.login1.User", "Service", bus_property_append_string, "s", u->service },
+ { "org.freedesktop.login1.User", "Display", bus_user_append_display, "(so)", u },
+ { "org.freedesktop.login1.User", "State", bus_user_append_state, "s", u },
+ { "org.freedesktop.login1.User", "Sessions", bus_user_append_sessions, "a(so)", u },
+ { NULL, NULL, NULL, NULL, NULL }
+ };
+
+ assert(u);
+ assert(connection);
+ assert(message);
+
+ return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+}
+
+static DBusHandlerResult user_message_handler(
+ DBusConnection *connection,
+ DBusMessage *message,
+ void *userdata) {
+
+ Manager *m = userdata;
+ User *u;
+ int r;
+
+ r = get_user_for_path(m, dbus_message_get_path(message), &u);
+ if (r < 0) {
+
+ if (r == -ENOMEM)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ if (r == -ENOENT) {
+ DBusError e;
+
+ dbus_error_init(&e);
+ dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown user");
+ return bus_send_error_reply(connection, message, &e, r);
+ }
+
+ return bus_send_error_reply(connection, message, NULL, r);
+ }
+
+ return user_message_dispatch(u, connection, message);
+}
+
+const DBusObjectPathVTable bus_user_vtable = {
+ .message_function = user_message_handler
+};
+
+char *user_bus_path(User *u) {
+ char *s;
+
+ assert(u);
+
+ if (asprintf(&s, "/org/freedesktop/login1/user/%llu", (unsigned long long) u->uid) < 0)
+ return NULL;
+
+ return s;
+}
diff --git a/src/logind-user.h b/src/logind-user.h
index fc48059..7f58aa2 100644
--- a/src/logind-user.h
+++ b/src/logind-user.h
@@ -70,6 +70,10 @@ UserState user_get_state(User *u);
int user_save(User *u);
int user_load(User *u);
+char *user_bus_path(User *s);
+
+extern const DBusObjectPathVTable bus_user_vtable;
+
const char* user_state_to_string(UserState s);
UserState user_state_from_string(const char *s);
diff --git a/src/logind.c b/src/logind.c
index 5d5181a..a628028 100644
--- a/src/logind.c
+++ b/src/logind.c
@@ -255,9 +255,15 @@ int manager_process_device(Manager *m, struct udev_device *d) {
assert(m);
+ /* FIXME: drop this check as soon as libudev's enum support
+ * honours tags and subsystem matches at the same time */
+ if (!streq_ptr(udev_device_get_subsystem(d), "graphics"))
+ return 0;
+
if (streq_ptr(udev_device_get_action(d), "remove")) {
- device = hashmap_get(m->devices, udev_device_get_syspath(d));
+ /* FIXME: use syspath instead of sysname here, as soon as fb driver is fixed */
+ device = hashmap_get(m->devices, udev_device_get_sysname(d));
if (!device)
return 0;
@@ -268,14 +274,16 @@ int manager_process_device(Manager *m, struct udev_device *d) {
const char *sn;
Seat *seat;
- sn = udev_device_get_property_value(d, "SEAT");
+ sn = udev_device_get_property_value(d, "ID_SEAT");
if (!sn)
sn = "seat0";
- if (!startswith(sn, "seat"))
- return -EINVAL;
+ if (!seat_name_is_valid(sn)) {
+ log_warning("Device with invalid seat name %s found, ignoring.", sn);
+ return 0;
+ }
- r = manager_add_device(m, udev_device_get_syspath(d), &device);
+ r = manager_add_device(m, udev_device_get_sysname(d), &device);
if (r < 0)
return r;
@@ -288,6 +296,7 @@ int manager_process_device(Manager *m, struct udev_device *d) {
}
device_attach(device, seat);
+ seat_start(seat);
}
return 0;
@@ -373,9 +382,6 @@ int manager_enumerate_seats(Manager *m) {
if (!dirent_is_file(de))
continue;
- if (!startswith(de->d_name, "seat"))
- continue;
-
s = hashmap_get(m->seats, de->d_name);
if (!s) {
unlinkat(dirfd(d), de->d_name, 0);
@@ -676,27 +682,15 @@ int manager_spawn_autovt(Manager *m, int vtnr) {
return 0;
}
-static DBusHandlerResult login_message_handler(
- DBusConnection *connection,
- DBusMessage *message,
- void *userdata) {
-
- return DBUS_HANDLER_RESULT_HANDLED;
-}
-
static DBusHandlerResult login_message_filter(
DBusConnection *connection,
DBusMessage *message,
void *userdata) {
- return DBUS_HANDLER_RESULT_HANDLED;
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static int manager_connect_bus(Manager *m) {
- const DBusObjectPathVTable login_vtable = {
- .message_function = login_message_handler
- };
-
DBusError error;
int r;
struct epoll_event ev;
@@ -714,13 +708,11 @@ static int manager_connect_bus(Manager *m) {
goto fail;
}
- if (!dbus_connection_register_object_path(m->bus, "/org/freedesktop/login1", &login_vtable, NULL)) {
- log_error("Not enough memory");
- r = -ENOMEM;
- goto fail;
- }
-
- if (!dbus_connection_add_filter(m->bus, login_message_filter, m, NULL)) {
+ if (!dbus_connection_register_object_path(m->bus, "/org/freedesktop/login1", &bus_manager_vtable, m) ||
+ !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/seat", &bus_seat_vtable, m) ||
+ !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/session", &bus_session_vtable, m) ||
+ !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/user", &bus_user_vtable, m) ||
+ !dbus_connection_add_filter(m->bus, login_message_filter, m, NULL)) {
log_error("Not enough memory");
r = -ENOMEM;
goto fail;
@@ -931,6 +923,9 @@ int manager_run(Manager *m) {
n = epoll_wait(m->epoll_fd, &event, 1, -1);
if (n < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+
log_error("epoll() failed: %m");
return -errno;
}
diff --git a/src/logind.h b/src/logind.h
index a8b387b..e4b7a3c 100644
--- a/src/logind.h
+++ b/src/logind.h
@@ -72,14 +72,14 @@ struct Manager {
int bus_fd;
int epoll_fd;
- int n_autovts;
+ unsigned n_autovts;
Seat *vtconsole;
char *cgroup_path;
char **controllers, **reset_controllers;
- char **kill_only_users, **kill_exlude_users;
+ char **kill_only_users, **kill_exclude_users;
bool kill_user_processes;
};
@@ -111,4 +111,6 @@ void manager_gc(Manager *m);
bool x11_display_is_local(const char *display);
+extern const DBusObjectPathVTable bus_manager_vtable;
+
#endif
commit bd253d1b910a003c1d87f1f58a6afabd4f946ce5
Author: Lennart Poettering <lennart at poettering.net>
Date: Thu May 26 02:16:49 2011 +0200
dbus: add api for append gid/uid properties
diff --git a/src/dbus-common.c b/src/dbus-common.c
index c2650fd..cb43bbd 100644
--- a/src/dbus-common.c
+++ b/src/dbus-common.c
@@ -503,7 +503,7 @@ int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *d
assert(property);
assert(data);
- /* Let's ensure that pid_t is actually 64bit, and hence this
+ /* Let's ensure that usec_t is actually 64bit, and hence this
* function can be used for usec_t */
assert_cc(sizeof(uint64_t) == sizeof(usec_t));
@@ -518,11 +518,14 @@ int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *d
assert(property);
assert(data);
- /* Let's ensure that pid_t and mode_t is actually 32bit, and
- * hence this function can be used for pid_t/mode_t */
+ /* Let's ensure that pid_t, mode_t, uid_t, gid_t are actually
+ * 32bit, and hence this function can be used for
+ * pid_t/mode_t/uid_t/gid_t */
assert_cc(sizeof(uint32_t) == sizeof(pid_t));
assert_cc(sizeof(uint32_t) == sizeof(mode_t));
assert_cc(sizeof(uint32_t) == sizeof(unsigned));
+ assert_cc(sizeof(uint32_t) == sizeof(uid_t));
+ assert_cc(sizeof(uint32_t) == sizeof(gid_t));
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
return -ENOMEM;
diff --git a/src/dbus-common.h b/src/dbus-common.h
index 1e5545f..e321a2c 100644
--- a/src/dbus-common.h
+++ b/src/dbus-common.h
@@ -129,6 +129,8 @@ int bus_property_append_long(DBusMessageIter *i, const char *property, void *dat
#define bus_property_append_int bus_property_append_int32
#define bus_property_append_pid bus_property_append_uint32
+#define bus_property_append_uid bus_property_append_uint32
+#define bus_property_append_gid bus_property_append_uint32
#define bus_property_append_mode bus_property_append_uint32
#define bus_property_append_unsigned bus_property_append_uint32
#define bus_property_append_usec bus_property_append_uint64
commit c9f09cda7705a1ad583b0d9e95b5f1e1b091438d
Author: Lennart Poettering <lennart at poettering.net>
Date: Thu May 26 02:16:17 2011 +0200
udev: simplify udev rules a bit
diff --git a/src/99-systemd.rules b/src/99-systemd.rules
index 186ef45..c079c35 100644
--- a/src/99-systemd.rules
+++ b/src/99-systemd.rules
@@ -5,7 +5,7 @@
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-ACTION!="add|change", GOTO="systemd_end"
+ACTION=="remove", GOTO="systemd_end"
SUBSYSTEM=="tty", KERNEL=="tty[0-9]|tty1[0-2]", TAG+="systemd"
SUBSYSTEM=="tty", KERNEL=="tty[a-zA-Z]*|hvc*", TAG+="systemd"
commit d2f92cdfd0189491387069da45734816effd8cbd
Author: Lennart Poettering <lennart at poettering.net>
Date: Wed May 25 00:58:55 2011 +0200
logind: unlink state files when stopping
diff --git a/src/logind-seat.c b/src/logind-seat.c
index 24a5d8f..ae89ec9 100644
--- a/src/logind-seat.c
+++ b/src/logind-seat.c
@@ -75,11 +75,7 @@ void seat_free(Seat *s) {
hashmap_remove(s->manager->seats, s->id);
- if (s->state_file) {
- unlink(s->state_file);
- free(s->state_file);
- }
-
+ free(s->state_file);
free(s);
}
@@ -323,7 +319,7 @@ int seat_stop(Seat *s) {
r = k;
}
- seat_save(s);
+ unlink(s->state_file);
seat_add_to_gc_queue(s);
return r;
diff --git a/src/logind-session.c b/src/logind-session.c
index 566323d..8f1280d 100644
--- a/src/logind-session.c
+++ b/src/logind-session.c
@@ -86,11 +86,7 @@ void session_free(Session *s) {
hashmap_remove(s->manager->sessions, s->id);
- if (s->state_file) {
- unlink(s->state_file);
- free(s->state_file);
- }
-
+ free(s->state_file);
free(s);
}
@@ -445,7 +441,8 @@ int session_stop(Session *s) {
/* Remove X11 symlink */
session_unlink_x11_socket(s);
- session_save(s);
+ unlink(s->state_file);
+ session_add_to_gc_queue(s);
return r;
}
diff --git a/src/logind-user.c b/src/logind-user.c
index 19db746..7d6df8d 100644
--- a/src/logind-user.c
+++ b/src/logind-user.c
@@ -82,12 +82,7 @@ void user_free(User *u) {
hashmap_remove(u->manager->users, ULONG_TO_PTR((unsigned long) u->uid));
free(u->name);
-
- if (u->state_file) {
- unlink(u->state_file);
- free(u->state_file);
- }
-
+ free(u->state_file);
free(u);
}
@@ -385,6 +380,9 @@ int user_stop(User *u) {
if (k < 0)
r = k;
+ unlink(u->state_file);
+ user_add_to_gc_queue(u);
+
return r;
}
diff --git a/src/logind.h b/src/logind.h
index 7a31216..a8b387b 100644
--- a/src/logind.h
+++ b/src/logind.h
@@ -39,6 +39,7 @@
* PAM rewrite
* spawn user systemd
* dbus API
+ * don't allow everybody to take logind name
*
* non-local X11 server
* reboot/shutdown halt management
commit 14c3baca3eb8b32fc266e46127851585bee5aff2
Author: Lennart Poettering <lennart at poettering.net>
Date: Wed May 25 00:55:58 2011 +0200
logind: implement GC
diff --git a/src/logind-seat.c b/src/logind-seat.c
index 743ded6..24a5d8f 100644
--- a/src/logind-seat.c
+++ b/src/logind-seat.c
@@ -48,21 +48,23 @@ Seat *seat_new(Manager *m, const char *id) {
}
s->id = file_name_from_path(s->state_file);
+ s->manager = m;
if (hashmap_put(m->seats, s->id, s) < 0) {
- free(s->id);
+ free(s->state_file);
free(s);
return NULL;
}
- s->manager = m;
-
return s;
}
void seat_free(Seat *s) {
assert(s);
+ if (s->in_gc_queue)
+ LIST_REMOVE(Seat, gc_queue, s->manager->seat_gc_queue, s);
+
while (s->sessions)
session_free(s->sessions);
@@ -73,25 +75,33 @@ void seat_free(Seat *s) {
hashmap_remove(s->manager->seats, s->id);
- free(s->state_file);
+ if (s->state_file) {
+ unlink(s->state_file);
+ free(s->state_file);
+ }
+
free(s);
}
int seat_save(Seat *s) {
- FILE *f;
int r;
+ FILE *f;
+ char *temp_path;
assert(s);
r = safe_mkdir("/run/systemd/seat", 0755, 0, 0);
if (r < 0)
- return r;
+ goto finish;
+
+ r = fopen_temporary(s->state_file, &f, &temp_path);
+ if (r < 0)
+ goto finish;
- f = fopen(s->state_file, "we");
- if (!f)
- return -errno;
+ fchmod(fileno(f), 0644);
fprintf(f,
+ "# This is private data. Do not parse.\n"
"IS_VTCONSOLE=%i\n",
s->manager->vtconsole == s);
@@ -107,28 +117,45 @@ int seat_save(Seat *s) {
if (s->sessions) {
Session *i;
- fputs("OTHER_UIDS=", f);
+ fputs("OTHER=", f);
LIST_FOREACH(sessions_by_seat, i, s->sessions) {
- assert(i->user);
+ if (i == s->active)
+ continue;
+
+ fprintf(f,
+ "%s%c",
+ i->id,
+ i->sessions_by_seat_next ? ' ' : '\n');
+ }
+ fputs("OTHER_UIDS=", f);
+ LIST_FOREACH(sessions_by_seat, i, s->sessions) {
if (i == s->active)
continue;
fprintf(f,
- "%s%lu",
- i == s->sessions ? "" : " ",
- (unsigned long) i->user->uid);
+ "%lu%c",
+ (unsigned long) i->user->uid,
+ i->sessions_by_seat_next ? ' ' : '\n');
}
}
fflush(f);
- if (ferror(f)) {
+
+ if (ferror(f) || rename(temp_path, s->state_file) < 0) {
r = -errno;
unlink(s->state_file);
+ unlink(temp_path);
}
fclose(f);
+ free(temp_path);
+
+finish:
+ if (r < 0)
+ log_error("Failed to save seat data for %s: %s", s->id, strerror(-r));
+
return r;
}
@@ -158,7 +185,7 @@ static int vt_allocate(int vtnr) {
return r;
}
-int seat_preallocate_vts(Seat *s) {
+static int seat_preallocate_vts(Seat *s) {
int i, r = 0;
assert(s);
@@ -174,8 +201,10 @@ int seat_preallocate_vts(Seat *s) {
int q;
q = vt_allocate(i);
- if (r >= 0 && q < 0)
+ if (q < 0) {
+ log_error("Failed to preallocate VT %i: %s", i, strerror(-q));
r = q;
+ }
}
return r;
@@ -199,44 +228,122 @@ int seat_apply_acls(Seat *s, Session *old_active) {
}
int seat_active_vt_changed(Seat *s, int vtnr) {
- Session *i;
- Session *old_active;
+ Session *i, *new_active = NULL, *old_active;
assert(s);
assert(vtnr >= 1);
- assert(s->manager->vtconsole == s);
- old_active = s->active;
- s->active = NULL;
+ if (s->manager->vtconsole != s)
+ return -EINVAL;
+
+ log_debug("VT changed to %i", vtnr);
LIST_FOREACH(sessions_by_seat, i, s->sessions)
if (i->vtnr == vtnr) {
- s->active = i;
+ new_active = i;
break;
}
- if (old_active == s->active)
+ if (new_active == s->active)
return 0;
+ old_active = s->active;
+ s->active = new_active;
+
seat_apply_acls(s, old_active);
manager_spawn_autovt(s->manager, vtnr);
return 0;
}
+int seat_read_active_vt(Seat *s) {
+ char t[64];
+ ssize_t k;
+ int r, vtnr;
+
+ assert(s);
+
+ if (s->manager->vtconsole != s)
+ return 0;
+
+ lseek(s->manager->console_active_fd, SEEK_SET, 0);
+
+ k = read(s->manager->console_active_fd, t, sizeof(t)-1);
+ if (k <= 0) {
+ log_error("Failed to read current console: %s", k < 0 ? strerror(-errno) : "EOF");
+ return k < 0 ? -errno : -EIO;
+ }
+
+ t[k] = 0;
+ truncate_nl(t);
+
+ if (!startswith(t, "tty")) {
+ log_error("Hm, /sys/class/tty/tty0/active is badly formatted.");
+ return -EIO;
+ }
+
+ r = safe_atoi(t+3, &vtnr);
+ if (r < 0) {
+ log_error("Failed to parse VT number %s", t+3);
+ return r;
+ }
+
+ if (vtnr <= 0) {
+ log_error("VT number invalid: %s", t+3);
+ return -EIO;
+ }
+
+ return seat_active_vt_changed(s, vtnr);
+}
+
+int seat_start(Seat *s) {
+ assert(s);
+
+ /* Initialize VT magic stuff */
+ seat_preallocate_vts(s);
+
+ /* Read current VT */
+ seat_read_active_vt(s);
+
+ /* Save seat data */
+ seat_save(s);
+
+ return 0;
+}
+
int seat_stop(Seat *s) {
Session *session;
- int r = 0;
+ int r = 0, k;
assert(s);
LIST_FOREACH(sessions_by_seat, session, s->sessions) {
- int k;
-
k = session_stop(session);
if (k < 0)
r = k;
}
+ seat_save(s);
+ seat_add_to_gc_queue(s);
+
return r;
}
+
+int seat_check_gc(Seat *s) {
+ assert(s);
+
+ if (s->manager->vtconsole == s)
+ return 1;
+
+ return !!s->devices;
+}
+
+void seat_add_to_gc_queue(Seat *s) {
+ assert(s);
+
+ if (s->in_gc_queue)
+ return;
+
+ LIST_PREPEND(Seat, gc_queue, s->manager->seat_gc_queue, s);
+ s->in_gc_queue = true;
+}
diff --git a/src/logind-seat.h b/src/logind-seat.h
index 4b6b340..b1a8d61 100644
--- a/src/logind-seat.h
+++ b/src/logind-seat.h
@@ -40,15 +40,26 @@ struct Seat {
Session *active;
LIST_HEAD(Session, sessions);
+
+ bool in_gc_queue:1;
+
+ LIST_FIELDS(Seat, gc_queue);
};
Seat *seat_new(Manager *m, const char *id);
void seat_free(Seat *s);
-int seat_preallocate_vts(Seat *s);
-int seat_active_vt_changed(Seat *s, int vtnr);
-int seat_apply_acls(Seat *s, Session *old_active);
-int seat_stop(Seat *s);
+
int seat_save(Seat *s);
int seat_load(Seat *s);
+int seat_apply_acls(Seat *s, Session *old_active);
+int seat_active_vt_changed(Seat *s, int vtnr);
+int seat_read_active_vt(Seat *s);
+
+int seat_start(Seat *s);
+int seat_stop(Seat *s);
+
+int seat_check_gc(Seat *s);
+void seat_add_to_gc_queue(Seat *s);
+
#endif
diff --git a/src/logind-session.c b/src/logind-session.c
index c10f5e6..566323d 100644
--- a/src/logind-session.c
+++ b/src/logind-session.c
@@ -34,7 +34,7 @@ Session* session_new(Manager *m, User *u, const char *id) {
assert(m);
assert(id);
- s = new(Session, 1);
+ s = new0(Session, 1);
if (!s)
return NULL;
@@ -56,7 +56,7 @@ Session* session_new(Manager *m, User *u, const char *id) {
s->pipe_fd = -1;
s->user = u;
- dual_timestamp_get(&s->timestamp);
+ LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
return s;
}
@@ -64,6 +64,9 @@ Session* session_new(Manager *m, User *u, const char *id) {
void session_free(Session *s) {
assert(s);
+ if (s->in_gc_queue)
+ LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
+
if (s->user) {
LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
@@ -83,26 +86,33 @@ void session_free(Session *s) {
hashmap_remove(s->manager->sessions, s->id);
- free(s->state_file);
+ if (s->state_file) {
+ unlink(s->state_file);
+ free(s->state_file);
+ }
+
free(s);
}
int session_save(Session *s) {
FILE *f;
int r = 0;
+ char *temp_path;
assert(s);
r = safe_mkdir("/run/systemd/session", 0755, 0, 0);
if (r < 0)
- return r;
+ goto finish;
- f = fopen(s->state_file, "we");
- if (!f)
- return -errno;
+ r = fopen_temporary(s->state_file, &f, &temp_path);
+ if (r < 0)
+ goto finish;
assert(s->user);
+ fchmod(fileno(f), 0644);
+
fprintf(f,
"# This is private data. Do not parse.\n"
"UID=%lu\n"
@@ -157,12 +167,20 @@ int session_save(Session *s) {
(unsigned long long) s->audit_id);
fflush(f);
- if (ferror(f)) {
+
+ if (ferror(f) || rename(temp_path, s->state_file) < 0) {
r = -errno;
unlink(s->state_file);
+ unlink(temp_path);
}
fclose(f);
+ free(temp_path);
+
+finish:
+ if (r < 0)
+ log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
+
return r;
}
@@ -196,10 +214,7 @@ int session_activate(Session *s) {
old_active = s->seat->active;
s->seat->active = s;
- seat_apply_acls(s->seat, old_active);
- manager_spawn_autovt(s->manager, s->vtnr);
-
- return 0;
+ return seat_apply_acls(s->seat, old_active);
}
bool x11_display_is_local(const char *display) {
@@ -333,11 +348,6 @@ int session_start(Session *s) {
assert(s);
assert(s->user);
- /* Create user first */
- r = user_start(s->user);
- if (r < 0)
- return r;
-
/* Create cgroup */
r = session_create_cgroup(s);
if (r < 0)
@@ -345,6 +355,12 @@ int session_start(Session *s) {
/* Create X11 symlink */
session_link_x11_socket(s);
+
+ /* Save session data */
+ session_save(s);
+
+ dual_timestamp_get(&s->timestamp);
+
return 0;
}
@@ -429,6 +445,8 @@ int session_stop(Session *s) {
/* Remove X11 symlink */
session_unlink_x11_socket(s);
+ session_save(s);
+
return r;
}
@@ -452,7 +470,7 @@ int session_check_gc(Session *s) {
if (r < 0)
return r;
- if (r <= 0)
+ if (r == 0)
return 1;
}
@@ -469,6 +487,16 @@ int session_check_gc(Session *s) {
return 0;
}
+void session_add_to_gc_queue(Session *s) {
+ assert(s);
+
+ if (s->in_gc_queue)
+ return;
+
+ LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
+ s->in_gc_queue = true;
+}
+
static const char* const session_type_table[_SESSION_TYPE_MAX] = {
[SESSION_TERMINAL] = "terminal",
[SESSION_X11] = "x11"
diff --git a/src/logind-session.h b/src/logind-session.h
index b3f0b5f..4c6e768 100644
--- a/src/logind-session.h
+++ b/src/logind-session.h
@@ -66,17 +66,21 @@ struct Session {
char *cgroup_path;
char **controllers, **reset_controllers;
- bool kill_processes;
+ bool kill_processes:1;
+ bool in_gc_queue:1;
LIST_FIELDS(Session, sessions_by_user);
LIST_FIELDS(Session, sessions_by_seat);
+
+ LIST_FIELDS(Session, gc_queue);
};
Session *session_new(Manager *m, User *u, const char *id);
void session_free(Session *s);
+int session_check_gc(Session *s);
+void session_add_to_gc_queue(Session *s);
int session_activate(Session *s);
bool session_is_active(Session *s);
-int session_check_gc(Session *s);
int session_start(Session *s);
int session_stop(Session *s);
int session_save(Session *s);
diff --git a/src/logind-user.c b/src/logind-user.c
index e0a3842..19db746 100644
--- a/src/logind-user.c
+++ b/src/logind-user.c
@@ -35,7 +35,7 @@ User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
assert(m);
assert(name);
- u = new(User, 1);
+ u = new0(User, 1);
if (!u)
return NULL;
@@ -68,6 +68,9 @@ User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
void user_free(User *u) {
assert(u);
+ if (u->in_gc_queue)
+ LIST_REMOVE(User, gc_queue, u->manager->user_gc_queue, u);
+
while (u->sessions)
session_free(u->sessions);
@@ -79,26 +82,35 @@ void user_free(User *u) {
hashmap_remove(u->manager->users, ULONG_TO_PTR((unsigned long) u->uid));
free(u->name);
- free(u->state_file);
+
+ if (u->state_file) {
+ unlink(u->state_file);
+ free(u->state_file);
+ }
+
free(u);
}
int user_save(User *u) {
FILE *f;
int r;
+ char *temp_path;
assert(u);
assert(u->state_file);
r = safe_mkdir("/run/systemd/user", 0755, 0, 0);
if (r < 0)
- return r;
+ goto finish;
- f = fopen(u->state_file, "we");
- if (!f)
- return -errno;
+ r = fopen_temporary(u->state_file, &f, &temp_path);
+ if (r < 0)
+ goto finish;
+
+ fchmod(fileno(f), 0644);
fprintf(f,
+ "# This is private data. Do not parse.\n"
"NAME=%s\n"
"STATE=%s\n",
u->name,
@@ -125,12 +137,20 @@ int user_save(User *u) {
u->display->id);
fflush(f);
- if (ferror(f)) {
+
+ if (ferror(f) || rename(temp_path, u->state_file) < 0) {
r = -errno;
unlink(u->state_file);
+ unlink(temp_path);
}
fclose(f);
+ free(temp_path);
+
+finish:
+ if (r < 0)
+ log_error("Failed to save user data for %s: %s", u->name, strerror(-r));
+
return r;
}
@@ -260,6 +280,9 @@ int user_start(User *u) {
if (r < 0)
return r;
+ /* Save new user data */
+ user_save(u);
+
dual_timestamp_get(&u->timestamp);
return 0;
@@ -395,6 +418,16 @@ int user_check_gc(User *u) {
return 0;
}
+void user_add_to_gc_queue(User *u) {
+ assert(u);
+
+ if (u->in_gc_queue)
+ return;
+
+ LIST_PREPEND(User, gc_queue, u->manager->user_gc_queue, u);
+ u->in_gc_queue = true;
+}
+
UserState user_get_state(User *u) {
Session *i;
diff --git a/src/logind-user.h b/src/logind-user.h
index 04392e0..fc48059 100644
--- a/src/logind-user.h
+++ b/src/logind-user.h
@@ -54,14 +54,18 @@ struct User {
dual_timestamp timestamp;
+ bool in_gc_queue:1;
+
LIST_HEAD(Session, sessions);
+ LIST_FIELDS(User, gc_queue);
};
User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name);
void user_free(User *u);
+int user_check_gc(User *u);
+void user_add_to_gc_queue(User *u);
int user_start(User *u);
int user_stop(User *u);
-int user_check_gc(User *u);
UserState user_get_state(User *u);
int user_save(User *u);
int user_load(User *u);
diff --git a/src/logind.c b/src/logind.c
index 7e9b706..5d5181a 100644
--- a/src/logind.c
+++ b/src/logind.c
@@ -200,7 +200,6 @@ int manager_add_session(Manager *m, User *u, const char *id, Session **_session)
int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) {
User *u;
- int r;
assert(m);
assert(name);
@@ -217,16 +216,10 @@ int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **
if (!u)
return -ENOMEM;
- r = user_start(u);
- if (r < 0) {
- user_stop(u);
- user_free(u);
- } else {
- if (_user)
- *_user = u;
- }
+ if (_user)
+ *_user = u;
- return r;
+ return 0;
}
int manager_add_user_by_name(Manager *m, const char *name, User **_user) {
@@ -257,33 +250,53 @@ int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) {
}
int manager_process_device(Manager *m, struct udev_device *d) {
- const char *sn;
- Seat *seat;
Device *device;
int r;
assert(m);
- sn = udev_device_get_property_value(d, "SEAT");
- if (!sn)
- sn = "seat0";
+ if (streq_ptr(udev_device_get_action(d), "remove")) {
- r = manager_add_device(m, udev_device_get_syspath(d), &device);
- if (r < 0)
- return r;
+ device = hashmap_get(m->devices, udev_device_get_syspath(d));
+ if (!device)
+ return 0;
- r = manager_add_seat(m, sn, &seat);
- if (r < 0)
- return r;
+ seat_add_to_gc_queue(device->seat);
+ device_free(device);
+
+ } else {
+ const char *sn;
+ Seat *seat;
+
+ sn = udev_device_get_property_value(d, "SEAT");
+ if (!sn)
+ sn = "seat0";
+
+ if (!startswith(sn, "seat"))
+ return -EINVAL;
+
+ r = manager_add_device(m, udev_device_get_syspath(d), &device);
+ if (r < 0)
+ return r;
+
+ r = manager_add_seat(m, sn, &seat);
+ if (r < 0) {
+ if (!device->seat)
+ device_free(device);
+
+ return r;
+ }
+
+ device_attach(device, seat);
+ }
- device_attach(device, seat);
return 0;
}
int manager_enumerate_devices(Manager *m) {
struct udev_list_entry *item = NULL, *first = NULL;
struct udev_enumerate *e;
- int r = -ENOMEM;
+ int r;
assert(m);
@@ -291,16 +304,21 @@ int manager_enumerate_devices(Manager *m) {
* necessary */
e = udev_enumerate_new(m->udev);
- if (!e)
+ if (!e) {
+ r = -ENOMEM;
goto finish;
+ }
- if (udev_enumerate_add_match_subsystem(e, "graphics") < 0)
+ r = udev_enumerate_add_match_subsystem(e, "graphics");
+ if (r < 0)
goto finish;
- if (udev_enumerate_add_match_tag(e, "seat") < 0)
+ r = udev_enumerate_add_match_tag(e, "seat");
+ if (r < 0)
goto finish;
- if (udev_enumerate_scan_devices(e) < 0)
+ r = udev_enumerate_scan_devices(e);
+ if (r < 0)
goto finish;
first = udev_enumerate_get_list_entry(e);
@@ -309,8 +327,10 @@ int manager_enumerate_devices(Manager *m) {
int k;
d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
- if (!d)
+ if (!d) {
+ r = -ENOMEM;
goto finish;
+ }
k = manager_process_device(m, d);
udev_device_unref(d);
@@ -353,6 +373,9 @@ int manager_enumerate_seats(Manager *m) {
if (!dirent_is_file(de))
continue;
+ if (!startswith(de->d_name, "seat"))
+ continue;
+
s = hashmap_get(m->seats, de->d_name);
if (!s) {
unlinkat(dirfd(d), de->d_name, 0);
@@ -385,24 +408,61 @@ static int manager_enumerate_users_from_cgroup(Manager *m) {
while ((r = cg_read_subgroup(d, &name)) > 0) {
User *user;
+ int k;
+
+ k = manager_add_user_by_name(m, name, &user);
+ if (k < 0) {
+ free(name);
+ r = k;
+ continue;
+ }
+
+ user_add_to_gc_queue(user);
+
+ if (!user->cgroup_path)
+ if (asprintf(&user->cgroup_path, "%s/%s", m->cgroup_path, name) < 0) {
+ r = -ENOMEM;
+ free(name);
+ break;
+ }
- r = manager_add_user_by_name(m, name, &user);
free(name);
+ }
+
+ closedir(d);
+
+ return r;
+}
- if (r < 0)
- break;
- if (user->cgroup_path)
+static int manager_enumerate_linger_users(Manager *m) {
+ DIR *d;
+ struct dirent *de;
+ int r = 0;
+
+ d = opendir("/var/lib/systemd/linger");
+ if (!d) {
+ if (errno == ENOENT)
+ return 0;
+
+ log_error("Failed to open /var/lib/systemd/linger/: %m");
+ return -errno;
+ }
+
+ while ((de = readdir(d))) {
+ int k;
+
+ if (!dirent_is_file(de))
continue;
- if (asprintf(&user->cgroup_path, "%s/%s", m->cgroup_path, name) < 0) {
- r = -ENOMEM;
- break;
+ k = manager_add_user_by_name(m, de->d_name, NULL);
+ if (k < 0) {
+ log_notice("Couldn't add lingering user %s: %s", de->d_name, strerror(-k));
+ r = k;
}
}
- if (d)
- closedir(d);
+ closedir(d);
return r;
}
@@ -410,12 +470,19 @@ static int manager_enumerate_users_from_cgroup(Manager *m) {
int manager_enumerate_users(Manager *m) {
DIR *d;
struct dirent *de;
- int r;
+ int r, k;
assert(m);
+ /* First, enumerate user cgroups */
r = manager_enumerate_users_from_cgroup(m);
+ /* Second, add lingering users on top */
+ k = manager_enumerate_linger_users(m);
+ if (k < 0)
+ r = k;
+
+ /* Third, read in user data stored on disk */
d = opendir("/run/systemd/users");
if (!d) {
if (errno == ENOENT)
@@ -428,7 +495,6 @@ int manager_enumerate_users(Manager *m) {
while ((de = readdir(d))) {
unsigned long ul;
User *u;
- int k;
if (!dirent_is_file(de))
continue;
@@ -465,6 +531,9 @@ static int manager_enumerate_sessions_from_cgroup(Manager *m) {
char *name;
int k;
+ if (!u->cgroup_path)
+ continue;
+
k = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, &d);
if (k < 0) {
if (k == -ENOENT)
@@ -479,18 +548,21 @@ static int manager_enumerate_sessions_from_cgroup(Manager *m) {
Session *session;
k = manager_add_session(m, u, name, &session);
- free(name);
-
- if (k < 0)
+ if (k < 0) {
+ free(name);
break;
+ }
- if (session->cgroup_path)
- continue;
+ session_add_to_gc_queue(session);
- if (asprintf(&session->cgroup_path, "%s/%s", u->cgroup_path, name) < 0) {
- k = -ENOMEM;
- break;
- }
+ if (!session->cgroup_path)
+ if (asprintf(&session->cgroup_path, "%s/%s", u->cgroup_path, name) < 0) {
+ k = -ENOMEM;
+ free(name);
+ break;
+ }
+
+ free(name);
}
closedir(d);
@@ -509,8 +581,10 @@ int manager_enumerate_sessions(Manager *m) {
assert(m);
+ /* First enumerate session cgroups */
r = manager_enumerate_sessions_from_cgroup(m);
+ /* Second, read in session data stored on disk */
d = opendir("/run/systemd/sessions");
if (!d) {
if (errno == ENOENT)
@@ -543,38 +617,6 @@ int manager_enumerate_sessions(Manager *m) {
return r;
}
-int manager_start_linger_users(Manager *m) {
- DIR *d;
- struct dirent *de;
- int r = 0;
-
- d = opendir("/var/lib/systemd/linger");
- if (!d) {
- if (errno == ENOENT)
- return 0;
-
- log_error("Failed to open /var/lib/systemd/linger/: %m");
- return -errno;
- }
-
- while ((de = readdir(d))) {
- int k;
-
- if (!dirent_is_file(de))
- continue;
-
- k = manager_add_user_by_name(m, de->d_name, NULL);
- if (k < 0) {
- log_notice("Couldn't add lingering user %s: %s", de->d_name, strerror(-k));
- r = k;
- }
- }
-
- closedir(d);
-
- return r;
-}
-
int manager_dispatch_udev(Manager *m) {
struct udev_device *d;
int r;
@@ -592,39 +634,10 @@ int manager_dispatch_udev(Manager *m) {
}
int manager_dispatch_console(Manager *m) {
- char t[64];
- ssize_t k;
- int r, vtnr;
-
assert(m);
- lseek(m->console_active_fd, SEEK_SET, 0);
-
- k = read(m->console_active_fd, t, sizeof(t)-1);
- if (k <= 0) {
- log_error("Failed to read current console: %s", k < 0 ? strerror(-errno) : "EOF");
- return k < 0 ? -errno : -EIO;
- }
-
- t[k] = 0;
- if (!startswith(t, "tty")) {
- log_error("Hm, /sys/class/tty/tty0/active is badly formatted.");
- return -EIO;
- }
-
- r = safe_atoi(t+3, &vtnr);
- if (r < 0) {
- log_error("Failed to parse VT number %s", t+3);
- return r;
- }
-
- if (vtnr <= 0) {
- log_error("VT number invalid: %s", t+3);
- return -EIO;
- }
-
if (m->vtconsole)
- seat_active_vt_changed(m->vtconsole, vtnr);
+ seat_read_active_vt(m->vtconsole);
return 0;
}
@@ -766,7 +779,7 @@ static int manager_connect_console(Manager *m) {
}
zero(ev);
- ev.events = EPOLLIN;
+ ev.events = 0;
ev.data.u32 = FD_CONSOLE;
if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->console_active_fd, &ev) < 0)
@@ -777,6 +790,7 @@ static int manager_connect_console(Manager *m) {
static int manager_connect_udev(Manager *m) {
struct epoll_event ev;
+ int r;
assert(m);
assert(!m->udev_monitor);
@@ -785,13 +799,17 @@ static int manager_connect_udev(Manager *m) {
if (!m->udev_monitor)
return -ENOMEM;
- udev_monitor_filter_add_match_tag(m->udev_monitor, "seat");
+ r = udev_monitor_filter_add_match_tag(m->udev_monitor, "seat");
+ if (r < 0)
+ return r;
- if (udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "graphics", NULL) < 0)
- return -ENOMEM;
+ r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "graphics", NULL);
+ if (r < 0)
+ return r;
- if (udev_monitor_enable_receiving(m->udev_monitor) < 0)
- return -ENOMEM;
+ r = udev_monitor_enable_receiving(m->udev_monitor);
+ if (r < 0)
+ return r;
m->udev_fd = udev_monitor_get_fd(m->udev_monitor);
@@ -805,8 +823,50 @@ static int manager_connect_udev(Manager *m) {
return 0;
}
+void manager_gc(Manager *m) {
+ Seat *seat;
+ Session *session;
+ User *user;
+
+ assert(m);
+
+ while ((seat = m->seat_gc_queue)) {
+ LIST_REMOVE(Seat, gc_queue, m->seat_gc_queue, seat);
+ seat->in_gc_queue = false;
+
+ if (seat_check_gc(seat) == 0) {
+ seat_stop(seat);
+ seat_free(seat);
+ }
+ }
+
+ while ((session = m->session_gc_queue)) {
+ LIST_REMOVE(Session, gc_queue, m->session_gc_queue, session);
+ session->in_gc_queue = false;
+
+ if (session_check_gc(session) == 0) {
+ session_stop(session);
+ session_free(session);
+ }
+ }
+
+ while ((user = m->user_gc_queue)) {
+ LIST_REMOVE(User, gc_queue, m->user_gc_queue, user);
+ user->in_gc_queue = false;
+
+ if (user_check_gc(user) == 0) {
+ user_stop(user);
+ user_free(user);
+ }
+ }
+}
+
int manager_startup(Manager *m) {
int r;
+ Seat *seat;
+ Session *session;
+ User *user;
+ Iterator i;
assert(m);
assert(m->epoll_fd <= 0);
@@ -830,14 +890,29 @@ int manager_startup(Manager *m) {
if (r < 0)
return r;
+ /* Instantiate magic seat 0 */
+ r = manager_add_seat(m, "seat0", &m->vtconsole);
+ if (r < 0)
+ return r;
+
/* Deserialize state */
manager_enumerate_devices(m);
manager_enumerate_seats(m);
manager_enumerate_users(m);
manager_enumerate_sessions(m);
- /* Spawn lingering users */
- manager_start_linger_users(m);
+ /* Get rid of objects that are no longer used */
+ manager_gc(m);
+
+ /* And start everything */
+ HASHMAP_FOREACH(seat, m->seats, i)
+ seat_start(seat);
+
+ HASHMAP_FOREACH(user, m->users, i)
+ user_start(user);
+
+ HASHMAP_FOREACH(session, m->sessions, i)
+ session_start(session);
return 0;
}
@@ -849,6 +924,8 @@ int manager_run(Manager *m) {
struct epoll_event event;
int n;
+ manager_gc(m);
+
if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE)
continue;
diff --git a/src/logind.h b/src/logind.h
index be5dab7..7a31216 100644
--- a/src/logind.h
+++ b/src/logind.h
@@ -59,6 +59,10 @@ struct Manager {
Hashmap *sessions;
Hashmap *users;
+ LIST_HEAD(Seat, seat_gc_queue);
+ LIST_HEAD(Session, session_gc_queue);
+ LIST_HEAD(User, user_gc_queue);
+
struct udev *udev;
struct udev_monitor *udev_monitor;
@@ -81,25 +85,29 @@ struct Manager {
Manager *manager_new(void);
void manager_free(Manager *m);
+
int manager_add_device(Manager *m, const char *sysfs, Device **_device);
int manager_add_seat(Manager *m, const char *id, Seat **_seat);
int manager_add_session(Manager *m, User *u, const char *id, Session **_session);
int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user);
int manager_add_user_by_name(Manager *m, const char *name, User **_user);
int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user);
+
int manager_process_device(Manager *m, struct udev_device *d);
int manager_dispatch_udev(Manager *m);
int manager_dispatch_console(Manager *m);
+
int manager_enumerate_devices(Manager *m);
int manager_enumerate_seats(Manager *m);
int manager_enumerate_sessions(Manager *m);
int manager_enumerate_users(Manager *m);
-int manager_start_one_linger_user(Manager *m, const char *user);
-int manager_start_linger_users(Manager *m);
+
int manager_startup(Manager *m);
int manager_run(Manager *m);
int manager_spawn_autovt(Manager *m, int vtnr);
+void manager_gc(Manager *m);
+
bool x11_display_is_local(const char *display);
#endif
diff --git a/src/org.freedesktop.login1.conf b/src/org.freedesktop.login1.conf
new file mode 100644
index 0000000..20008ea
--- /dev/null
+++ b/src/org.freedesktop.login1.conf
@@ -0,0 +1,28 @@
+<?xml version="1.0"?> <!--*-nxml-*-->
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+
+<!--
+ This file is part of systemd.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+-->
+
+<busconfig>
+
+ <policy user="root">
+ <allow own="org.freedesktop.login1"/>
+ <allow send_destination="org.freedesktop.login1"/>
+ <allow receive_sender="org.freedesktop.login1"/>
+ </policy>
+
+ <policy context="default">
+ <allow own="org.freedesktop.login1"/>
+ <allow send_destination="org.freedesktop.login1"/>
+ <allow receive_sender="org.freedesktop.login1"/>
+ </policy>
+
+</busconfig>
commit 5a3ab509b56bd79bf2be53cc259ce45c0be269e6
Author: Lennart Poettering <lennart at poettering.net>
Date: Wed May 25 00:54:32 2011 +0200
util: add fopen_temporary()
diff --git a/src/util.c b/src/util.c
index ad1ca06..156d32a 100644
--- a/src/util.c
+++ b/src/util.c
@@ -4455,7 +4455,49 @@ int pipe_eof(int fd) {
return pollfd.revents & POLLHUP;
}
+int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
+ FILE *f;
+ char *t;
+ const char *fn;
+ size_t k;
+ int fd;
+
+ assert(path);
+ assert(_f);
+ assert(_temp_path);
+
+ t = new(char, strlen(path) + 1 + 6 + 1);
+ if (!t)
+ return -ENOMEM;
+
+ fn = file_name_from_path(path);
+ k = fn-path;
+ memcpy(t, path, k);
+ t[k] = '.';
+ stpcpy(stpcpy(t+k+1, fn), "XXXXXX");
+
+ fd = mkostemp(t, O_WRONLY|O_CLOEXEC);
+ if (fd < 0) {
+ free(t);
+ return -errno;
+ }
+
+ f = fdopen(fd, "we");
+ if (!f) {
+ unlink(t);
+ free(t);
+ return -errno;
+ }
+
+ *_f = f;
+ *_temp_path = t;
+
+ return 0;
+}
+
int terminal_vhangup_fd(int fd) {
+ assert(fd >= 0);
+
if (ioctl(fd, TIOCVHANGUP) < 0)
return -errno;
diff --git a/src/util.h b/src/util.h
index 6076e69..15dfe17 100644
--- a/src/util.h
+++ b/src/util.h
@@ -330,6 +330,7 @@ int default_signals(int sig, ...);
int sigaction_many(const struct sigaction *sa, ...);
int close_pipe(int p[]);
+int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll);
ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll);
commit 5eda94dda25bccda928c4b33c790dbe748573a22
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue May 24 04:20:35 2011 +0200
logind: implement ACL management
diff --git a/.gitignore b/.gitignore
index c2820b0..7bd22c5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+systemd-uaccess
systemd-logind
systemd-hostnamed
systemd-binfmt
diff --git a/Makefile.am b/Makefile.am
index 79ccbbe..f455f21 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -159,7 +159,8 @@ rootlibexec_PROGRAMS = \
systemd-detect-virt \
systemd-sysctl \
systemd-hostnamed \
- systemd-logind
+ systemd-logind \
+ systemd-uaccess
if ENABLE_BINFMT
rootlibexec_PROGRAMS += \
@@ -813,6 +814,7 @@ systemd_logind_SOURCES = \
src/logind-seat.c \
src/logind-session.c \
src/logind-user.c \
+ src/logind-acl.c \
src/dbus-common.c \
src/dbus-loop.c \
src/cgroup-util.c
@@ -820,13 +822,29 @@ systemd_logind_SOURCES = \
systemd_logind_CFLAGS = \
$(AM_CFLAGS) \
$(DBUS_CFLAGS) \
- $(UDEV_CFLAGS)
+ $(UDEV_CFLAGS) \
+ $(ACL_CFLAGS)
systemd_logind_LDADD = \
libsystemd-basic.la \
libsystemd-daemon.la \
$(DBUS_LIBS) \
- $(UDEV_LIBS)
+ $(UDEV_LIBS) \
+ $(ACL_LIBS)
+
+systemd_uaccess_SOURCES = \
+ src/uaccess.c \
+ src/logind-acl.c
+
+systemd_uaccess_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(UDEV_CFLAGS) \
+ $(ACL_CFLAGS)
+
+systemd_uaccess_LDADD = \
+ libsystemd-basic.la \
+ $(UDEV_LIBS) \
+ $(ACL_LIBS)
systemd_shutdown_SOURCES = \
src/mount-setup.c \
diff --git a/configure.ac b/configure.ac
index eb5fb6a..0dd185b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -193,6 +193,43 @@ fi
AC_SUBST(PAM_LIBS)
AM_CONDITIONAL([HAVE_PAM], [test "x$have_pam" != xno])
+AC_ARG_ENABLE([acl],
+ AS_HELP_STRING([--disable-acl],[Disable optional ACL support]),
+ [case "${enableval}" in
+ yes) have_acl=yes ;;
+ no) have_acl=no ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --disable-acl) ;;
+ esac],
+ [have_acl=auto])
+
+if test "x${have_acl}" != xno ; then
+ AC_CHECK_HEADERS(
+ [sys/acl.h acl/libacl.h],
+ [have_acl=yes],
+ [if test "x$have_acl" = xyes ; then
+ AC_MSG_ERROR([*** ACL headers not found.])
+ fi])
+
+ AC_CHECK_LIB(
+ [acl],
+ [acl_get_file],
+ [have_acl=yes],
+ [if test "x$have_acl" = xyes ; then
+ AC_MSG_ERROR([*** libacl not found.])
+ fi])
+
+ if test "x$have_acl" = xyes ; then
+ ACL_LIBS="-lacl"
+ AC_DEFINE(HAVE_ACL, 1, [ACL available])
+ else
+ have_acl=no
+ fi
+else
+ ACL_LIBS=
+fi
+AC_SUBST(ACL_LIBS)
+AM_CONDITIONAL([HAVE_ACL], [test "x$have_acl" != xno])
+
AC_ARG_ENABLE([audit],
AS_HELP_STRING([--disable-audit],[Disable optional AUDIT support]),
[case "${enableval}" in
@@ -496,6 +533,7 @@ echo "
PAM: ${have_pam}
AUDIT: ${have_audit}
SELinux: ${have_selinux}
+ ACL: ${have_acl}
binfmt: ${have_binfmt}
prefix: ${prefix}
root dir: ${with_rootdir}
diff --git a/src/logind-acl.c b/src/logind-acl.c
new file mode 100644
index 0000000..3df104f
--- /dev/null
+++ b/src/logind-acl.c
@@ -0,0 +1,282 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <sys/acl.h>
+#include <acl/libacl.h>
+#include <errno.h>
+#include <string.h>
+
+#include "logind-acl.h"
+#include "util.h"
+
+static int find_acl(acl_t acl, uid_t uid, acl_entry_t *entry) {
+ acl_entry_t i;
+ int found;
+
+ assert(acl);
+ assert(entry);
+
+ for (found = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
+ found > 0;
+ found = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) {
+
+ acl_tag_t tag;
+ uid_t *u;
+ bool b;
+
+ if (acl_get_tag_type(i, &tag) < 0)
+ return -errno;
+
+ if (tag != ACL_USER)
+ continue;
+
+ u = acl_get_qualifier(i);
+ if (!u)
+ return -errno;
+
+ b = *u == uid;
+ free(u);
+
+ if (b) {
+ *entry = i;
+ return 1;
+ }
+ }
+
+ if (found < 0)
+ return -errno;
+
+ return 0;
+}
+
+static int flush_acl(acl_t acl) {
+ acl_entry_t i;
+ int found;
+ bool changed = false;
+
+ assert(acl);
+
+ for (found = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
+ found > 0;
+ found = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) {
+
+ acl_tag_t tag;
+
+ if (acl_get_tag_type(i, &tag) < 0)
+ return -errno;
+
+ if (tag != ACL_USER)
+ continue;
+
+ if (acl_delete_entry(acl, i) < 0)
+ return -errno;
+
+ changed = true;
+ }
+
+ if (found < 0)
+ return -errno;
+
+ return changed;
+}
+
+int devnode_acl(const char *path,
+ bool flush,
+ bool del, uid_t old_uid,
+ bool add, uid_t new_uid) {
+
+ acl_t acl;
+ int r;
+ bool changed = false;
+
+ assert(path);
+
+ acl = acl_get_file(path, ACL_TYPE_ACCESS);
+ if (!acl)
+ return -errno;
+
+ if (flush) {
+
+ r = flush_acl(acl);
+ if (r < 0)
+ goto finish;
+ if (r > 0)
+ changed = true;
+
+ } else if (del && old_uid > 0) {
+ acl_entry_t entry;
+
+ r = find_acl(acl, old_uid, &entry);
+ if (r < 0)
+ goto finish;
+
+ if (r > 0) {
+ if (acl_delete_entry(acl, entry) < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ changed = true;
+ }
+ }
+
+ if (add && new_uid > 0) {
+ acl_entry_t entry;
+ acl_permset_t permset;
+ int rd, wt;
+
+ r = find_acl(acl, new_uid, &entry);
+ if (r < 0)
+ goto finish;
+
+ if (r == 0) {
+ if (acl_create_entry(&acl, &entry) < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ if (acl_set_tag_type(entry, ACL_USER) < 0 ||
+ acl_set_qualifier(entry, &new_uid) < 0) {
+ r = -errno;
+ goto finish;
+ }
+ }
+
+ if (acl_get_permset(entry, &permset) < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ rd = acl_get_perm(permset, ACL_READ);
+ if (rd < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ wt = acl_get_perm(permset, ACL_WRITE);
+ if (wt < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ if (!rd || !wt) {
+
+ if (acl_add_perm(permset, ACL_READ|ACL_WRITE) < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ changed = true;
+ }
+ }
+
+ if (!changed)
+ goto finish;
+
+ if (acl_calc_mask(&acl) < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ if (acl_set_file(path, ACL_TYPE_ACCESS, acl) < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ r = 0;
+
+finish:
+ acl_free(acl);
+
+ return r;
+}
+
+int devnode_acl_all(struct udev *udev,
+ const char *seat,
+ bool flush,
+ bool del, uid_t old_uid,
+ bool add, uid_t new_uid) {
+
+ struct udev_list_entry *item = NULL, *first = NULL;
+ struct udev_enumerate *e;
+ int r;
+
+ assert(udev);
+
+ if (!seat)
+ seat = "seat0";
+
+ e = udev_enumerate_new(udev);
+ if (!e)
+ return -ENOMEM;
+
+ r = udev_enumerate_add_match_tag(e, "uaccess");
+ if (r < 0)
+ goto finish;
+
+ r = udev_enumerate_add_match_tag(e, seat);
+ if (r < 0)
+ goto finish;
+
+ r = udev_enumerate_scan_devices(e);
+ if (r < 0)
+ goto finish;
+
+ first = udev_enumerate_get_list_entry(e);
+ udev_list_entry_foreach(item, first) {
+ struct udev_device *d;
+ const char *node, *sn;
+
+ d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
+ if (!d) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ sn = udev_device_get_property_value(d, "SEAT");
+ if (!sn)
+ sn = "seat0";
+
+ if (!streq(seat, sn)) {
+ udev_device_unref(d);
+ continue;
+ }
+
+ node = udev_device_get_devnode(d);
+ udev_device_unref(d);
+
+ if (!node) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ r = devnode_acl(node, flush, del, old_uid, add, new_uid);
+ if (r < 0)
+ goto finish;
+ }
+
+finish:
+ if (e)
+ udev_enumerate_unref(e);
+
+ return r;
+}
diff --git a/src/logind-acl.h b/src/logind-acl.h
new file mode 100644
index 0000000..9c88a80
--- /dev/null
+++ b/src/logind-acl.h
@@ -0,0 +1,40 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foologindaclhfoo
+#define foologindaclhfoo
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/types.h>
+#include <stdbool.h>
+#include <libudev.h>
+
+int devnode_acl(const char *path,
+ bool flush,
+ bool del, uid_t old_uid,
+ bool add, uid_t new_uid);
+
+int devnode_acl_all(struct udev *udev,
+ const char *seat,
+ bool flush,
+ bool del, uid_t old_uid,
+ bool add, uid_t new_uid);
+
+#endif
diff --git a/src/logind-seat.c b/src/logind-seat.c
index 3154900..743ded6 100644
--- a/src/logind-seat.c
+++ b/src/logind-seat.c
@@ -25,8 +25,10 @@
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/vt.h>
+#include <string.h>
#include "logind-seat.h"
+#include "logind-acl.h"
#include "util.h"
Seat *seat_new(Manager *m, const char *id) {
@@ -179,40 +181,32 @@ int seat_preallocate_vts(Seat *s) {
return r;
}
-int seat_apply_acls(Seat *s) {
- assert(s);
-
-
- return 0;
-}
-
-static int vt_is_busy(int vtnr) {
- struct vt_stat vt_stat;
- int r = 0, fd;
-
- assert(vtnr >= 1);
+int seat_apply_acls(Seat *s, Session *old_active) {
+ int r;
- fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return -errno;
+ assert(s);
- if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
- r = -errno;
- else
- r = !!(vt_stat.v_state & (1 << vtnr));
+ r = devnode_acl_all(s->manager->udev,
+ s->id,
+ false,
+ !!old_active, old_active ? old_active->user->uid : 0,
+ !!s->active, s->active ? s->active->user->uid : 0);
- close_nointr_nofail(fd);
+ if (r < 0)
+ log_error("Failed to apply ACLs: %s", strerror(-r));
return r;
}
-void seat_active_vt_changed(Seat *s, int vtnr) {
+int seat_active_vt_changed(Seat *s, int vtnr) {
Session *i;
+ Session *old_active;
assert(s);
assert(vtnr >= 1);
assert(s->manager->vtconsole == s);
+ old_active = s->active;
s->active = NULL;
LIST_FOREACH(sessions_by_seat, i, s->sessions)
@@ -221,10 +215,13 @@ void seat_active_vt_changed(Seat *s, int vtnr) {
break;
}
- seat_apply_acls(s);
+ if (old_active == s->active)
+ return 0;
+
+ seat_apply_acls(s, old_active);
+ manager_spawn_autovt(s->manager, vtnr);
- if (vt_is_busy(vtnr) == 0)
- manager_spawn_autovt(s->manager, vtnr);
+ return 0;
}
int seat_stop(Seat *s) {
diff --git a/src/logind-seat.h b/src/logind-seat.h
index 2fe7949..4b6b340 100644
--- a/src/logind-seat.h
+++ b/src/logind-seat.h
@@ -45,8 +45,8 @@ struct Seat {
Seat *seat_new(Manager *m, const char *id);
void seat_free(Seat *s);
int seat_preallocate_vts(Seat *s);
-void seat_active_vt_changed(Seat *s, int vtnr);
-int seat_apply_acls(Seat *s);
+int seat_active_vt_changed(Seat *s, int vtnr);
+int seat_apply_acls(Seat *s, Session *old_active);
int seat_stop(Seat *s);
int seat_save(Seat *s);
int seat_load(Seat *s);
diff --git a/src/logind-session.c b/src/logind-session.c
index 7bdf487..c10f5e6 100644
--- a/src/logind-session.c
+++ b/src/logind-session.c
@@ -174,6 +174,7 @@ int session_load(Session *s) {
int session_activate(Session *s) {
int r;
+ Session *old_active;
assert(s);
@@ -192,9 +193,13 @@ int session_activate(Session *s) {
if (r < 0)
return r;
+ old_active = s->seat->active;
s->seat->active = s;
- return seat_apply_acls(s->seat);
+ seat_apply_acls(s->seat, old_active);
+ manager_spawn_autovt(s->manager, s->vtnr);
+
+ return 0;
}
bool x11_display_is_local(const char *display) {
diff --git a/src/logind.c b/src/logind.c
index 0c26aad..7e9b706 100644
--- a/src/logind.c
+++ b/src/logind.c
@@ -26,6 +26,8 @@
#include <string.h>
#include <unistd.h>
#include <sys/epoll.h>
+#include <sys/ioctl.h>
+#include <linux/vt.h>
#include "logind.h"
#include "dbus-common.h"
@@ -290,7 +292,7 @@ int manager_enumerate_devices(Manager *m) {
e = udev_enumerate_new(m->udev);
if (!e)
- return -ENOMEM;
+ goto finish;
if (udev_enumerate_add_match_subsystem(e, "graphics") < 0)
goto finish;
@@ -627,9 +629,37 @@ int manager_dispatch_console(Manager *m) {
return 0;
}
+static int vt_is_busy(int vtnr) {
+ struct vt_stat vt_stat;
+ int r = 0, fd;
+
+ assert(vtnr >= 1);
+
+ fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
+ r = -errno;
+ else
+ r = !!(vt_stat.v_state & (1 << vtnr));
+
+ close_nointr_nofail(fd);
+
+ return r;
+}
+
int manager_spawn_autovt(Manager *m, int vtnr) {
+ int r;
+
assert(m);
+ r = vt_is_busy(vtnr);
+ if (r != 0)
+ return r;
+
+ /* ... */
+
return 0;
}
@@ -849,7 +879,7 @@ int manager_run(Manager *m) {
int main(int argc, char *argv[]) {
Manager *m = NULL;
- int r = 0;
+ int r;
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
diff --git a/src/logind.h b/src/logind.h
index 0d3bd89..be5dab7 100644
--- a/src/logind.h
+++ b/src/logind.h
@@ -36,11 +36,12 @@
*
* recreate VTs when disallocated
* udev rules
+ * PAM rewrite
* spawn user systemd
+ * dbus API
+ *
* non-local X11 server
- * udev-acl
* reboot/shutdown halt management
- * PAM rewrite
*/
typedef struct Manager Manager;
diff --git a/src/uaccess.c b/src/uaccess.c
new file mode 100644
index 0000000..e55ab51
--- /dev/null
+++ b/src/uaccess.c
@@ -0,0 +1,87 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <string.h>
+
+#include "logind-acl.h"
+#include "util.h"
+#include "log.h"
+
+int main(int argc, char *argv[]) {
+ int r;
+ const char *path, *seat;
+ char *p, *active_uid = NULL;
+ unsigned long ul;
+
+ log_set_target(LOG_TARGET_AUTO);
+ log_parse_environment();
+ log_open();
+
+ if (argc != 2) {
+ log_error("This program expects two argument.");
+ r = -EINVAL;
+ goto finish;
+ }
+
+ path = argv[1];
+ seat = argv[2];
+
+ p = strappend("/run/systemd/seat/", seat);
+ if (!p) {
+ log_error("Out of memory.");
+ goto finish;
+ }
+
+ r = parse_env_file(p, NEWLINE,
+ "ACTIVE_UID", &active_uid,
+ NULL);
+ free(p);
+
+ if (r < 0) {
+ if (errno == ENOENT) {
+ r = 0;
+ goto finish;
+ }
+
+ log_error("Failed to read seat data for %s: %s", seat, strerror(-r));
+ goto finish;
+ }
+
+ r = safe_atolu(active_uid, &ul);
+ if (r < 0) {
+ log_error("Failed to parse active UID value %s: %s", active_uid, strerror(-r));
+ goto finish;
+ }
+
+ r = devnode_acl(path, true, false, 0, true, (uid_t) ul);
+ if (r < 0) {
+ log_error("Failed to apply ACL on %s: %s", path, strerror(-r));
+ goto finish;
+ }
+
+ r = 0;
+
+finish:
+ free(active_uid);
+
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
commit 90821c935e5f4258dc21fc515cf721beb0914a85
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue May 24 00:19:22 2011 +0200
logind: split up logind.h
diff --git a/src/logind-device.c b/src/logind-device.c
index 9084b5f..4e076c2 100644
--- a/src/logind-device.c
+++ b/src/logind-device.c
@@ -22,7 +22,7 @@
#include <assert.h>
#include <string.h>
-#include "logind.h"
+#include "logind-device.h"
#include "util.h"
Device* device_new(Manager *m, const char *sysfs) {
diff --git a/src/logind-device.h b/src/logind-device.h
new file mode 100644
index 0000000..e25a534
--- /dev/null
+++ b/src/logind-device.h
@@ -0,0 +1,48 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foologinddevicehfoo
+#define foologinddevicehfoo
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct Device Device;
+
+#include "list.h"
+#include "util.h"
+#include "logind.h"
+#include "logind-seat.h"
+
+struct Device {
+ Manager *manager;
+
+ char *sysfs;
+ Seat *seat;
+
+ dual_timestamp timestamp;
+
+ LIST_FIELDS(struct Device, devices);
+};
+
+Device* device_new(Manager *m, const char *sysfs);
+void device_free(Device *d);
+void device_attach(Device *d, Seat *s);
+void device_detach(Device *d);
+
+#endif
diff --git a/src/logind-seat.c b/src/logind-seat.c
index dcf1c71..3154900 100644
--- a/src/logind-seat.c
+++ b/src/logind-seat.c
@@ -26,7 +26,7 @@
#include <sys/ioctl.h>
#include <linux/vt.h>
-#include "logind.h"
+#include "logind-seat.h"
#include "util.h"
Seat *seat_new(Manager *m, const char *id) {
diff --git a/src/logind-seat.h b/src/logind-seat.h
new file mode 100644
index 0000000..2fe7949
--- /dev/null
+++ b/src/logind-seat.h
@@ -0,0 +1,54 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foologindseathfoo
+#define foologindseathfoo
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct Seat Seat;
+
+#include "list.h"
+#include "util.h"
+#include "logind.h"
+#include "logind-device.h"
+#include "logind-session.h"
+
+struct Seat {
+ Manager *manager;
+ char *id;
+
+ char *state_file;
+
+ LIST_HEAD(Device, devices);
+
+ Session *active;
+ LIST_HEAD(Session, sessions);
+};
+
+Seat *seat_new(Manager *m, const char *id);
+void seat_free(Seat *s);
+int seat_preallocate_vts(Seat *s);
+void seat_active_vt_changed(Seat *s, int vtnr);
+int seat_apply_acls(Seat *s);
+int seat_stop(Seat *s);
+int seat_save(Seat *s);
+int seat_load(Seat *s);
+
+#endif
diff --git a/src/logind-session.c b/src/logind-session.c
index 9af99d0..7bdf487 100644
--- a/src/logind-session.c
+++ b/src/logind-session.c
@@ -23,7 +23,7 @@
#include <string.h>
#include <unistd.h>
-#include "logind.h"
+#include "logind-session.h"
#include "strv.h"
#include "util.h"
#include "cgroup-util.h"
diff --git a/src/logind-session.h b/src/logind-session.h
new file mode 100644
index 0000000..b3f0b5f
--- /dev/null
+++ b/src/logind-session.h
@@ -0,0 +1,88 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foologindsessionhfoo
+#define foologindsessionhfoo
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct Session Session;
+
+#include "list.h"
+#include "util.h"
+#include "logind.h"
+#include "logind-seat.h"
+#include "logind-user.h"
+
+typedef enum SessionType {
+ SESSION_TERMINAL,
+ SESSION_X11,
+ _SESSION_TYPE_MAX,
+ _SESSION_TYPE_INVALID = -1
+} SessionType;
+
+struct Session {
+ Manager *manager;
+
+ char *id;
+ SessionType type;
+
+ char *state_file;
+
+ User *user;
+
+ dual_timestamp timestamp;
+
+ char *tty;
+ char *display;
+
+ bool remote;
+ char *remote_host;
+
+ int vtnr;
+ Seat *seat;
+
+ pid_t leader;
+ uint64_t audit_id;
+
+ int pipe_fd;
+
+ char *cgroup_path;
+ char **controllers, **reset_controllers;
+
+ bool kill_processes;
+
+ LIST_FIELDS(Session, sessions_by_user);
+ LIST_FIELDS(Session, sessions_by_seat);
+};
+
+Session *session_new(Manager *m, User *u, const char *id);
+void session_free(Session *s);
+int session_activate(Session *s);
+bool session_is_active(Session *s);
+int session_check_gc(Session *s);
+int session_start(Session *s);
+int session_stop(Session *s);
+int session_save(Session *s);
+int session_load(Session *s);
+
+const char* session_type_to_string(SessionType t);
+SessionType session_type_from_string(const char *s);
+
+#endif
diff --git a/src/logind-user.c b/src/logind-user.c
index 1292eed..e0a3842 100644
--- a/src/logind-user.c
+++ b/src/logind-user.c
@@ -23,7 +23,7 @@
#include <unistd.h>
#include <errno.h>
-#include "logind.h"
+#include "logind-user.h"
#include "util.h"
#include "cgroup-util.h"
#include "hashmap.h"
diff --git a/src/logind-user.h b/src/logind-user.h
new file mode 100644
index 0000000..04392e0
--- /dev/null
+++ b/src/logind-user.h
@@ -0,0 +1,72 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foologinduserhfoo
+#define foologinduserhfoo
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct User User;
+
+#include "list.h"
+#include "util.h"
+#include "logind.h"
+#include "logind-session.h"
+
+typedef enum UserState {
+ USER_OFFLINE,
+ USER_LINGERING,
+ USER_ONLINE,
+ USER_ACTIVE,
+ _USER_STATE_MAX,
+ _USER_STATE_INVALID = -1
+} UserState;
+
+struct User {
+ Manager *manager;
+
+ uid_t uid;
+ gid_t gid;
+ char *name;
+
+ char *state_file;
+ char *runtime_path;
+ char *service;
+ char *cgroup_path;
+
+ Session *display;
+
+ dual_timestamp timestamp;
+
+ LIST_HEAD(Session, sessions);
+};
+
+User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name);
+void user_free(User *u);
+int user_start(User *u);
+int user_stop(User *u);
+int user_check_gc(User *u);
+UserState user_get_state(User *u);
+int user_save(User *u);
+int user_load(User *u);
+
+const char* user_state_to_string(UserState s);
+UserState user_state_from_string(const char *s);
+
+#endif
diff --git a/src/logind.h b/src/logind.h
index 5e69a71..0d3bd89 100644
--- a/src/logind.h
+++ b/src/logind.h
@@ -44,103 +44,11 @@
*/
typedef struct Manager Manager;
-typedef struct Device Device;
-typedef struct Seat Seat;
-typedef struct Session Session;
-typedef struct User User;
-struct Device {
- Manager *manager;
-
- char *sysfs;
- Seat *seat;
-
- dual_timestamp timestamp;
-
- LIST_FIELDS(struct Device, devices);
-};
-
-struct Seat {
- Manager *manager;
- char *id;
-
- char *state_file;
-
- LIST_HEAD(Device, devices);
-
- Session *active;
- LIST_HEAD(Session, sessions);
-};
-
-typedef enum SessionType {
- SESSION_TERMINAL,
- SESSION_X11,
- _SESSION_TYPE_MAX,
- _SESSION_TYPE_INVALID = -1
-} SessionType;
-
-struct Session {
- Manager *manager;
-
- char *id;
- SessionType type;
-
- char *state_file;
-
- User *user;
-
- dual_timestamp timestamp;
-
- char *tty;
- char *display;
-
- bool remote;
- char *remote_host;
-
- int vtnr;
- Seat *seat;
-
- pid_t leader;
- uint64_t audit_id;
-
- int pipe_fd;
-
- char *cgroup_path;
- char **controllers, **reset_controllers;
-
- bool kill_processes;
-
- LIST_FIELDS(Session, sessions_by_user);
- LIST_FIELDS(Session, sessions_by_seat);
-};
-
-typedef enum UserState {
- USER_OFFLINE,
- USER_LINGERING,
- USER_ONLINE,
- USER_ACTIVE,
- _USER_STATE_MAX,
- _USER_STATE_INVALID = -1
-} UserState;
-
-struct User {
- Manager *manager;
-
- uid_t uid;
- gid_t gid;
- char *name;
-
- char *state_file;
- char *runtime_path;
- char *service;
- char *cgroup_path;
-
- Session *display;
-
- dual_timestamp timestamp;
-
- LIST_HEAD(Session, sessions);
-};
+#include "logind-device.h"
+#include "logind-seat.h"
+#include "logind-session.h"
+#include "logind-user.h"
struct Manager {
DBusConnection *bus;
@@ -170,39 +78,6 @@ struct Manager {
bool kill_user_processes;
};
-Device* device_new(Manager *m, const char *sysfs);
-void device_free(Device *d);
-void device_attach(Device *d, Seat *s);
-void device_detach(Device *d);
-
-Seat *seat_new(Manager *m, const char *id);
-void seat_free(Seat *s);
-int seat_preallocate_vts(Seat *s);
-void seat_active_vt_changed(Seat *s, int vtnr);
-int seat_apply_acls(Seat *s);
-int seat_stop(Seat *s);
-int seat_save(Seat *s);
-int seat_load(Seat *s);
-
-Session *session_new(Manager *m, User *u, const char *id);
-void session_free(Session *s);
-int session_activate(Session *s);
-bool session_is_active(Session *s);
-int session_check_gc(Session *s);
-int session_start(Session *s);
-int session_stop(Session *s);
-int session_save(Session *s);
-int session_load(Session *s);
-
-User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name);
-void user_free(User *u);
-int user_start(User *u);
-int user_stop(User *u);
-int user_check_gc(User *u);
-UserState user_get_state(User *u);
-int user_save(User *u);
-int user_load(User *u);
-
Manager *manager_new(void);
void manager_free(Manager *m);
int manager_add_device(Manager *m, const char *sysfs, Device **_device);
@@ -224,12 +99,6 @@ int manager_startup(Manager *m);
int manager_run(Manager *m);
int manager_spawn_autovt(Manager *m, int vtnr);
-const char* session_type_to_string(SessionType t);
-SessionType session_type_from_string(const char *s);
-
-const char* user_state_to_string(UserState s);
-UserState user_state_from_string(const char *s);
-
bool x11_display_is_local(const char *display);
#endif
commit 202630822f52e06dce8404633407329c38099278
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon May 23 23:55:06 2011 +0200
logind: first version that compiles fine
diff --git a/.gitignore b/.gitignore
index 5669d74..c2820b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+systemd-logind
systemd-hostnamed
systemd-binfmt
systemd-getty-generator
diff --git a/Makefile.am b/Makefile.am
index 7ca0ae8..79ccbbe 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -158,7 +158,8 @@ rootlibexec_PROGRAMS = \
systemd-ac-power \
systemd-detect-virt \
systemd-sysctl \
- systemd-hostnamed
+ systemd-hostnamed \
+ systemd-logind
if ENABLE_BINFMT
rootlibexec_PROGRAMS += \
@@ -806,6 +807,27 @@ systemd_hostnamed_LDADD = \
libsystemd-daemon.la \
$(DBUS_LIBS)
+systemd_logind_SOURCES = \
+ src/logind.c \
+ src/logind-device.c \
+ src/logind-seat.c \
+ src/logind-session.c \
+ src/logind-user.c \
+ src/dbus-common.c \
+ src/dbus-loop.c \
+ src/cgroup-util.c
+
+systemd_logind_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(DBUS_CFLAGS) \
+ $(UDEV_CFLAGS)
+
+systemd_logind_LDADD = \
+ libsystemd-basic.la \
+ libsystemd-daemon.la \
+ $(DBUS_LIBS) \
+ $(UDEV_LIBS)
+
systemd_shutdown_SOURCES = \
src/mount-setup.c \
src/umount.c \
diff --git a/src/dbus-loop.c b/src/dbus-loop.c
new file mode 100644
index 0000000..8eb1d17
--- /dev/null
+++ b/src/dbus-loop.c
@@ -0,0 +1,263 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <assert.h>
+#include <sys/epoll.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/timerfd.h>
+#include <unistd.h>
+
+#include "dbus-loop.h"
+#include "dbus-common.h"
+#include "util.h"
+
+/* Minimal implementation of the dbus loop which integrates all dbus
+ * events into a single epoll fd which we can triviall integrate with
+ * other loops. Note that this is not used in the main systemd daemon
+ * since we run a more elaborate mainloop there. */
+
+typedef struct EpollData {
+ int fd;
+ void *object;
+ bool is_timeout:1;
+ bool fd_is_dupped:1;
+} EpollData;
+
+static dbus_bool_t add_watch(DBusWatch *watch, void *data) {
+ EpollData *e;
+ struct epoll_event ev;
+
+ assert(watch);
+
+ e = new0(EpollData, 1);
+ if (!e)
+ return FALSE;
+
+ e->fd = dbus_watch_get_unix_fd(watch);
+ e->object = watch;
+ e->is_timeout = false;
+
+ zero(ev);
+ ev.events = bus_flags_to_events(watch);
+ ev.data.ptr = e;
+
+ if (epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_ADD, e->fd, &ev) < 0) {
+
+ if (errno != EEXIST) {
+ free(e);
+ return FALSE;
+ }
+
+ /* Hmm, bloody D-Bus creates multiple watches on the
+ * same fd. epoll() does not like that. As a dirty
+ * hack we simply dup() the fd and hence get a second
+ * one we can safely add to the epoll(). */
+
+ e->fd = dup(e->fd);
+ if (e->fd < 0) {
+ free(e);
+ return FALSE;
+ }
+
+ if (epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_ADD, e->fd, &ev) < 0) {
+ close_nointr_nofail(e->fd);
+ free(e);
+ return FALSE;
+ }
+
+ e->fd_is_dupped = true;
+ }
+
+ dbus_watch_set_data(watch, e, NULL);
+
+ return TRUE;
+}
+
+static void remove_watch(DBusWatch *watch, void *data) {
+ EpollData *e;
+
+ assert(watch);
+
+ e = dbus_watch_get_data(watch);
+ if (!e)
+ return;
+
+ assert_se(epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_DEL, e->fd, NULL) >= 0);
+
+ if (e->fd_is_dupped)
+ close_nointr_nofail(e->fd);
+
+ free(e);
+}
+
+static void toggle_watch(DBusWatch *watch, void *data) {
+ EpollData *e;
+ struct epoll_event ev;
+
+ assert(watch);
+
+ e = dbus_watch_get_data(watch);
+ if (!e)
+ return;
+
+ zero(ev);
+ ev.events = bus_flags_to_events(watch);
+ ev.data.ptr = e;
+
+ assert_se(epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_MOD, e->fd, &ev) == 0);
+}
+
+static int timeout_arm(EpollData *e) {
+ struct itimerspec its;
+
+ assert(e);
+ assert(e->is_timeout);
+
+ zero(its);
+
+ if (dbus_timeout_get_enabled(e->object)) {
+ timespec_store(&its.it_value, dbus_timeout_get_interval(e->object) * USEC_PER_MSEC);
+ its.it_interval = its.it_value;
+ }
+
+ if (timerfd_settime(e->fd, 0, &its, NULL) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) {
+ EpollData *e;
+ struct epoll_event ev;
+
+ assert(timeout);
+
+ e = new0(EpollData, 1);
+ if (!e)
+ return FALSE;
+
+ e->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC);
+ if (e->fd < 0)
+ goto fail;
+
+ e->object = timeout;
+ e->is_timeout = true;
+
+ if (timeout_arm(e) < 0)
+ goto fail;
+
+ zero(ev);
+ ev.events = EPOLLIN;
+ ev.data.ptr = e;
+
+ if (epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_ADD, e->fd, &ev) < 0)
+ goto fail;
+
+ dbus_timeout_set_data(timeout, e, NULL);
+
+ return TRUE;
+
+fail:
+ if (e->fd >= 0)
+ close_nointr_nofail(e->fd);
+
+ free(e);
+ return FALSE;
+}
+
+static void remove_timeout(DBusTimeout *timeout, void *data) {
+ EpollData *e;
+
+ assert(timeout);
+
+ e = dbus_timeout_get_data(timeout);
+ if (!e)
+ return;
+
+ assert_se(epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_DEL, e->fd, NULL) >= 0);
+ close_nointr_nofail(e->fd);
+ free(e);
+}
+
+static void toggle_timeout(DBusTimeout *timeout, void *data) {
+ EpollData *e;
+ int r;
+
+ assert(timeout);
+
+ e = dbus_timeout_get_data(timeout);
+ if (!e)
+ return;
+
+ r = timeout_arm(e);
+ if (r < 0)
+ log_error("Failed to rearm timer: %s", strerror(-r));
+}
+
+int bus_loop_open(DBusConnection *c) {
+ int fd;
+
+ assert(c);
+
+ fd = epoll_create1(EPOLL_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ if (!dbus_connection_set_watch_functions(c, add_watch, remove_watch, toggle_watch, INT_TO_PTR(fd), NULL) ||
+ !dbus_connection_set_timeout_functions(c, add_timeout, remove_timeout, toggle_timeout, INT_TO_PTR(fd), NULL)) {
+ close_nointr_nofail(fd);
+ return -ENOMEM;
+ }
+
+ return fd;
+}
+
+int bus_loop_dispatch(int fd) {
+ int n;
+ struct epoll_event event;
+ EpollData *d;
+
+ assert(fd >= 0);
+
+ zero(event);
+
+ n = epoll_wait(fd, &event, 1, 0);
+ if (n < 0)
+ return errno == EAGAIN || errno == EINTR ? 0 : -errno;
+
+ assert_se(d = event.data.ptr);
+
+ if (d->is_timeout) {
+ DBusTimeout *t = d->object;
+
+ if (dbus_timeout_get_enabled(t))
+ dbus_timeout_handle(t);
+ } else {
+ DBusWatch *w = d->object;
+
+ if (dbus_watch_get_enabled(w))
+ dbus_watch_handle(w, bus_events_to_flags(event.events));
+ }
+
+ return 0;
+}
diff --git a/src/dbus-loop.h b/src/dbus-loop.h
new file mode 100644
index 0000000..0bbdfe5
--- /dev/null
+++ b/src/dbus-loop.h
@@ -0,0 +1,30 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foodbusloophfoo
+#define foodbusloophfoo
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+int bus_loop_open(DBusConnection *c);
+int bus_loop_dispatch(int fd);
+
+#endif
diff --git a/src/logind-device.c b/src/logind-device.c
new file mode 100644
index 0000000..9084b5f
--- /dev/null
+++ b/src/logind-device.c
@@ -0,0 +1,85 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <string.h>
+
+#include "logind.h"
+#include "util.h"
+
+Device* device_new(Manager *m, const char *sysfs) {
+ Device *d;
+
+ assert(m);
+ assert(sysfs);
+
+ d = new0(Device, 1);
+ if (!d)
+ return NULL;
+
+ d->sysfs = strdup(sysfs);
+ if (!d->sysfs) {
+ free(d);
+ return NULL;
+ }
+
+ if (hashmap_put(m->devices, d->sysfs, d) < 0) {
+ free(d->sysfs);
+ free(d);
+ return NULL;
+ }
+
+ d->manager = m;
+ dual_timestamp_get(&d->timestamp);
+
+ return d;
+}
+
+void device_free(Device *d) {
+ assert(d);
+
+ device_detach(d);
+
+ hashmap_remove(d->manager->devices, d->sysfs);
+
+ free(d->sysfs);
+ free(d);
+}
+
+void device_detach(Device *d) {
+ assert(d);
+
+ if (d->seat)
+ LIST_REMOVE(Device, devices, d->seat->devices, d);
+
+ d->seat = NULL;
+}
+
+void device_attach(Device *d, Seat *s) {
+ assert(d);
+ assert(s);
+
+ if (d->seat)
+ device_detach(d);
+
+ LIST_PREPEND(Device, devices, d->seat->devices, d);
+ d->seat = s;
+}
diff --git a/src/logind-seat.c b/src/logind-seat.c
new file mode 100644
index 0000000..dcf1c71
--- /dev/null
+++ b/src/logind-seat.c
@@ -0,0 +1,245 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/vt.h>
+
+#include "logind.h"
+#include "util.h"
+
+Seat *seat_new(Manager *m, const char *id) {
+ Seat *s;
+
+ assert(m);
+ assert(id);
+
+ s = new0(Seat, 1);
+ if (!s)
+ return NULL;
+
+ s->state_file = strappend("/run/systemd/seat/", id);
+ if (!s->state_file) {
+ free(s);
+ return NULL;
+ }
+
+ s->id = file_name_from_path(s->state_file);
+
+ if (hashmap_put(m->seats, s->id, s) < 0) {
+ free(s->id);
+ free(s);
+ return NULL;
+ }
+
+ s->manager = m;
+
+ return s;
+}
+
+void seat_free(Seat *s) {
+ assert(s);
+
+ while (s->sessions)
+ session_free(s->sessions);
+
+ assert(!s->active);
+
+ while (s->devices)
+ device_free(s->devices);
+
+ hashmap_remove(s->manager->seats, s->id);
+
+ free(s->state_file);
+ free(s);
+}
+
+int seat_save(Seat *s) {
+ FILE *f;
+ int r;
+
+ assert(s);
+
+ r = safe_mkdir("/run/systemd/seat", 0755, 0, 0);
+ if (r < 0)
+ return r;
+
+ f = fopen(s->state_file, "we");
+ if (!f)
+ return -errno;
+
+ fprintf(f,
+ "IS_VTCONSOLE=%i\n",
+ s->manager->vtconsole == s);
+
+ if (s->active) {
+ assert(s->active->user);
+
+ fprintf(f,
+ "ACTIVE=%s\n"
+ "ACTIVE_UID=%lu\n",
+ s->active->id,
+ (unsigned long) s->active->user->uid);
+ }
+
+ if (s->sessions) {
+ Session *i;
+ fputs("OTHER_UIDS=", f);
+
+ LIST_FOREACH(sessions_by_seat, i, s->sessions) {
+ assert(i->user);
+
+ if (i == s->active)
+ continue;
+
+ fprintf(f,
+ "%s%lu",
+ i == s->sessions ? "" : " ",
+ (unsigned long) i->user->uid);
+ }
+ }
+
+ fflush(f);
+ if (ferror(f)) {
+ r = -errno;
+ unlink(s->state_file);
+ }
+
+ fclose(f);
+ return r;
+}
+
+int seat_load(Seat *s) {
+ assert(s);
+
+ return 0;
+}
+
+static int vt_allocate(int vtnr) {
+ int fd, r;
+ char *p;
+
+ assert(vtnr >= 1);
+
+ if (asprintf(&p, "/dev/tty%i", vtnr) < 0)
+ return -ENOMEM;
+
+ fd = open_terminal(p, O_RDWR|O_NOCTTY|O_CLOEXEC);
+ free(p);
+
+ r = fd < 0 ? -errno : 0;
+
+ if (fd >= 0)
+ close_nointr_nofail(fd);
+
+ return r;
+}
+
+int seat_preallocate_vts(Seat *s) {
+ int i, r = 0;
+
+ assert(s);
+ assert(s->manager);
+
+ if (s->manager->n_autovts <= 0)
+ return 0;
+
+ if (s->manager->vtconsole != s)
+ return 0;
+
+ for (i = 1; i < s->manager->n_autovts; i++) {
+ int q;
+
+ q = vt_allocate(i);
+ if (r >= 0 && q < 0)
+ r = q;
+ }
+
+ return r;
+}
+
+int seat_apply_acls(Seat *s) {
+ assert(s);
+
+
+ return 0;
+}
+
+static int vt_is_busy(int vtnr) {
+ struct vt_stat vt_stat;
+ int r = 0, fd;
+
+ assert(vtnr >= 1);
+
+ fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
+ r = -errno;
+ else
+ r = !!(vt_stat.v_state & (1 << vtnr));
+
+ close_nointr_nofail(fd);
+
+ return r;
+}
+
+void seat_active_vt_changed(Seat *s, int vtnr) {
+ Session *i;
+
+ assert(s);
+ assert(vtnr >= 1);
+ assert(s->manager->vtconsole == s);
+
+ s->active = NULL;
+
+ LIST_FOREACH(sessions_by_seat, i, s->sessions)
+ if (i->vtnr == vtnr) {
+ s->active = i;
+ break;
+ }
+
+ seat_apply_acls(s);
+
+ if (vt_is_busy(vtnr) == 0)
+ manager_spawn_autovt(s->manager, vtnr);
+}
+
+int seat_stop(Seat *s) {
+ Session *session;
+ int r = 0;
+
+ assert(s);
+
+ LIST_FOREACH(sessions_by_seat, session, s->sessions) {
+ int k;
+
+ k = session_stop(session);
+ if (k < 0)
+ r = k;
+ }
+
+ return r;
+}
diff --git a/src/logind-session.c b/src/logind-session.c
new file mode 100644
index 0000000..9af99d0
--- /dev/null
+++ b/src/logind-session.c
@@ -0,0 +1,472 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "logind.h"
+#include "strv.h"
+#include "util.h"
+#include "cgroup-util.h"
+
+Session* session_new(Manager *m, User *u, const char *id) {
+ Session *s;
+
+ assert(m);
+ assert(id);
+
+ s = new(Session, 1);
+ if (!s)
+ return NULL;
+
+ s->state_file = strappend("/run/systemd/session/", id);
+ if (!s->state_file) {
+ free(s);
+ return NULL;
+ }
+
+ s->id = file_name_from_path(s->state_file);
+
+ if (hashmap_put(m->sessions, s->id, s) < 0) {
+ free(s->id);
+ free(s);
+ return NULL;
+ }
+
+ s->manager = m;
+ s->pipe_fd = -1;
+ s->user = u;
+
+ dual_timestamp_get(&s->timestamp);
+
+ return s;
+}
+
+void session_free(Session *s) {
+ assert(s);
+
+ if (s->user) {
+ LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
+
+ if (s->user->display == s)
+ s->user->display = NULL;
+ }
+
+ if (s->seat)
+ LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
+
+ free(s->cgroup_path);
+ strv_free(s->controllers);
+
+ free(s->tty);
+ free(s->display);
+ free(s->remote_host);
+
+ hashmap_remove(s->manager->sessions, s->id);
+
+ free(s->state_file);
+ free(s);
+}
+
+int session_save(Session *s) {
+ FILE *f;
+ int r = 0;
+
+ assert(s);
+
+ r = safe_mkdir("/run/systemd/session", 0755, 0, 0);
+ if (r < 0)
+ return r;
+
+ f = fopen(s->state_file, "we");
+ if (!f)
+ return -errno;
+
+ assert(s->user);
+
+ fprintf(f,
+ "# This is private data. Do not parse.\n"
+ "UID=%lu\n"
+ "USER=%s\n"
+ "ACTIVE=%i\n"
+ "REMOTE=%i\n"
+ "KILL_PROCESSES=%i\n",
+ (unsigned long) s->user->uid,
+ s->user->name,
+ session_is_active(s),
+ s->remote,
+ s->kill_processes);
+
+ if (s->cgroup_path)
+ fprintf(f,
+ "CGROUP=%s\n",
+ s->cgroup_path);
+
+ if (s->seat)
+ fprintf(f,
+ "SEAT=%s\n",
+ s->seat->id);
+
+ if (s->tty)
+ fprintf(f,
+ "TTY=%s\n",
+ s->tty);
+
+ if (s->display)
+ fprintf(f,
+ "DISPLAY=%s\n",
+ s->display);
+
+ if (s->remote_host)
+ fprintf(f,
+ "REMOTE_HOST=%s\n",
+ s->remote_host);
+
+ if (s->seat && s->seat->manager->vtconsole == s->seat)
+ fprintf(f,
+ "VTNR=%i\n",
+ s->vtnr);
+
+ if (s->leader > 0)
+ fprintf(f,
+ "LEADER=%lu\n",
+ (unsigned long) s->leader);
+
+ if (s->audit_id > 0)
+ fprintf(f,
+ "AUDIT=%llu\n",
+ (unsigned long long) s->audit_id);
+
+ fflush(f);
+ if (ferror(f)) {
+ r = -errno;
+ unlink(s->state_file);
+ }
+
+ fclose(f);
+ return r;
+}
+
+int session_load(Session *s) {
+ assert(s);
+
+ return 0;
+}
+
+int session_activate(Session *s) {
+ int r;
+
+ assert(s);
+
+ if (s->vtnr < 0)
+ return -ENOTSUP;
+
+ if (!s->seat)
+ return -ENOTSUP;
+
+ if (s->seat->active == s)
+ return 0;
+
+ assert(s->manager->vtconsole == s->seat);
+
+ r = chvt(s->vtnr);
+ if (r < 0)
+ return r;
+
+ s->seat->active = s;
+
+ return seat_apply_acls(s->seat);
+}
+
+bool x11_display_is_local(const char *display) {
+ assert(display);
+
+ return
+ display[0] == ':' &&
+ display[1] >= '0' &&
+ display[1] <= '9';
+}
+
+static int session_link_x11_socket(Session *s) {
+ char *t, *f, *c;
+ size_t k;
+
+ assert(s);
+ assert(s->user);
+ assert(s->user->runtime_path);
+
+ if (s->user->display)
+ return 0;
+
+ if (!s->display || !x11_display_is_local(s->display))
+ return 0;
+
+ k = strspn(s->display+1, "0123456789");
+ f = new(char, sizeof("/tmp/.X11-unix/X") + k);
+ if (!f) {
+ log_error("Out of memory");
+ return -ENOMEM;
+ }
+
+ c = stpcpy(f, "/tmp/.X11-unix/X");
+ memcpy(c, s->display+1, k);
+ c[k] = 0;
+
+ if (access(f, F_OK) < 0) {
+ log_warning("Session %s has display %s with nonexisting socket %s.", s->id, s->display, f);
+ free(f);
+ return -ENOENT;
+ }
+
+ t = strappend(s->user->runtime_path, "/display");
+ if (!t) {
+ log_error("Out of memory");
+ free(f);
+ return -ENOMEM;
+ }
+
+ if (link(f, t) < 0) {
+ if (errno == EEXIST) {
+ unlink(t);
+
+ if (link(f, t) >= 0)
+ goto done;
+ }
+
+ if (symlink(f, t) < 0) {
+
+ if (errno == EEXIST) {
+ unlink(t);
+
+ if (symlink(f, t) >= 0)
+ goto done;
+ }
+
+ log_error("Failed to link %s to %s: %m", f, t);
+ free(f);
+ free(t);
+ return -errno;
+ }
+ }
+
+done:
+ log_info("Linked %s to %s.", f, t);
+ free(f);
+ free(t);
+
+ s->user->display = s;
+
+ return 0;
+}
+
+static int session_create_cgroup(Session *s) {
+ char **k;
+ char *p;
+ int r;
+
+ assert(s);
+ assert(s->user);
+ assert(s->user->cgroup_path);
+
+ if (!s->cgroup_path) {
+ if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0) {
+ log_error("Out of memory");
+ return -ENOMEM;
+ }
+ } else
+ p = s->cgroup_path;
+
+ if (s->leader > 0)
+ r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, p, s->leader);
+ else
+ r = cg_create(SYSTEMD_CGROUP_CONTROLLER, p);
+
+ if (r < 0) {
+ free(p);
+ s->cgroup_path = NULL;
+ log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
+ return r;
+ }
+
+ s->cgroup_path = p;
+
+ STRV_FOREACH(k, s->manager->controllers) {
+ if (s->leader > 0)
+ r = cg_create_and_attach(*k, p, s->leader);
+ else
+ r = cg_create(*k, p);
+
+ if (r < 0)
+ log_warning("Failed to create cgroup %s:%s: %s", *k, p, strerror(-r));
+ }
+
+ return 0;
+}
+
+int session_start(Session *s) {
+ int r;
+
+ assert(s);
+ assert(s->user);
+
+ /* Create user first */
+ r = user_start(s->user);
+ if (r < 0)
+ return r;
+
+ /* Create cgroup */
+ r = session_create_cgroup(s);
+ if (r < 0)
+ return r;
+
+ /* Create X11 symlink */
+ session_link_x11_socket(s);
+ return 0;
+}
+
+static bool session_shall_kill(Session *s) {
+ assert(s);
+
+ return s->kill_processes;
+}
+
+static int session_kill_cgroup(Session *s) {
+ int r;
+ char **k;
+
+ assert(s);
+
+ if (!s->cgroup_path)
+ return 0;
+
+ cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
+
+ if (session_shall_kill(s)) {
+
+ r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
+ if (r < 0)
+ log_error("Failed to kill session cgroup: %s", strerror(-r));
+
+ } else {
+ r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
+ if (r < 0)
+ log_error("Failed to check session cgroup: %s", strerror(-r));
+ else if (r > 0) {
+ r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
+ if (r < 0)
+ log_error("Failed to delete session cgroup: %s", strerror(-r));
+ } else
+ r = -EBUSY;
+ }
+
+ STRV_FOREACH(k, s->user->manager->controllers)
+ cg_trim(*k, s->cgroup_path, true);
+
+ free(s->cgroup_path);
+ s->cgroup_path = NULL;
+
+ return r;
+}
+
+static int session_unlink_x11_socket(Session *s) {
+ char *t;
+ int r;
+
+ assert(s);
+ assert(s->user);
+
+ if (s->user->display != s)
+ return 0;
+
+ s->user->display = NULL;
+
+ t = strappend(s->user->runtime_path, "/display");
+ if (!t) {
+ log_error("Out of memory");
+ return -ENOMEM;
+ }
+
+ r = unlink(t);
+ free(t);
+
+ return r < 0 ? -errno : 0;
+}
+
+int session_stop(Session *s) {
+ int r = 0, k;
+
+ assert(s);
+
+ /* Kill cgroup */
+ k = session_kill_cgroup(s);
+ if (k < 0)
+ r = k;
+
+ /* Remove X11 symlink */
+ session_unlink_x11_socket(s);
+
+ return r;
+}
+
+bool session_is_active(Session *s) {
+ assert(s);
+
+ if (!s->seat)
+ return true;
+
+ return s->seat->active == s;
+}
+
+int session_check_gc(Session *s) {
+ int r;
+
+ assert(s);
+
+ if (s->pipe_fd >= 0) {
+
+ r = pipe_eof(s->pipe_fd);
+ if (r < 0)
+ return r;
+
+ if (r <= 0)
+ return 1;
+ }
+
+ if (s->cgroup_path) {
+
+ r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
+ if (r < 0)
+ return r;
+
+ if (r <= 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+static const char* const session_type_table[_SESSION_TYPE_MAX] = {
+ [SESSION_TERMINAL] = "terminal",
+ [SESSION_X11] = "x11"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
diff --git a/src/logind-user.c b/src/logind-user.c
new file mode 100644
index 0000000..1292eed
--- /dev/null
+++ b/src/logind-user.c
@@ -0,0 +1,420 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "logind.h"
+#include "util.h"
+#include "cgroup-util.h"
+#include "hashmap.h"
+#include "strv.h"
+
+User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
+ User *u;
+
+ assert(m);
+ assert(name);
+
+ u = new(User, 1);
+ if (!u)
+ return NULL;
+
+ u->name = strdup(name);
+ if (!u->name) {
+ free(u);
+ return NULL;
+ }
+
+ if (asprintf(&u->state_file, "/run/systemd/user/%lu", (unsigned long) uid) < 0) {
+ free(u->name);
+ free(u);
+ return NULL;
+ }
+
+ if (hashmap_put(m->users, ULONG_TO_PTR((unsigned long) uid), u) < 0) {
+ free(u->state_file);
+ free(u->name);
+ free(u);
+ return NULL;
+ }
+
+ u->manager = m;
+ u->uid = uid;
+ u->gid = gid;
+
+ return u;
+}
+
+void user_free(User *u) {
+ assert(u);
+
+ while (u->sessions)
+ session_free(u->sessions);
+
+ free(u->cgroup_path);
+
+ free(u->service);
+ free(u->runtime_path);
+
+ hashmap_remove(u->manager->users, ULONG_TO_PTR((unsigned long) u->uid));
+
+ free(u->name);
+ free(u->state_file);
+ free(u);
+}
+
+int user_save(User *u) {
+ FILE *f;
+ int r;
+
+ assert(u);
+ assert(u->state_file);
+
+ r = safe_mkdir("/run/systemd/user", 0755, 0, 0);
+ if (r < 0)
+ return r;
+
+ f = fopen(u->state_file, "we");
+ if (!f)
+ return -errno;
+
+ fprintf(f,
+ "NAME=%s\n"
+ "STATE=%s\n",
+ u->name,
+ user_state_to_string(user_get_state(u)));
+
+ if (u->cgroup_path)
+ fprintf(f,
+ "CGROUP=%s\n",
+ u->cgroup_path);
+
+ if (u->runtime_path)
+ fprintf(f,
+ "RUNTIME=%s\n",
+ u->runtime_path);
+
+ if (u->service)
+ fprintf(f,
+ "SERVICE=%s\n",
+ u->service);
+
+ if (u->display)
+ fprintf(f,
+ "DISPLAY=%s\n",
+ u->display->id);
+
+ fflush(f);
+ if (ferror(f)) {
+ r = -errno;
+ unlink(u->state_file);
+ }
+
+ fclose(f);
+ return r;
+}
+
+int user_load(User *u) {
+ int r;
+ char *display = NULL;
+ Session *s;
+
+ assert(u);
+
+ r = parse_env_file(u->state_file, "r",
+ "CGROUP", &u->cgroup_path,
+ "RUNTIME", &u->runtime_path,
+ "SERVICE", &u->service,
+ "DISPLAY", &display,
+ NULL);
+ if (r < 0) {
+ free(display);
+
+ if (r == -ENOENT)
+ return 0;
+
+ log_error("Failed to read %s: %s", u->state_file, strerror(-r));
+ return r;
+ }
+
+ s = hashmap_get(u->manager->sessions, display);
+ free(display);
+
+ if (s && s->display && x11_display_is_local(s->display))
+ u->display = s;
+
+ return r;
+}
+
+static int user_mkdir_runtime_path(User *u) {
+ char *p;
+ int r;
+
+ assert(u);
+
+ r = safe_mkdir("/run/user", 0755, 0, 0);
+ if (r < 0) {
+ log_error("Failed to create /run/user: %s", strerror(-r));
+ return r;
+ }
+
+ if (!u->runtime_path) {
+ p = strappend("/run/user/", u->name);
+
+ if (!p) {
+ log_error("Out of memory");
+ return -ENOMEM;
+ }
+ } else
+ p = u->runtime_path;
+
+ r = safe_mkdir(p, 0700, u->uid, u->gid);
+ if (r < 0) {
+ log_error("Failed to create runtime directory %s: %s", p, strerror(-r));
+ free(p);
+ u->runtime_path = NULL;
+ return r;
+ }
+
+ u->runtime_path = p;
+ return 0;
+}
+
+static int user_create_cgroup(User *u) {
+ char **k;
+ char *p;
+ int r;
+
+ assert(u);
+
+ if (!u->cgroup_path) {
+ if (asprintf(&p, "%s/%s", u->manager->cgroup_path, u->name) < 0) {
+ log_error("Out of memory");
+ return -ENOMEM;
+ }
+ } else
+ p = u->cgroup_path;
+
+ r = cg_create(SYSTEMD_CGROUP_CONTROLLER, p);
+ if (r < 0) {
+ free(p);
+ u->cgroup_path = NULL;
+ log_error("Failed to create cgroup "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
+ return r;
+ }
+
+ u->cgroup_path = p;
+
+ STRV_FOREACH(k, u->manager->controllers) {
+ r = cg_create(*k, p);
+ if (r < 0)
+ log_warning("Failed to create cgroup %s:%s: %s", *k, p, strerror(-r));
+ }
+
+ return 0;
+}
+
+static int user_start_service(User *u) {
+ assert(u);
+
+ return 0;
+}
+
+int user_start(User *u) {
+ int r;
+
+ assert(u);
+
+ /* Make XDG_RUNTIME_DIR */
+ r = user_mkdir_runtime_path(u);
+ if (r < 0)
+ return r;
+
+ /* Create cgroup */
+ r = user_create_cgroup(u);
+ if (r < 0)
+ return r;
+
+ /* Spawn user systemd */
+ r = user_start_service(u);
+ if (r < 0)
+ return r;
+
+ dual_timestamp_get(&u->timestamp);
+
+ return 0;
+}
+
+static int user_stop_service(User *u) {
+ assert(u);
+
+ if (!u->service)
+ return 0;
+
+ return 0;
+}
+
+static int user_shall_kill(User *u) {
+ assert(u);
+
+ return u->manager->kill_user_processes;
+}
+
+static int user_kill_cgroup(User *u) {
+ int r;
+ char **k;
+
+ assert(u);
+
+ if (!u->cgroup_path)
+ return 0;
+
+ cg_trim(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, false);
+
+ if (user_shall_kill(u)) {
+
+ r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
+ if (r < 0)
+ log_error("Failed to kill user cgroup: %s", strerror(-r));
+ } else {
+
+ r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
+ if (r < 0)
+ log_error("Failed to check user cgroup: %s", strerror(-r));
+ else if (r > 0) {
+ r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
+ if (r < 0)
+ log_error("Failed to delete user cgroup: %s", strerror(-r));
+ } else
+ r = -EBUSY;
+ }
+
+ STRV_FOREACH(k, u->manager->controllers)
+ cg_trim(*k, u->cgroup_path, true);
+
+ free(u->cgroup_path);
+ u->cgroup_path = NULL;
+
+ return r;
+}
+
+static int user_remove_runtime_path(User *u) {
+ int r;
+
+ assert(u);
+
+ if (!u->runtime_path)
+ return 0;
+
+ r = rm_rf(u->runtime_path, false, true);
+ if (r < 0)
+ log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
+
+ free(u->runtime_path);
+ u->runtime_path = NULL;
+
+ return r;
+}
+
+int user_stop(User *u) {
+ Session *s;
+ int r = 0, k;
+ assert(u);
+
+ LIST_FOREACH(sessions_by_user, s, u->sessions) {
+ k = session_stop(s);
+ if (k < 0)
+ r = k;
+ }
+
+ /* Kill systemd */
+ k = user_stop_service(u);
+ if (k < 0)
+ r = k;
+
+ /* Kill cgroup */
+ k = user_kill_cgroup(u);
+ if (k < 0)
+ r = k;
+
+ /* Kill XDG_RUNTIME_DIR */
+ k = user_remove_runtime_path(u);
+ if (k < 0)
+ r = k;
+
+ return r;
+}
+
+int user_check_gc(User *u) {
+ int r;
+ char *p;
+
+ assert(u);
+
+ if (u->sessions)
+ return 1;
+
+ if (asprintf(&p, "/var/lib/systemd/linger/%s", u->name) < 0)
+ return -ENOMEM;
+
+ r = access(p, F_OK) >= 0;
+ free(p);
+
+ if (r > 0)
+ return 1;
+
+ if (u->cgroup_path) {
+ r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, false);
+ if (r < 0)
+ return r;
+
+ if (r <= 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+UserState user_get_state(User *u) {
+ Session *i;
+
+ assert(u);
+
+ if (!u->sessions)
+ return USER_LINGERING;
+
+ LIST_FOREACH(sessions_by_user, i, u->sessions)
+ if (session_is_active(i))
+ return USER_ACTIVE;
+
+ return USER_ONLINE;
+}
+
+static const char* const user_state_table[_USER_STATE_MAX] = {
+ [USER_OFFLINE] = "offline",
+ [USER_LINGERING] = "lingering",
+ [USER_ONLINE] = "online",
+ [USER_ACTIVE] = "active"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
diff --git a/src/logind.c b/src/logind.c
new file mode 100644
index 0000000..0c26aad
--- /dev/null
+++ b/src/logind.c
@@ -0,0 +1,886 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <pwd.h>
+#include <libudev.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+
+#include "logind.h"
+#include "dbus-common.h"
+#include "dbus-loop.h"
+
+enum {
+ FD_UDEV,
+ FD_CONSOLE,
+ FD_BUS
+};
+
+Manager *manager_new(void) {
+ Manager *m;
+
+ m = new0(Manager, 1);
+ if (!m)
+ return NULL;
+
+ m->console_active_fd = -1;
+ m->bus_fd = -1;
+ m->udev_fd = -1;
+ m->epoll_fd = -1;
+ m->n_autovts = 6;
+
+ m->devices = hashmap_new(string_hash_func, string_compare_func);
+ m->seats = hashmap_new(string_hash_func, string_compare_func);
+ m->sessions = hashmap_new(string_hash_func, string_compare_func);
+ m->users = hashmap_new(trivial_hash_func, trivial_compare_func);
+
+ if (!m->devices || !m->seats || !m->sessions || !m->users) {
+ manager_free(m);
+ return NULL;
+ }
+
+ m->udev = udev_new();
+ if (!m->udev) {
+ manager_free(m);
+ return NULL;
+ }
+
+ if (cg_get_user_path(&m->cgroup_path) < 0) {
+ manager_free(m);
+ return NULL;
+ }
+
+ return m;
+}
+
+void manager_free(Manager *m) {
+ Session *session;
+ User *u;
+ Device *d;
+ Seat *s;
+
+ assert(m);
+
+ while ((session = hashmap_first(m->sessions)))
+ session_free(session);
+
+ while ((u = hashmap_first(m->users)))
+ user_free(u);
+
+ while ((d = hashmap_first(m->devices)))
+ device_free(d);
+
+ while ((s = hashmap_first(m->seats)))
+ seat_free(s);
+
+ hashmap_free(m->sessions);
+ hashmap_free(m->users);
+ hashmap_free(m->devices);
+ hashmap_free(m->seats);
+
+ if (m->console_active_fd >= 0)
+ close_nointr_nofail(m->console_active_fd);
+
+ if (m->udev_monitor)
+ udev_monitor_unref(m->udev_monitor);
+
+ if (m->udev)
+ udev_unref(m->udev);
+
+ if (m->bus) {
+ dbus_connection_flush(m->bus);
+ dbus_connection_close(m->bus);
+ dbus_connection_unref(m->bus);
+ }
+
+ if (m->bus_fd >= 0)
+ close_nointr_nofail(m->bus_fd);
+
+ if (m->epoll_fd >= 0)
+ close_nointr_nofail(m->epoll_fd);
+
+ free(m->cgroup_path);
+ free(m);
+}
+
+int manager_add_device(Manager *m, const char *sysfs, Device **_device) {
+ Device *d;
+
+ assert(m);
+ assert(sysfs);
+
+ d = hashmap_get(m->devices, sysfs);
+ if (d) {
+ if (_device)
+ *_device = d;
+
+ return 0;
+ }
+
+ d = device_new(m, sysfs);
+ if (!d)
+ return -ENOMEM;
+
+ if (_device)
+ *_device = d;
+
+ return 0;
+}
+
+int manager_add_seat(Manager *m, const char *id, Seat **_seat) {
+ Seat *s;
+
+ assert(m);
+ assert(id);
+
+ s = hashmap_get(m->seats, id);
+ if (s) {
+ if (_seat)
+ *_seat = s;
+
+ return 0;
+ }
+
+ s = seat_new(m, id);
+ if (!s)
+ return -ENOMEM;
+
+ if (_seat)
+ *_seat = s;
+
+ return 0;
+}
+
+int manager_add_session(Manager *m, User *u, const char *id, Session **_session) {
+ Session *s;
+
+ assert(m);
+ assert(id);
+
+ s = hashmap_get(m->sessions, id);
+ if (s) {
+ if (_session)
+ *_session = s;
+
+ return 0;
+ }
+
+ s = session_new(m, u, id);
+ if (!s)
+ return -ENOMEM;
+
+ if (_session)
+ *_session = s;
+
+ return 0;
+}
+
+int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) {
+ User *u;
+ int r;
+
+ assert(m);
+ assert(name);
+
+ u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
+ if (u) {
+ if (_user)
+ *_user = u;
+
+ return 0;
+ }
+
+ u = user_new(m, uid, gid, name);
+ if (!u)
+ return -ENOMEM;
+
+ r = user_start(u);
+ if (r < 0) {
+ user_stop(u);
+ user_free(u);
+ } else {
+ if (_user)
+ *_user = u;
+ }
+
+ return r;
+}
+
+int manager_add_user_by_name(Manager *m, const char *name, User **_user) {
+ struct passwd *p;
+
+ assert(m);
+ assert(name);
+
+ errno = 0;
+ p = getpwnam(name);
+ if (!p)
+ return errno ? -errno : -ENOENT;
+
+ return manager_add_user(m, p->pw_uid, p->pw_gid, name, _user);
+}
+
+int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) {
+ struct passwd *p;
+
+ assert(m);
+
+ errno = 0;
+ p = getpwuid(uid);
+ if (!p)
+ return errno ? -errno : -ENOENT;
+
+ return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user);
+}
+
+int manager_process_device(Manager *m, struct udev_device *d) {
+ const char *sn;
+ Seat *seat;
+ Device *device;
+ int r;
+
+ assert(m);
+
+ sn = udev_device_get_property_value(d, "SEAT");
+ if (!sn)
+ sn = "seat0";
+
+ r = manager_add_device(m, udev_device_get_syspath(d), &device);
+ if (r < 0)
+ return r;
+
+ r = manager_add_seat(m, sn, &seat);
+ if (r < 0)
+ return r;
+
+ device_attach(device, seat);
+ return 0;
+}
+
+int manager_enumerate_devices(Manager *m) {
+ struct udev_list_entry *item = NULL, *first = NULL;
+ struct udev_enumerate *e;
+ int r = -ENOMEM;
+
+ assert(m);
+
+ /* Loads devices from udev and creates seats for them as
+ * necessary */
+
+ e = udev_enumerate_new(m->udev);
+ if (!e)
+ return -ENOMEM;
+
+ if (udev_enumerate_add_match_subsystem(e, "graphics") < 0)
+ goto finish;
+
+ if (udev_enumerate_add_match_tag(e, "seat") < 0)
+ goto finish;
+
+ if (udev_enumerate_scan_devices(e) < 0)
+ goto finish;
+
+ first = udev_enumerate_get_list_entry(e);
+ udev_list_entry_foreach(item, first) {
+ struct udev_device *d;
+ int k;
+
+ d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
+ if (!d)
+ goto finish;
+
+ k = manager_process_device(m, d);
+ udev_device_unref(d);
+
+ if (k < 0)
+ r = k;
+ }
+
+finish:
+ if (e)
+ udev_enumerate_unref(e);
+
+ return r;
+}
+
+int manager_enumerate_seats(Manager *m) {
+ DIR *d;
+ struct dirent *de;
+ int r = 0;
+
+ assert(m);
+
+ /* This loads data about seats stored on disk, but does not
+ * actually create any seats. Removes data of seats that no
+ * longer exist. */
+
+ d = opendir("/run/systemd/seats");
+ if (!d) {
+ if (errno == ENOENT)
+ return 0;
+
+ log_error("Failed to open /run/systemd/seats: %m");
+ return -errno;
+ }
+
+ while ((de = readdir(d))) {
+ Seat *s;
+ int k;
+
+ if (!dirent_is_file(de))
+ continue;
+
+ s = hashmap_get(m->seats, de->d_name);
+ if (!s) {
+ unlinkat(dirfd(d), de->d_name, 0);
+ continue;
+ }
+
+ k = seat_load(s);
+ if (k < 0)
+ r = k;
+ }
+
+ closedir(d);
+
+ return r;
+}
+
+static int manager_enumerate_users_from_cgroup(Manager *m) {
+ int r = 0;
+ char *name;
+ DIR *d;
+
+ r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, &d);
+ if (r < 0) {
+ if (r == -ENOENT)
+ return 0;
+
+ log_error("Failed to open %s: %s", m->cgroup_path, strerror(-r));
+ return r;
+ }
+
+ while ((r = cg_read_subgroup(d, &name)) > 0) {
+ User *user;
+
+ r = manager_add_user_by_name(m, name, &user);
+ free(name);
+
+ if (r < 0)
+ break;
+
+ if (user->cgroup_path)
+ continue;
+
+ if (asprintf(&user->cgroup_path, "%s/%s", m->cgroup_path, name) < 0) {
+ r = -ENOMEM;
+ break;
+ }
+ }
+
+ if (d)
+ closedir(d);
+
+ return r;
+}
+
+int manager_enumerate_users(Manager *m) {
+ DIR *d;
+ struct dirent *de;
+ int r;
+
+ assert(m);
+
+ r = manager_enumerate_users_from_cgroup(m);
+
+ d = opendir("/run/systemd/users");
+ if (!d) {
+ if (errno == ENOENT)
+ return 0;
+
+ log_error("Failed to open /run/systemd/users: %m");
+ return -errno;
+ }
+
+ while ((de = readdir(d))) {
+ unsigned long ul;
+ User *u;
+ int k;
+
+ if (!dirent_is_file(de))
+ continue;
+
+ k = safe_atolu(de->d_name, &ul);
+ if (k < 0) {
+ log_error("Failed to parse file name %s: %s", de->d_name, strerror(-k));
+ continue;
+ }
+
+ u = hashmap_get(m->users, ULONG_TO_PTR(ul));
+ if (!u) {
+ unlinkat(dirfd(d), de->d_name, 0);
+ continue;
+ }
+
+ k = user_load(u);
+ if (k < 0)
+ r = k;
+ }
+
+ closedir(d);
+
+ return r;
+}
+
+static int manager_enumerate_sessions_from_cgroup(Manager *m) {
+ User *u;
+ Iterator i;
+ int r = 0;
+
+ HASHMAP_FOREACH(u, m->users, i) {
+ DIR *d;
+ char *name;
+ int k;
+
+ k = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, &d);
+ if (k < 0) {
+ if (k == -ENOENT)
+ continue;
+
+ log_error("Failed to open %s: %s", u->cgroup_path, strerror(-k));
+ r = k;
+ continue;
+ }
+
+ while ((k = cg_read_subgroup(d, &name)) > 0) {
+ Session *session;
+
+ k = manager_add_session(m, u, name, &session);
+ free(name);
+
+ if (k < 0)
+ break;
+
+ if (session->cgroup_path)
+ continue;
+
+ if (asprintf(&session->cgroup_path, "%s/%s", u->cgroup_path, name) < 0) {
+ k = -ENOMEM;
+ break;
+ }
+ }
+
+ closedir(d);
+
+ if (k < 0)
+ r = k;
+ }
+
+ return r;
+}
+
+int manager_enumerate_sessions(Manager *m) {
+ DIR *d;
+ struct dirent *de;
+ int r = 0;
+
+ assert(m);
+
+ r = manager_enumerate_sessions_from_cgroup(m);
+
+ d = opendir("/run/systemd/sessions");
+ if (!d) {
+ if (errno == ENOENT)
+ return 0;
+
+ log_error("Failed to open /run/systemd/sessions: %m");
+ return -errno;
+ }
+
+ while ((de = readdir(d))) {
+ struct Session *s;
+ int k;
+
+ if (!dirent_is_file(de))
+ continue;
+
+ s = hashmap_get(m->sessions, de->d_name);
+ if (!s) {
+ unlinkat(dirfd(d), de->d_name, 0);
+ continue;
+ }
+
+ k = session_load(s);
+ if (k < 0)
+ r = k;
+ }
+
+ closedir(d);
+
+ return r;
+}
+
+int manager_start_linger_users(Manager *m) {
+ DIR *d;
+ struct dirent *de;
+ int r = 0;
+
+ d = opendir("/var/lib/systemd/linger");
+ if (!d) {
+ if (errno == ENOENT)
+ return 0;
+
+ log_error("Failed to open /var/lib/systemd/linger/: %m");
+ return -errno;
+ }
+
+ while ((de = readdir(d))) {
+ int k;
+
+ if (!dirent_is_file(de))
+ continue;
+
+ k = manager_add_user_by_name(m, de->d_name, NULL);
+ if (k < 0) {
+ log_notice("Couldn't add lingering user %s: %s", de->d_name, strerror(-k));
+ r = k;
+ }
+ }
+
+ closedir(d);
+
+ return r;
+}
+
+int manager_dispatch_udev(Manager *m) {
+ struct udev_device *d;
+ int r;
+
+ assert(m);
+
+ d = udev_monitor_receive_device(m->udev_monitor);
+ if (!d)
+ return -ENOMEM;
+
+ r = manager_process_device(m, d);
+ udev_device_unref(d);
+
+ return r;
+}
+
+int manager_dispatch_console(Manager *m) {
+ char t[64];
+ ssize_t k;
+ int r, vtnr;
+
+ assert(m);
+
+ lseek(m->console_active_fd, SEEK_SET, 0);
+
+ k = read(m->console_active_fd, t, sizeof(t)-1);
+ if (k <= 0) {
+ log_error("Failed to read current console: %s", k < 0 ? strerror(-errno) : "EOF");
+ return k < 0 ? -errno : -EIO;
+ }
+
+ t[k] = 0;
+ if (!startswith(t, "tty")) {
+ log_error("Hm, /sys/class/tty/tty0/active is badly formatted.");
+ return -EIO;
+ }
+
+ r = safe_atoi(t+3, &vtnr);
+ if (r < 0) {
+ log_error("Failed to parse VT number %s", t+3);
+ return r;
+ }
+
+ if (vtnr <= 0) {
+ log_error("VT number invalid: %s", t+3);
+ return -EIO;
+ }
+
+ if (m->vtconsole)
+ seat_active_vt_changed(m->vtconsole, vtnr);
+
+ return 0;
+}
+
+int manager_spawn_autovt(Manager *m, int vtnr) {
+ assert(m);
+
+ return 0;
+}
+
+static DBusHandlerResult login_message_handler(
+ DBusConnection *connection,
+ DBusMessage *message,
+ void *userdata) {
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult login_message_filter(
+ DBusConnection *connection,
+ DBusMessage *message,
+ void *userdata) {
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static int manager_connect_bus(Manager *m) {
+ const DBusObjectPathVTable login_vtable = {
+ .message_function = login_message_handler
+ };
+
+ DBusError error;
+ int r;
+ struct epoll_event ev;
+
+ assert(m);
+ assert(!m->bus);
+ assert(m->bus_fd < 0);
+
+ dbus_error_init(&error);
+
+ m->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
+ if (!m->bus) {
+ log_error("Failed to get system D-Bus connection: %s", error.message);
+ r = -ECONNREFUSED;
+ goto fail;
+ }
+
+ if (!dbus_connection_register_object_path(m->bus, "/org/freedesktop/login1", &login_vtable, NULL)) {
+ log_error("Not enough memory");
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ if (!dbus_connection_add_filter(m->bus, login_message_filter, m, NULL)) {
+ log_error("Not enough memory");
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ dbus_bus_add_match(m->bus,
+ "type='signal',"
+ "interface='org.freedesktop.systemd1.Agent',"
+ "member='Released',"
+ "path='/org/freedesktop/systemd1/agent'",
+ &error);
+
+ if (dbus_error_is_set(&error)) {
+ log_error("Failed to register match: %s", error.message);
+ r = -EIO;
+ goto fail;
+ }
+
+ if (dbus_bus_request_name(m->bus, "org.freedesktop.login1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) < 0) {
+ log_error("Failed to register name on bus: %s", error.message);
+ r = -EEXIST;
+ goto fail;
+ }
+
+ m->bus_fd = bus_loop_open(m->bus);
+ if (m->bus_fd < 0) {
+ r = m->bus_fd;
+ goto fail;
+ }
+
+ zero(ev);
+ ev.events = EPOLLIN;
+ ev.data.u32 = FD_BUS;
+
+ if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->bus_fd, &ev) < 0)
+ goto fail;
+
+ return 0;
+
+fail:
+ dbus_error_free(&error);
+
+ return r;
+}
+
+static int manager_connect_console(Manager *m) {
+ struct epoll_event ev;
+
+ assert(m);
+ assert(m->console_active_fd < 0);
+
+ m->console_active_fd = open("/sys/class/tty/tty0/active", O_RDONLY|O_NOCTTY|O_CLOEXEC);
+ if (m->console_active_fd < 0) {
+ log_error("Failed to open /sys/class/tty/tty0/active: %m");
+ return -errno;
+ }
+
+ zero(ev);
+ ev.events = EPOLLIN;
+ ev.data.u32 = FD_CONSOLE;
+
+ if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->console_active_fd, &ev) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static int manager_connect_udev(Manager *m) {
+ struct epoll_event ev;
+
+ assert(m);
+ assert(!m->udev_monitor);
+
+ m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
+ if (!m->udev_monitor)
+ return -ENOMEM;
+
+ udev_monitor_filter_add_match_tag(m->udev_monitor, "seat");
+
+ if (udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "graphics", NULL) < 0)
+ return -ENOMEM;
+
+ if (udev_monitor_enable_receiving(m->udev_monitor) < 0)
+ return -ENOMEM;
+
+ m->udev_fd = udev_monitor_get_fd(m->udev_monitor);
+
+ zero(ev);
+ ev.events = EPOLLIN;
+ ev.data.u32 = FD_UDEV;
+
+ if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_fd, &ev) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int manager_startup(Manager *m) {
+ int r;
+
+ assert(m);
+ assert(m->epoll_fd <= 0);
+
+ m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+ if (m->epoll_fd < 0)
+ return -errno;
+
+ /* Connect to udev */
+ r = manager_connect_udev(m);
+ if (r < 0)
+ return r;
+
+ /* Connect to console */
+ r = manager_connect_console(m);
+ if (r < 0)
+ return r;
+
+ /* Connect to the bus */
+ r = manager_connect_bus(m);
+ if (r < 0)
+ return r;
+
+ /* Deserialize state */
+ manager_enumerate_devices(m);
+ manager_enumerate_seats(m);
+ manager_enumerate_users(m);
+ manager_enumerate_sessions(m);
+
+ /* Spawn lingering users */
+ manager_start_linger_users(m);
+
+ return 0;
+}
+
+int manager_run(Manager *m) {
+ assert(m);
+
+ for (;;) {
+ struct epoll_event event;
+ int n;
+
+ if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE)
+ continue;
+
+ n = epoll_wait(m->epoll_fd, &event, 1, -1);
+ if (n < 0) {
+ log_error("epoll() failed: %m");
+ return -errno;
+ }
+
+ switch (event.data.u32) {
+
+ case FD_UDEV:
+ manager_dispatch_udev(m);
+ break;
+
+ case FD_CONSOLE:
+ manager_dispatch_console(m);
+ break;
+
+ case FD_BUS:
+ bus_loop_dispatch(m->bus_fd);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ Manager *m = NULL;
+ int r = 0;
+
+ log_set_target(LOG_TARGET_AUTO);
+ log_parse_environment();
+ log_open();
+
+ if (argc != 1) {
+ log_error("This program takes no arguments.");
+ r = -EINVAL;
+ goto finish;
+ }
+
+ umask(0022);
+
+ m = manager_new();
+ if (!m) {
+ log_error("Out of memory");
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ r = manager_startup(m);
+ if (r < 0) {
+ log_error("Failed to fully start up daemon: %s", strerror(-r));
+ goto finish;
+ }
+
+ r = manager_run(m);
+
+finish:
+ if (m)
+ manager_free(m);
+
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/src/logind.h b/src/logind.h
new file mode 100644
index 0000000..5e69a71
--- /dev/null
+++ b/src/logind.h
@@ -0,0 +1,235 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foologindhfoo
+#define foologindhfoo
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <inttypes.h>
+#include <dbus/dbus.h>
+#include <libudev.h>
+
+#include "util.h"
+#include "list.h"
+#include "hashmap.h"
+#include "cgroup-util.h"
+
+/* TODO:
+ *
+ * recreate VTs when disallocated
+ * udev rules
+ * spawn user systemd
+ * non-local X11 server
+ * udev-acl
+ * reboot/shutdown halt management
+ * PAM rewrite
+ */
+
+typedef struct Manager Manager;
+typedef struct Device Device;
+typedef struct Seat Seat;
+typedef struct Session Session;
+typedef struct User User;
+
+struct Device {
+ Manager *manager;
+
+ char *sysfs;
+ Seat *seat;
+
+ dual_timestamp timestamp;
+
+ LIST_FIELDS(struct Device, devices);
+};
+
+struct Seat {
+ Manager *manager;
+ char *id;
+
+ char *state_file;
+
+ LIST_HEAD(Device, devices);
+
+ Session *active;
+ LIST_HEAD(Session, sessions);
+};
+
+typedef enum SessionType {
+ SESSION_TERMINAL,
+ SESSION_X11,
+ _SESSION_TYPE_MAX,
+ _SESSION_TYPE_INVALID = -1
+} SessionType;
+
+struct Session {
+ Manager *manager;
+
+ char *id;
+ SessionType type;
+
+ char *state_file;
+
+ User *user;
+
+ dual_timestamp timestamp;
+
+ char *tty;
+ char *display;
+
+ bool remote;
+ char *remote_host;
+
+ int vtnr;
+ Seat *seat;
+
+ pid_t leader;
+ uint64_t audit_id;
+
+ int pipe_fd;
+
+ char *cgroup_path;
+ char **controllers, **reset_controllers;
+
+ bool kill_processes;
+
+ LIST_FIELDS(Session, sessions_by_user);
+ LIST_FIELDS(Session, sessions_by_seat);
+};
+
+typedef enum UserState {
+ USER_OFFLINE,
+ USER_LINGERING,
+ USER_ONLINE,
+ USER_ACTIVE,
+ _USER_STATE_MAX,
+ _USER_STATE_INVALID = -1
+} UserState;
+
+struct User {
+ Manager *manager;
+
+ uid_t uid;
+ gid_t gid;
+ char *name;
+
+ char *state_file;
+ char *runtime_path;
+ char *service;
+ char *cgroup_path;
+
+ Session *display;
+
+ dual_timestamp timestamp;
+
+ LIST_HEAD(Session, sessions);
+};
+
+struct Manager {
+ DBusConnection *bus;
+
+ Hashmap *devices;
+ Hashmap *seats;
+ Hashmap *sessions;
+ Hashmap *users;
+
+ struct udev *udev;
+ struct udev_monitor *udev_monitor;
+
+ int udev_fd;
+ int console_active_fd;
+ int bus_fd;
+ int epoll_fd;
+
+ int n_autovts;
+
+ Seat *vtconsole;
+
+ char *cgroup_path;
+ char **controllers, **reset_controllers;
+
+ char **kill_only_users, **kill_exlude_users;
+
+ bool kill_user_processes;
+};
+
+Device* device_new(Manager *m, const char *sysfs);
+void device_free(Device *d);
+void device_attach(Device *d, Seat *s);
+void device_detach(Device *d);
+
+Seat *seat_new(Manager *m, const char *id);
+void seat_free(Seat *s);
+int seat_preallocate_vts(Seat *s);
+void seat_active_vt_changed(Seat *s, int vtnr);
+int seat_apply_acls(Seat *s);
+int seat_stop(Seat *s);
+int seat_save(Seat *s);
+int seat_load(Seat *s);
+
+Session *session_new(Manager *m, User *u, const char *id);
+void session_free(Session *s);
+int session_activate(Session *s);
+bool session_is_active(Session *s);
+int session_check_gc(Session *s);
+int session_start(Session *s);
+int session_stop(Session *s);
+int session_save(Session *s);
+int session_load(Session *s);
+
+User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name);
+void user_free(User *u);
+int user_start(User *u);
+int user_stop(User *u);
+int user_check_gc(User *u);
+UserState user_get_state(User *u);
+int user_save(User *u);
+int user_load(User *u);
+
+Manager *manager_new(void);
+void manager_free(Manager *m);
+int manager_add_device(Manager *m, const char *sysfs, Device **_device);
+int manager_add_seat(Manager *m, const char *id, Seat **_seat);
+int manager_add_session(Manager *m, User *u, const char *id, Session **_session);
+int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user);
+int manager_add_user_by_name(Manager *m, const char *name, User **_user);
+int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user);
+int manager_process_device(Manager *m, struct udev_device *d);
+int manager_dispatch_udev(Manager *m);
+int manager_dispatch_console(Manager *m);
+int manager_enumerate_devices(Manager *m);
+int manager_enumerate_seats(Manager *m);
+int manager_enumerate_sessions(Manager *m);
+int manager_enumerate_users(Manager *m);
+int manager_start_one_linger_user(Manager *m, const char *user);
+int manager_start_linger_users(Manager *m);
+int manager_startup(Manager *m);
+int manager_run(Manager *m);
+int manager_spawn_autovt(Manager *m, int vtnr);
+
+const char* session_type_to_string(SessionType t);
+SessionType session_type_from_string(const char *s);
+
+const char* user_state_to_string(UserState s);
+UserState user_state_from_string(const char *s);
+
+bool x11_display_is_local(const char *display);
+
+#endif
commit f41607a6e10202003efe307eab975e8aca37d3de
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon May 23 23:54:22 2011 +0200
util: move string enum mapping to the end
diff --git a/src/util.c b/src/util.c
index 4a735db..ad1ca06 100644
--- a/src/util.c
+++ b/src/util.c
@@ -4537,141 +4537,6 @@ int vt_disallocate(const char *name) {
return 0;
}
-static const char *const ioprio_class_table[] = {
- [IOPRIO_CLASS_NONE] = "none",
- [IOPRIO_CLASS_RT] = "realtime",
- [IOPRIO_CLASS_BE] = "best-effort",
- [IOPRIO_CLASS_IDLE] = "idle"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(ioprio_class, int);
-
-static const char *const sigchld_code_table[] = {
- [CLD_EXITED] = "exited",
- [CLD_KILLED] = "killed",
- [CLD_DUMPED] = "dumped",
- [CLD_TRAPPED] = "trapped",
- [CLD_STOPPED] = "stopped",
- [CLD_CONTINUED] = "continued",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
-
-static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = {
- [LOG_FAC(LOG_KERN)] = "kern",
- [LOG_FAC(LOG_USER)] = "user",
- [LOG_FAC(LOG_MAIL)] = "mail",
- [LOG_FAC(LOG_DAEMON)] = "daemon",
- [LOG_FAC(LOG_AUTH)] = "auth",
- [LOG_FAC(LOG_SYSLOG)] = "syslog",
- [LOG_FAC(LOG_LPR)] = "lpr",
- [LOG_FAC(LOG_NEWS)] = "news",
- [LOG_FAC(LOG_UUCP)] = "uucp",
- [LOG_FAC(LOG_CRON)] = "cron",
- [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
- [LOG_FAC(LOG_FTP)] = "ftp",
- [LOG_FAC(LOG_LOCAL0)] = "local0",
- [LOG_FAC(LOG_LOCAL1)] = "local1",
- [LOG_FAC(LOG_LOCAL2)] = "local2",
- [LOG_FAC(LOG_LOCAL3)] = "local3",
- [LOG_FAC(LOG_LOCAL4)] = "local4",
- [LOG_FAC(LOG_LOCAL5)] = "local5",
- [LOG_FAC(LOG_LOCAL6)] = "local6",
- [LOG_FAC(LOG_LOCAL7)] = "local7"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(log_facility_unshifted, int);
-
-static const char *const log_level_table[] = {
- [LOG_EMERG] = "emerg",
- [LOG_ALERT] = "alert",
- [LOG_CRIT] = "crit",
- [LOG_ERR] = "err",
- [LOG_WARNING] = "warning",
- [LOG_NOTICE] = "notice",
- [LOG_INFO] = "info",
- [LOG_DEBUG] = "debug"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(log_level, int);
-
-static const char* const sched_policy_table[] = {
- [SCHED_OTHER] = "other",
- [SCHED_BATCH] = "batch",
- [SCHED_IDLE] = "idle",
- [SCHED_FIFO] = "fifo",
- [SCHED_RR] = "rr"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(sched_policy, int);
-
-static const char* const rlimit_table[] = {
- [RLIMIT_CPU] = "LimitCPU",
- [RLIMIT_FSIZE] = "LimitFSIZE",
- [RLIMIT_DATA] = "LimitDATA",
- [RLIMIT_STACK] = "LimitSTACK",
- [RLIMIT_CORE] = "LimitCORE",
- [RLIMIT_RSS] = "LimitRSS",
- [RLIMIT_NOFILE] = "LimitNOFILE",
- [RLIMIT_AS] = "LimitAS",
- [RLIMIT_NPROC] = "LimitNPROC",
- [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
- [RLIMIT_LOCKS] = "LimitLOCKS",
- [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
- [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
- [RLIMIT_NICE] = "LimitNICE",
- [RLIMIT_RTPRIO] = "LimitRTPRIO",
- [RLIMIT_RTTIME] = "LimitRTTIME"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
-
-static const char* const ip_tos_table[] = {
- [IPTOS_LOWDELAY] = "low-delay",
- [IPTOS_THROUGHPUT] = "throughput",
- [IPTOS_RELIABILITY] = "reliability",
- [IPTOS_LOWCOST] = "low-cost",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(ip_tos, int);
-
-static const char *const signal_table[] = {
- [SIGHUP] = "HUP",
- [SIGINT] = "INT",
- [SIGQUIT] = "QUIT",
- [SIGILL] = "ILL",
- [SIGTRAP] = "TRAP",
- [SIGABRT] = "ABRT",
- [SIGBUS] = "BUS",
- [SIGFPE] = "FPE",
- [SIGKILL] = "KILL",
- [SIGUSR1] = "USR1",
- [SIGSEGV] = "SEGV",
- [SIGUSR2] = "USR2",
- [SIGPIPE] = "PIPE",
- [SIGALRM] = "ALRM",
- [SIGTERM] = "TERM",
-#ifdef SIGSTKFLT
- [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */
-#endif
- [SIGCHLD] = "CHLD",
- [SIGCONT] = "CONT",
- [SIGSTOP] = "STOP",
- [SIGTSTP] = "TSTP",
- [SIGTTIN] = "TTIN",
- [SIGTTOU] = "TTOU",
- [SIGURG] = "URG",
- [SIGXCPU] = "XCPU",
- [SIGXFSZ] = "XFSZ",
- [SIGVTALRM] = "VTALRM",
- [SIGPROF] = "PROF",
- [SIGWINCH] = "WINCH",
- [SIGIO] = "IO",
- [SIGPWR] = "PWR",
- [SIGSYS] = "SYS"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(signal, int);
static int file_is_conf(const struct dirent *d, const char *suffix) {
assert(d);
@@ -4868,3 +4733,139 @@ int hwclock_set_time(const struct tm *tm) {
return err;
}
+
+static const char *const ioprio_class_table[] = {
+ [IOPRIO_CLASS_NONE] = "none",
+ [IOPRIO_CLASS_RT] = "realtime",
+ [IOPRIO_CLASS_BE] = "best-effort",
+ [IOPRIO_CLASS_IDLE] = "idle"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(ioprio_class, int);
+
+static const char *const sigchld_code_table[] = {
+ [CLD_EXITED] = "exited",
+ [CLD_KILLED] = "killed",
+ [CLD_DUMPED] = "dumped",
+ [CLD_TRAPPED] = "trapped",
+ [CLD_STOPPED] = "stopped",
+ [CLD_CONTINUED] = "continued",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
+
+static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = {
+ [LOG_FAC(LOG_KERN)] = "kern",
+ [LOG_FAC(LOG_USER)] = "user",
+ [LOG_FAC(LOG_MAIL)] = "mail",
+ [LOG_FAC(LOG_DAEMON)] = "daemon",
+ [LOG_FAC(LOG_AUTH)] = "auth",
+ [LOG_FAC(LOG_SYSLOG)] = "syslog",
+ [LOG_FAC(LOG_LPR)] = "lpr",
+ [LOG_FAC(LOG_NEWS)] = "news",
+ [LOG_FAC(LOG_UUCP)] = "uucp",
+ [LOG_FAC(LOG_CRON)] = "cron",
+ [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
+ [LOG_FAC(LOG_FTP)] = "ftp",
+ [LOG_FAC(LOG_LOCAL0)] = "local0",
+ [LOG_FAC(LOG_LOCAL1)] = "local1",
+ [LOG_FAC(LOG_LOCAL2)] = "local2",
+ [LOG_FAC(LOG_LOCAL3)] = "local3",
+ [LOG_FAC(LOG_LOCAL4)] = "local4",
+ [LOG_FAC(LOG_LOCAL5)] = "local5",
+ [LOG_FAC(LOG_LOCAL6)] = "local6",
+ [LOG_FAC(LOG_LOCAL7)] = "local7"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(log_facility_unshifted, int);
+
+static const char *const log_level_table[] = {
+ [LOG_EMERG] = "emerg",
+ [LOG_ALERT] = "alert",
+ [LOG_CRIT] = "crit",
+ [LOG_ERR] = "err",
+ [LOG_WARNING] = "warning",
+ [LOG_NOTICE] = "notice",
+ [LOG_INFO] = "info",
+ [LOG_DEBUG] = "debug"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(log_level, int);
+
+static const char* const sched_policy_table[] = {
+ [SCHED_OTHER] = "other",
+ [SCHED_BATCH] = "batch",
+ [SCHED_IDLE] = "idle",
+ [SCHED_FIFO] = "fifo",
+ [SCHED_RR] = "rr"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(sched_policy, int);
+
+static const char* const rlimit_table[] = {
+ [RLIMIT_CPU] = "LimitCPU",
+ [RLIMIT_FSIZE] = "LimitFSIZE",
+ [RLIMIT_DATA] = "LimitDATA",
+ [RLIMIT_STACK] = "LimitSTACK",
+ [RLIMIT_CORE] = "LimitCORE",
+ [RLIMIT_RSS] = "LimitRSS",
+ [RLIMIT_NOFILE] = "LimitNOFILE",
+ [RLIMIT_AS] = "LimitAS",
+ [RLIMIT_NPROC] = "LimitNPROC",
+ [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
+ [RLIMIT_LOCKS] = "LimitLOCKS",
+ [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
+ [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
+ [RLIMIT_NICE] = "LimitNICE",
+ [RLIMIT_RTPRIO] = "LimitRTPRIO",
+ [RLIMIT_RTTIME] = "LimitRTTIME"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
+
+static const char* const ip_tos_table[] = {
+ [IPTOS_LOWDELAY] = "low-delay",
+ [IPTOS_THROUGHPUT] = "throughput",
+ [IPTOS_RELIABILITY] = "reliability",
+ [IPTOS_LOWCOST] = "low-cost",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(ip_tos, int);
+
+static const char *const signal_table[] = {
+ [SIGHUP] = "HUP",
+ [SIGINT] = "INT",
+ [SIGQUIT] = "QUIT",
+ [SIGILL] = "ILL",
+ [SIGTRAP] = "TRAP",
+ [SIGABRT] = "ABRT",
+ [SIGBUS] = "BUS",
+ [SIGFPE] = "FPE",
+ [SIGKILL] = "KILL",
+ [SIGUSR1] = "USR1",
+ [SIGSEGV] = "SEGV",
+ [SIGUSR2] = "USR2",
+ [SIGPIPE] = "PIPE",
+ [SIGALRM] = "ALRM",
+ [SIGTERM] = "TERM",
+#ifdef SIGSTKFLT
+ [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */
+#endif
+ [SIGCHLD] = "CHLD",
+ [SIGCONT] = "CONT",
+ [SIGSTOP] = "STOP",
+ [SIGTSTP] = "TSTP",
+ [SIGTTIN] = "TTIN",
+ [SIGTTOU] = "TTOU",
+ [SIGURG] = "URG",
+ [SIGXCPU] = "XCPU",
+ [SIGXFSZ] = "XFSZ",
+ [SIGVTALRM] = "VTALRM",
+ [SIGPROF] = "PROF",
+ [SIGWINCH] = "WINCH",
+ [SIGIO] = "IO",
+ [SIGPWR] = "PWR",
+ [SIGSYS] = "SYS"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(signal, int);
commit 1325aa4202cbd393c9577794e2b4995cc8743892
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon May 23 23:54:00 2011 +0200
util: add pipe_eof()
diff --git a/src/util.c b/src/util.c
index 7f59021..4a735db 100644
--- a/src/util.c
+++ b/src/util.c
@@ -4437,6 +4437,24 @@ char* hostname_cleanup(char *s) {
return s;
}
+int pipe_eof(int fd) {
+ struct pollfd pollfd;
+ int r;
+
+ zero(pollfd);
+ pollfd.fd = fd;
+ pollfd.events = POLLIN|POLLHUP;
+
+ r = poll(&pollfd, 1, 0);
+ if (r < 0)
+ return -errno;
+
+ if (r == 0)
+ return 0;
+
+ return pollfd.revents & POLLHUP;
+}
+
int terminal_vhangup_fd(int fd) {
if (ioctl(fd, TIOCVHANGUP) < 0)
return -errno;
diff --git a/src/util.h b/src/util.h
index f2156af..6076e69 100644
--- a/src/util.h
+++ b/src/util.h
@@ -357,6 +357,8 @@ int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
int rm_rf(const char *path, bool only_dirs, bool delete_root);
+int pipe_eof(int fd);
+
cpu_set_t* cpu_set_malloc(unsigned *ncpus);
void status_vprintf(const char *format, va_list ap);
commit ab5c3e3ff172e7dc295d3022170ee6a3be062a3f
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon May 23 23:53:43 2011 +0200
english: s/_per_/_by_/
diff --git a/src/automount.c b/src/automount.c
index 33c962e..51fa003 100644
--- a/src/automount.c
+++ b/src/automount.c
@@ -142,7 +142,7 @@ static int automount_add_mount_links(Automount *a) {
assert(a);
- LIST_FOREACH(units_per_type, other, a->meta.manager->units_per_type[UNIT_MOUNT])
+ LIST_FOREACH(units_by_type, other, a->meta.manager->units_by_type[UNIT_MOUNT])
if ((r = automount_add_one_mount_link(a, (Mount*) other)) < 0)
return r;
diff --git a/src/manager.h b/src/manager.h
index 07b92c8..4557d5f 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -102,7 +102,7 @@ struct Manager {
/* To make it easy to iterate through the units of a specific
* type we maintain a per type linked list */
- LIST_HEAD(Meta, units_per_type[_UNIT_TYPE_MAX]);
+ LIST_HEAD(Meta, units_by_type[_UNIT_TYPE_MAX]);
/* Units that need to be loaded */
LIST_HEAD(Meta, load_queue); /* this is actually more a stack than a queue, but uh. */
diff --git a/src/mount.c b/src/mount.c
index 423cf43..660af13 100644
--- a/src/mount.c
+++ b/src/mount.c
@@ -114,7 +114,7 @@ static void mount_done(Unit *u) {
m->where = NULL;
/* Try to detach us from the automount unit if there is any */
- LIST_FOREACH(units_per_type, other, m->meta.manager->units_per_type[UNIT_AUTOMOUNT]) {
+ LIST_FOREACH(units_by_type, other, m->meta.manager->units_by_type[UNIT_AUTOMOUNT]) {
Automount *a = (Automount*) other;
if (a->mount == m)
@@ -166,7 +166,7 @@ static int mount_add_mount_links(Mount *m) {
/* Adds in links to other mount points that might lie below or
* above us in the hierarchy */
- LIST_FOREACH(units_per_type, other, m->meta.manager->units_per_type[UNIT_MOUNT]) {
+ LIST_FOREACH(units_by_type, other, m->meta.manager->units_by_type[UNIT_MOUNT]) {
Mount *n = (Mount*) other;
MountParameters *pn;
@@ -223,7 +223,7 @@ static int mount_add_swap_links(Mount *m) {
assert(m);
- LIST_FOREACH(units_per_type, other, m->meta.manager->units_per_type[UNIT_SWAP])
+ LIST_FOREACH(units_by_type, other, m->meta.manager->units_by_type[UNIT_SWAP])
if ((r = swap_add_one_mount_link((Swap*) other, m)) < 0)
return r;
@@ -236,7 +236,7 @@ static int mount_add_path_links(Mount *m) {
assert(m);
- LIST_FOREACH(units_per_type, other, m->meta.manager->units_per_type[UNIT_PATH])
+ LIST_FOREACH(units_by_type, other, m->meta.manager->units_by_type[UNIT_PATH])
if ((r = path_add_one_mount_link((Path*) other, m)) < 0)
return r;
@@ -249,7 +249,7 @@ static int mount_add_automount_links(Mount *m) {
assert(m);
- LIST_FOREACH(units_per_type, other, m->meta.manager->units_per_type[UNIT_AUTOMOUNT])
+ LIST_FOREACH(units_by_type, other, m->meta.manager->units_by_type[UNIT_AUTOMOUNT])
if ((r = automount_add_one_mount_link((Automount*) other, m)) < 0)
return r;
@@ -262,7 +262,7 @@ static int mount_add_socket_links(Mount *m) {
assert(m);
- LIST_FOREACH(units_per_type, other, m->meta.manager->units_per_type[UNIT_SOCKET])
+ LIST_FOREACH(units_by_type, other, m->meta.manager->units_by_type[UNIT_SOCKET])
if ((r = socket_add_one_mount_link((Socket*) other, m)) < 0)
return r;
@@ -1687,7 +1687,7 @@ void mount_fd_event(Manager *m, int events) {
log_error("Failed to reread /proc/self/mountinfo: %s", strerror(-r));
/* Reset flags, just in case, for later calls */
- LIST_FOREACH(units_per_type, meta, m->units_per_type[UNIT_MOUNT]) {
+ LIST_FOREACH(units_by_type, meta, m->units_by_type[UNIT_MOUNT]) {
Mount *mount = (Mount*) meta;
mount->is_mounted = mount->just_mounted = mount->just_changed = false;
@@ -1698,7 +1698,7 @@ void mount_fd_event(Manager *m, int events) {
manager_dispatch_load_queue(m);
- LIST_FOREACH(units_per_type, meta, m->units_per_type[UNIT_MOUNT]) {
+ LIST_FOREACH(units_by_type, meta, m->units_by_type[UNIT_MOUNT]) {
Mount *mount = (Mount*) meta;
if (!mount->is_mounted) {
diff --git a/src/path.c b/src/path.c
index c722a45..1c20dcf 100644
--- a/src/path.c
+++ b/src/path.c
@@ -102,7 +102,7 @@ static int path_add_mount_links(Path *p) {
assert(p);
- LIST_FOREACH(units_per_type, other, p->meta.manager->units_per_type[UNIT_MOUNT])
+ LIST_FOREACH(units_by_type, other, p->meta.manager->units_by_type[UNIT_MOUNT])
if ((r = path_add_one_mount_link(p, (Mount*) other)) < 0)
return r;
diff --git a/src/service.c b/src/service.c
index d59c4cb..1f74868 100644
--- a/src/service.c
+++ b/src/service.c
@@ -372,7 +372,7 @@ static int sysv_fix_order(Service *s) {
/* For each pair of services where at least one lacks a LSB
* header, we use the start priority value to order things. */
- LIST_FOREACH(units_per_type, other, s->meta.manager->units_per_type[UNIT_SERVICE]) {
+ LIST_FOREACH(units_by_type, other, s->meta.manager->units_by_type[UNIT_SERVICE]) {
Service *t;
UnitDependency d;
bool special_s, special_t;
@@ -1006,7 +1006,7 @@ static int fsck_fix_order(Service *s) {
/* For each pair of services where both have an fsck priority
* we order things based on it. */
- LIST_FOREACH(units_per_type, other, s->meta.manager->units_per_type[UNIT_SERVICE]) {
+ LIST_FOREACH(units_by_type, other, s->meta.manager->units_by_type[UNIT_SERVICE]) {
Service *t;
UnitDependency d;
diff --git a/src/socket.c b/src/socket.c
index c013958..8b78a3f 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -131,7 +131,7 @@ static void socket_done(Unit *u) {
unit_unwatch_timer(u, &s->timer_watch);
/* Make sure no service instance refers to us anymore. */
- LIST_FOREACH(units_per_type, i, u->meta.manager->units_per_type[UNIT_SERVICE]) {
+ LIST_FOREACH(units_by_type, i, u->meta.manager->units_by_type[UNIT_SERVICE]) {
Service *service = (Service *) i;
if (service->accept_socket == s)
@@ -283,7 +283,7 @@ static int socket_add_mount_links(Socket *s) {
assert(s);
- LIST_FOREACH(units_per_type, other, s->meta.manager->units_per_type[UNIT_MOUNT])
+ LIST_FOREACH(units_by_type, other, s->meta.manager->units_by_type[UNIT_MOUNT])
if ((r = socket_add_one_mount_link(s, (Mount*) other)) < 0)
return r;
@@ -1361,7 +1361,7 @@ static void socket_enter_running(Socket *s, int cfd) {
/* If there's already a start pending don't bother to
* do anything */
- LIST_FOREACH(units_per_type, i, s->meta.manager->units_per_type[UNIT_SERVICE]) {
+ LIST_FOREACH(units_by_type, i, s->meta.manager->units_by_type[UNIT_SERVICE]) {
Service *service = (Service *) i;
if (!set_get(service->configured_sockets, s))
diff --git a/src/swap.c b/src/swap.c
index 04df585..14719ad 100644
--- a/src/swap.c
+++ b/src/swap.c
@@ -155,7 +155,7 @@ static int swap_add_mount_links(Swap *s) {
assert(s);
- LIST_FOREACH(units_per_type, other, s->meta.manager->units_per_type[UNIT_MOUNT])
+ LIST_FOREACH(units_by_type, other, s->meta.manager->units_by_type[UNIT_MOUNT])
if ((r = swap_add_one_mount_link(s, (Mount*) other)) < 0)
return r;
@@ -1100,7 +1100,7 @@ int swap_fd_event(Manager *m, int events) {
log_error("Failed to reread /proc/swaps: %s", strerror(-r));
/* Reset flags, just in case, for late calls */
- LIST_FOREACH(units_per_type, meta, m->units_per_type[UNIT_SWAP]) {
+ LIST_FOREACH(units_by_type, meta, m->units_by_type[UNIT_SWAP]) {
Swap *swap = (Swap*) meta;
swap->is_active = swap->just_activated = false;
@@ -1111,7 +1111,7 @@ int swap_fd_event(Manager *m, int events) {
manager_dispatch_load_queue(m);
- LIST_FOREACH(units_per_type, meta, m->units_per_type[UNIT_SWAP]) {
+ LIST_FOREACH(units_by_type, meta, m->units_by_type[UNIT_SWAP]) {
Swap *swap = (Swap*) meta;
if (!swap->is_active) {
diff --git a/src/unit.c b/src/unit.c
index 9bb4e56..057431c 100644
--- a/src/unit.c
+++ b/src/unit.c
@@ -159,7 +159,7 @@ int unit_add_name(Unit *u, const char *text) {
u->meta.id = s;
u->meta.instance = i;
- LIST_PREPEND(Meta, units_per_type, u->meta.manager->units_per_type[t], &u->meta);
+ LIST_PREPEND(Meta, units_by_type, u->meta.manager->units_by_type[t], &u->meta);
if (UNIT_VTABLE(u)->init)
UNIT_VTABLE(u)->init(u);
@@ -354,7 +354,7 @@ void unit_free(Unit *u) {
bidi_set_free(u, u->meta.dependencies[d]);
if (u->meta.type != _UNIT_TYPE_INVALID)
- LIST_REMOVE(Meta, units_per_type, u->meta.manager->units_per_type[u->meta.type], &u->meta);
+ LIST_REMOVE(Meta, units_by_type, u->meta.manager->units_by_type[u->meta.type], &u->meta);
if (u->meta.in_load_queue)
LIST_REMOVE(Meta, load_queue, u->meta.manager->load_queue, &u->meta);
diff --git a/src/unit.h b/src/unit.h
index 717c928..1c8cf63 100644
--- a/src/unit.h
+++ b/src/unit.h
@@ -168,7 +168,7 @@ struct Meta {
CGroupBonding *cgroup_bondings;
/* Per type list */
- LIST_FIELDS(Meta, units_per_type);
+ LIST_FIELDS(Meta, units_by_type);
/* Load queue */
LIST_FIELDS(Meta, load_queue);
commit fb19a739d528651e6c78e198269ae856192ffc68
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon May 23 21:39:15 2011 +0200
util: introduce dirent_is_file()
diff --git a/src/util.c b/src/util.c
index 4046938..7f59021 100644
--- a/src/util.c
+++ b/src/util.c
@@ -4181,6 +4181,20 @@ finish:
return r;
}
+bool dirent_is_file(struct dirent *de) {
+ assert(de);
+
+ if (ignore_file(de->d_name))
+ return false;
+
+ if (de->d_type != DT_REG &&
+ de->d_type != DT_LNK &&
+ de->d_type != DT_UNKNOWN)
+ return false;
+
+ return true;
+}
+
void execute_directory(const char *directory, DIR *d, char *argv[]) {
DIR *_d = NULL;
struct dirent *de;
@@ -4214,12 +4228,7 @@ void execute_directory(const char *directory, DIR *d, char *argv[]) {
pid_t pid;
int k;
- if (ignore_file(de->d_name))
- continue;
-
- if (de->d_type != DT_REG &&
- de->d_type != DT_LNK &&
- de->d_type != DT_UNKNOWN)
+ if (!dirent_is_file(de))
continue;
if (asprintf(&path, "%s/%s", directory, de->d_name) < 0) {
diff --git a/src/util.h b/src/util.h
index 79d634b..f2156af 100644
--- a/src/util.h
+++ b/src/util.h
@@ -268,6 +268,7 @@ bool path_equal(const char *a, const char *b);
char *ascii_strlower(char *path);
+bool dirent_is_file(struct dirent *de);
bool ignore_file(const char *filename);
bool chars_intersect(const char *a, const char *b);
commit d0baa06fda52905c24d93df27a9f3e879fab4d0d
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon May 23 21:38:20 2011 +0200
hostnamed: split dbus initialization into a separate function
diff --git a/src/hostnamed.c b/src/hostnamed.c
index ce69045..cf2172f 100644
--- a/src/hostnamed.c
+++ b/src/hostnamed.c
@@ -655,17 +655,55 @@ oom:
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
-int main(int argc, char *argv[]) {
- const DBusObjectPathVTable hostname_vtable = {
+static int connect_bus(DBusConnection **_bus) {
+ static const DBusObjectPathVTable hostname_vtable = {
.message_function = hostname_message_handler
};
-
- DBusConnection *bus = NULL;
DBusError error;
+ DBusConnection *bus = NULL;
int r;
+ assert(_bus);
+
dbus_error_init(&error);
+ bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
+ if (!bus) {
+ log_error("Failed to get system D-Bus connection: %s", error.message);
+ r = -ECONNREFUSED;
+ goto fail;
+ }
+
+ if (!dbus_connection_register_object_path(bus, "/org/freedesktop/hostname1", &hostname_vtable, NULL)) {
+ log_error("Not enough memory");
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ if (dbus_bus_request_name(bus, "org.freedesktop.hostname1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) < 0) {
+ log_error("Failed to register name on bus: %s", error.message);
+ r = -EEXIST;
+ goto fail;
+ }
+
+ if (_bus)
+ *_bus = bus;
+
+ return 0;
+
+fail:
+ dbus_connection_close(bus);
+ dbus_connection_unref(bus);
+
+ dbus_error_free(&error);
+
+ return r;
+}
+
+int main(int argc, char *argv[]) {
+ int r;
+ DBusConnection *bus = NULL;
+
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
log_open();
@@ -687,24 +725,9 @@ int main(int argc, char *argv[]) {
goto finish;
}
- bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
- if (!bus) {
- log_error("Failed to get system D-Bus connection: %s", error.message);
- r = -ECONNREFUSED;
- goto finish;
- }
-
- if (!dbus_connection_register_object_path(bus, "/org/freedesktop/hostname1", &hostname_vtable, NULL)) {
- log_error("Not enough memory");
- r = -ENOMEM;
- goto finish;
- }
-
- if (dbus_bus_request_name(bus, "org.freedesktop.hostname1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) < 0) {
- log_error("Failed to register name on bus: %s", error.message);
- r = -EEXIST;
+ r = connect_bus(&bus);
+ if (r < 0)
goto finish;
- }
while (dbus_connection_read_write_dispatch(bus, -1))
;
@@ -720,7 +743,5 @@ finish:
dbus_connection_unref(bus);
}
- dbus_error_free(&error);
-
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
commit 3df5bf612325b0f6a19acb67befe28d6b07d3804
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon May 23 21:36:52 2011 +0200
dbus: make bus_flags_to_events() and friends generally useful
diff --git a/src/dbus-common.c b/src/dbus-common.c
index 5db077b..c2650fd 100644
--- a/src/dbus-common.c
+++ b/src/dbus-common.c
@@ -27,6 +27,7 @@
#include <stdlib.h>
#include <dbus/dbus.h>
#include <string.h>
+#include <sys/epoll.h>
#include "log.h"
#include "dbus-common.h"
@@ -698,3 +699,38 @@ oom:
return NULL;
}
+
+uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
+ unsigned flags;
+ uint32_t events = 0;
+
+ assert(bus_watch);
+
+ /* no watch flags for disabled watches */
+ if (!dbus_watch_get_enabled(bus_watch))
+ return 0;
+
+ flags = dbus_watch_get_flags(bus_watch);
+
+ if (flags & DBUS_WATCH_READABLE)
+ events |= EPOLLIN;
+ if (flags & DBUS_WATCH_WRITABLE)
+ events |= EPOLLOUT;
+
+ return events | EPOLLHUP | EPOLLERR;
+}
+
+unsigned bus_events_to_flags(uint32_t events) {
+ unsigned flags = 0;
+
+ if (events & EPOLLIN)
+ flags |= DBUS_WATCH_READABLE;
+ if (events & EPOLLOUT)
+ flags |= DBUS_WATCH_WRITABLE;
+ if (events & EPOLLHUP)
+ flags |= DBUS_WATCH_HANGUP;
+ if (events & EPOLLERR)
+ flags |= DBUS_WATCH_ERROR;
+
+ return flags;
+}
diff --git a/src/dbus-common.h b/src/dbus-common.h
index a88cb13..1e5545f 100644
--- a/src/dbus-common.h
+++ b/src/dbus-common.h
@@ -153,4 +153,7 @@ const char *bus_errno_to_dbus(int error);
DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties);
+uint32_t bus_flags_to_events(DBusWatch *bus_watch);
+unsigned bus_events_to_flags(uint32_t events);
+
#endif
diff --git a/src/dbus.c b/src/dbus.c
index 187ed30..e153c35 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -91,41 +91,6 @@ static void bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status,
set_move_one(m->bus_connections_for_dispatch, m->bus_connections, bus);
}
-static uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
- unsigned flags;
- uint32_t events = 0;
-
- assert(bus_watch);
-
- /* no watch flags for disabled watches */
- if (!dbus_watch_get_enabled(bus_watch))
- return 0;
-
- flags = dbus_watch_get_flags(bus_watch);
-
- if (flags & DBUS_WATCH_READABLE)
- events |= EPOLLIN;
- if (flags & DBUS_WATCH_WRITABLE)
- events |= EPOLLOUT;
-
- return events | EPOLLHUP | EPOLLERR;
-}
-
-static unsigned events_to_bus_flags(uint32_t events) {
- unsigned flags = 0;
-
- if (events & EPOLLIN)
- flags |= DBUS_WATCH_READABLE;
- if (events & EPOLLOUT)
- flags |= DBUS_WATCH_WRITABLE;
- if (events & EPOLLHUP)
- flags |= DBUS_WATCH_HANGUP;
- if (events & EPOLLERR)
- flags |= DBUS_WATCH_ERROR;
-
- return flags;
-}
-
void bus_watch_event(Manager *m, Watch *w, int events) {
assert(m);
assert(w);
@@ -136,7 +101,7 @@ void bus_watch_event(Manager *m, Watch *w, int events) {
if (!dbus_watch_get_enabled(w->data.bus_watch))
return;
- dbus_watch_handle(w->data.bus_watch, events_to_bus_flags(events));
+ dbus_watch_handle(w->data.bus_watch, bus_events_to_flags(events));
}
static dbus_bool_t bus_add_watch(DBusWatch *bus_watch, void *data) {
@@ -196,7 +161,8 @@ static void bus_remove_watch(DBusWatch *bus_watch, void *data) {
assert(bus_watch);
assert(m);
- if (!(w = dbus_watch_get_data(bus_watch)))
+ w = dbus_watch_get_data(bus_watch);
+ if (!w)
return;
assert(w->type == WATCH_DBUS_WATCH);
@@ -216,7 +182,10 @@ static void bus_toggle_watch(DBusWatch *bus_watch, void *data) {
assert(bus_watch);
assert(m);
- assert_se(w = dbus_watch_get_data(bus_watch));
+ w = dbus_watch_get_data(bus_watch);
+ if (!w)
+ return;
+
assert(w->type == WATCH_DBUS_WATCH);
zero(ev);
@@ -304,10 +273,12 @@ static void bus_remove_timeout(DBusTimeout *timeout, void *data) {
assert(timeout);
assert(m);
- if (!(w = dbus_timeout_get_data(timeout)))
+ w = dbus_timeout_get_data(timeout);
+ if (!w)
return;
assert(w->type == WATCH_DBUS_TIMEOUT);
+
assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
close_nointr_nofail(w->fd);
free(w);
@@ -321,7 +292,10 @@ static void bus_toggle_timeout(DBusTimeout *timeout, void *data) {
assert(timeout);
assert(m);
- assert_se(w = dbus_timeout_get_data(timeout));
+ w = dbus_timeout_get_data(timeout);
+ if (!w)
+ return;
+
assert(w->type == WATCH_DBUS_TIMEOUT);
if ((r = bus_timeout_arm(m, w)) < 0)
@@ -819,7 +793,7 @@ static int bus_init_system(Manager *m) {
if (!dbus_connection_add_filter(m->system_bus, system_bus_message_filter, m, NULL)) {
log_error("Not enough memory");
- r = -EIO;
+ r = -ENOMEM;
goto fail;
}
diff --git a/src/manager.c b/src/manager.c
index 62451a0..19172a2 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -2260,7 +2260,7 @@ static int process_event(Manager *m, struct epoll_event *ev) {
assert(m);
assert(ev);
- assert(w = ev->data.ptr);
+ assert_se(w = ev->data.ptr);
if (w->type == WATCH_INVALID)
return 0;
More information about the systemd-commits
mailing list