2011-05-23 23:55:06 +02:00
|
|
|
/*-*- 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
|
2012-04-12 00:20:58 +02:00
|
|
|
under the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
2011-05-23 23:55:06 +02:00
|
|
|
(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
|
2012-04-12 00:20:58 +02:00
|
|
|
Lesser General Public License for more details.
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2012-04-12 00:20:58 +02:00
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
2011-05-23 23:55:06 +02:00
|
|
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
2011-06-24 23:25:28 +02:00
|
|
|
#include <sys/epoll.h>
|
2011-06-29 00:06:04 +02:00
|
|
|
#include <fcntl.h>
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2013-07-02 01:46:30 +02:00
|
|
|
#include <systemd/sd-id128.h>
|
|
|
|
#include <systemd/sd-messages.h>
|
|
|
|
|
2011-05-23 23:55:06 +02:00
|
|
|
#include "strv.h"
|
|
|
|
#include "util.h"
|
2012-04-10 21:54:31 +02:00
|
|
|
#include "mkdir.h"
|
2012-05-07 21:36:12 +02:00
|
|
|
#include "path-util.h"
|
2013-02-14 12:26:13 +01:00
|
|
|
#include "fileio.h"
|
2013-07-02 01:46:30 +02:00
|
|
|
#include "dbus-common.h"
|
|
|
|
#include "logind-session.h"
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2013-06-20 03:45:08 +02:00
|
|
|
Session* session_new(Manager *m, const char *id) {
|
2011-05-23 23:55:06 +02:00
|
|
|
Session *s;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(id);
|
2013-09-16 04:26:56 +02:00
|
|
|
assert(session_id_valid(id));
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2011-05-25 00:55:58 +02:00
|
|
|
s = new0(Session, 1);
|
2011-05-23 23:55:06 +02:00
|
|
|
if (!s)
|
|
|
|
return NULL;
|
|
|
|
|
2011-06-24 18:50:50 +02:00
|
|
|
s->state_file = strappend("/run/systemd/sessions/", id);
|
2011-05-23 23:55:06 +02:00
|
|
|
if (!s->state_file) {
|
|
|
|
free(s);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-05-07 21:36:12 +02:00
|
|
|
s->id = path_get_file_name(s->state_file);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
if (hashmap_put(m->sessions, s->id, s) < 0) {
|
2012-04-16 16:47:33 +02:00
|
|
|
free(s->state_file);
|
2011-05-23 23:55:06 +02:00
|
|
|
free(s);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
s->manager = m;
|
2011-06-29 00:06:04 +02:00
|
|
|
s->fifo_fd = -1;
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_free(Session *s) {
|
|
|
|
assert(s);
|
|
|
|
|
2011-05-25 00:55:58 +02:00
|
|
|
if (s->in_gc_queue)
|
|
|
|
LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
|
|
|
|
|
2013-09-17 17:39:56 +02:00
|
|
|
session_drop_controller(s);
|
|
|
|
|
2011-05-23 23:55:06 +02:00
|
|
|
if (s->user) {
|
|
|
|
LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
|
|
|
|
|
|
|
|
if (s->user->display == s)
|
|
|
|
s->user->display = NULL;
|
|
|
|
}
|
|
|
|
|
2011-06-21 21:46:13 +02:00
|
|
|
if (s->seat) {
|
|
|
|
if (s->seat->active == s)
|
|
|
|
s->seat->active = NULL;
|
|
|
|
|
2011-05-23 23:55:06 +02:00
|
|
|
LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
|
2011-06-21 21:46:13 +02:00
|
|
|
}
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2013-07-02 01:46:30 +02:00
|
|
|
if (s->scope) {
|
|
|
|
hashmap_remove(s->manager->session_units, s->scope);
|
|
|
|
free(s->scope);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(s->scope_job);
|
2011-06-24 20:41:56 +02:00
|
|
|
|
2013-07-02 01:46:30 +02:00
|
|
|
if (s->create_message)
|
|
|
|
dbus_message_unref(s->create_message);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
free(s->tty);
|
|
|
|
free(s->display);
|
|
|
|
free(s->remote_host);
|
2011-05-26 02:21:16 +02:00
|
|
|
free(s->remote_user);
|
2011-06-24 18:50:50 +02:00
|
|
|
free(s->service);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
hashmap_remove(s->manager->sessions, s->id);
|
2011-06-29 00:06:04 +02:00
|
|
|
session_remove_fifo(s);
|
2011-06-24 18:50:50 +02:00
|
|
|
|
2011-05-25 00:58:55 +02:00
|
|
|
free(s->state_file);
|
2011-05-23 23:55:06 +02:00
|
|
|
free(s);
|
|
|
|
}
|
|
|
|
|
2013-06-20 03:45:08 +02:00
|
|
|
void session_set_user(Session *s, User *u) {
|
|
|
|
assert(s);
|
|
|
|
assert(!s->user);
|
|
|
|
|
|
|
|
s->user = u;
|
|
|
|
LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
|
|
|
|
}
|
|
|
|
|
2011-05-23 23:55:06 +02:00
|
|
|
int session_save(Session *s) {
|
2013-06-06 00:44:16 +02:00
|
|
|
_cleanup_fclose_ FILE *f = NULL;
|
|
|
|
_cleanup_free_ char *temp_path = NULL;
|
2011-05-23 23:55:06 +02:00
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2013-06-20 03:45:08 +02:00
|
|
|
if (!s->user)
|
|
|
|
return -ESTALE;
|
|
|
|
|
2011-06-27 23:06:34 +02:00
|
|
|
if (!s->started)
|
|
|
|
return 0;
|
|
|
|
|
2012-05-31 12:40:20 +02:00
|
|
|
r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
|
2011-05-23 23:55:06 +02:00
|
|
|
if (r < 0)
|
2011-05-25 00:55:58 +02:00
|
|
|
goto finish;
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2011-05-25 00:55:58 +02:00
|
|
|
r = fopen_temporary(s->state_file, &f, &temp_path);
|
|
|
|
if (r < 0)
|
|
|
|
goto finish;
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
assert(s->user);
|
|
|
|
|
2011-05-25 00:55:58 +02:00
|
|
|
fchmod(fileno(f), 0644);
|
|
|
|
|
2011-05-23 23:55:06 +02:00
|
|
|
fprintf(f,
|
|
|
|
"# This is private data. Do not parse.\n"
|
|
|
|
"UID=%lu\n"
|
|
|
|
"USER=%s\n"
|
|
|
|
"ACTIVE=%i\n"
|
2012-06-21 16:14:53 +02:00
|
|
|
"STATE=%s\n"
|
2013-07-02 01:46:30 +02:00
|
|
|
"REMOTE=%i\n",
|
2011-05-23 23:55:06 +02:00
|
|
|
(unsigned long) s->user->uid,
|
|
|
|
s->user->name,
|
|
|
|
session_is_active(s),
|
2012-06-21 16:14:53 +02:00
|
|
|
session_state_to_string(session_get_state(s)),
|
2013-07-02 01:46:30 +02:00
|
|
|
s->remote);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2011-06-24 23:50:39 +02:00
|
|
|
if (s->type >= 0)
|
2013-06-06 00:44:16 +02:00
|
|
|
fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
|
2011-06-24 23:50:39 +02:00
|
|
|
|
2012-02-14 21:33:51 +01:00
|
|
|
if (s->class >= 0)
|
2013-06-06 00:44:16 +02:00
|
|
|
fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
|
2012-02-14 21:33:51 +01:00
|
|
|
|
2013-07-02 01:46:30 +02:00
|
|
|
if (s->scope)
|
|
|
|
fprintf(f, "SCOPE=%s\n", s->scope);
|
|
|
|
|
|
|
|
if (s->scope_job)
|
|
|
|
fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2011-06-29 00:06:04 +02:00
|
|
|
if (s->fifo_path)
|
2013-06-06 00:44:16 +02:00
|
|
|
fprintf(f, "FIFO=%s\n", s->fifo_path);
|
2011-06-29 00:06:04 +02:00
|
|
|
|
2011-05-23 23:55:06 +02:00
|
|
|
if (s->seat)
|
2013-06-06 00:44:16 +02:00
|
|
|
fprintf(f, "SEAT=%s\n", s->seat->id);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
if (s->tty)
|
2013-06-06 00:44:16 +02:00
|
|
|
fprintf(f, "TTY=%s\n", s->tty);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
if (s->display)
|
2013-06-06 00:44:16 +02:00
|
|
|
fprintf(f, "DISPLAY=%s\n", s->display);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
if (s->remote_host)
|
2013-06-06 00:44:16 +02:00
|
|
|
fprintf(f, "REMOTE_HOST=%s\n", s->remote_host);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2011-05-26 02:21:16 +02:00
|
|
|
if (s->remote_user)
|
2013-06-06 00:44:16 +02:00
|
|
|
fprintf(f, "REMOTE_USER=%s\n", s->remote_user);
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2011-06-24 18:50:50 +02:00
|
|
|
if (s->service)
|
2013-06-06 00:44:16 +02:00
|
|
|
fprintf(f, "SERVICE=%s\n", s->service);
|
2011-06-24 18:50:50 +02:00
|
|
|
|
2013-09-17 17:40:02 +02:00
|
|
|
if (s->seat && seat_has_vts(s->seat))
|
2013-06-06 00:44:16 +02:00
|
|
|
fprintf(f, "VTNR=%i\n", s->vtnr);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
if (s->leader > 0)
|
2013-06-06 00:44:16 +02:00
|
|
|
fprintf(f, "LEADER=%lu\n", (unsigned long) s->leader);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
if (s->audit_id > 0)
|
2013-06-06 00:44:16 +02:00
|
|
|
fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2013-06-20 03:45:08 +02:00
|
|
|
if (dual_timestamp_is_set(&s->timestamp))
|
|
|
|
fprintf(f,
|
|
|
|
"REALTIME=%llu\n"
|
|
|
|
"MONOTONIC=%llu\n",
|
|
|
|
(unsigned long long) s->timestamp.realtime,
|
|
|
|
(unsigned long long) s->timestamp.monotonic);
|
|
|
|
|
2011-05-23 23:55:06 +02:00
|
|
|
fflush(f);
|
2011-05-25 00:55:58 +02:00
|
|
|
|
|
|
|
if (ferror(f) || rename(temp_path, s->state_file) < 0) {
|
2011-05-23 23:55:06 +02:00
|
|
|
r = -errno;
|
|
|
|
unlink(s->state_file);
|
2011-05-25 00:55:58 +02:00
|
|
|
unlink(temp_path);
|
2011-05-23 23:55:06 +02:00
|
|
|
}
|
|
|
|
|
2011-05-25 00:55:58 +02:00
|
|
|
finish:
|
|
|
|
if (r < 0)
|
|
|
|
log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
|
|
|
|
|
2011-05-23 23:55:06 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
int session_load(Session *s) {
|
2013-06-20 03:45:08 +02:00
|
|
|
_cleanup_free_ char *remote = NULL,
|
2011-06-17 15:59:18 +02:00
|
|
|
*seat = NULL,
|
|
|
|
*vtnr = NULL,
|
|
|
|
*leader = NULL,
|
2011-06-24 23:50:39 +02:00
|
|
|
*audit_id = NULL,
|
2012-02-14 21:33:51 +01:00
|
|
|
*type = NULL,
|
2013-06-20 03:45:08 +02:00
|
|
|
*class = NULL,
|
|
|
|
*uid = NULL,
|
|
|
|
*realtime = NULL,
|
|
|
|
*monotonic = NULL;
|
2011-06-17 15:59:18 +02:00
|
|
|
|
|
|
|
int k, r;
|
|
|
|
|
2011-05-23 23:55:06 +02:00
|
|
|
assert(s);
|
|
|
|
|
2011-06-17 15:59:18 +02:00
|
|
|
r = parse_env_file(s->state_file, NEWLINE,
|
|
|
|
"REMOTE", &remote,
|
2013-07-02 01:46:30 +02:00
|
|
|
"SCOPE", &s->scope,
|
|
|
|
"SCOPE_JOB", &s->scope_job,
|
2011-06-29 00:06:04 +02:00
|
|
|
"FIFO", &s->fifo_path,
|
2011-06-17 15:59:18 +02:00
|
|
|
"SEAT", &seat,
|
|
|
|
"TTY", &s->tty,
|
|
|
|
"DISPLAY", &s->display,
|
|
|
|
"REMOTE_HOST", &s->remote_host,
|
|
|
|
"REMOTE_USER", &s->remote_user,
|
2011-06-24 18:50:50 +02:00
|
|
|
"SERVICE", &s->service,
|
2011-06-17 15:59:18 +02:00
|
|
|
"VTNR", &vtnr,
|
|
|
|
"LEADER", &leader,
|
2011-06-24 23:50:39 +02:00
|
|
|
"TYPE", &type,
|
2012-02-14 21:33:51 +01:00
|
|
|
"CLASS", &class,
|
2013-06-20 03:45:08 +02:00
|
|
|
"UID", &uid,
|
|
|
|
"REALTIME", &realtime,
|
|
|
|
"MONOTONIC", &monotonic,
|
2011-06-17 15:59:18 +02:00
|
|
|
NULL);
|
|
|
|
|
2013-06-20 03:45:08 +02:00
|
|
|
if (r < 0) {
|
|
|
|
log_error("Failed to read %s: %s", s->state_file, strerror(-r));
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!s->user) {
|
|
|
|
uid_t u;
|
|
|
|
User *user;
|
|
|
|
|
|
|
|
if (!uid) {
|
|
|
|
log_error("UID not specified for session %s", s->id);
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = parse_uid(uid, &u);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error("Failed to parse UID value %s for session %s.", uid, s->id);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
|
|
|
|
if (!user) {
|
|
|
|
log_error("User of session %s not known.", s->id);
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
session_set_user(s, user);
|
|
|
|
}
|
2011-06-17 15:59:18 +02:00
|
|
|
|
|
|
|
if (remote) {
|
|
|
|
k = parse_boolean(remote);
|
|
|
|
if (k >= 0)
|
|
|
|
s->remote = k;
|
|
|
|
}
|
|
|
|
|
2011-06-21 21:46:13 +02:00
|
|
|
if (seat && !s->seat) {
|
2011-06-17 15:59:18 +02:00
|
|
|
Seat *o;
|
|
|
|
|
|
|
|
o = hashmap_get(s->manager->seats, seat);
|
|
|
|
if (o)
|
|
|
|
seat_attach_session(o, s);
|
|
|
|
}
|
|
|
|
|
2013-09-17 17:40:02 +02:00
|
|
|
if (vtnr && s->seat && seat_has_vts(s->seat)) {
|
2011-06-17 15:59:18 +02:00
|
|
|
int v;
|
|
|
|
|
|
|
|
k = safe_atoi(vtnr, &v);
|
|
|
|
if (k >= 0 && v >= 1)
|
|
|
|
s->vtnr = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (leader) {
|
2012-04-16 16:47:33 +02:00
|
|
|
k = parse_pid(leader, &s->leader);
|
|
|
|
if (k >= 0)
|
|
|
|
audit_session_from_pid(s->leader, &s->audit_id);
|
2011-06-17 15:59:18 +02:00
|
|
|
}
|
|
|
|
|
2011-06-24 23:50:39 +02:00
|
|
|
if (type) {
|
|
|
|
SessionType t;
|
|
|
|
|
|
|
|
t = session_type_from_string(type);
|
|
|
|
if (t >= 0)
|
|
|
|
s->type = t;
|
|
|
|
}
|
|
|
|
|
2012-02-14 21:33:51 +01:00
|
|
|
if (class) {
|
|
|
|
SessionClass c;
|
|
|
|
|
|
|
|
c = session_class_from_string(class);
|
|
|
|
if (c >= 0)
|
|
|
|
s->class = c;
|
|
|
|
}
|
|
|
|
|
2011-06-29 03:48:53 +02:00
|
|
|
if (s->fifo_path) {
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
/* If we open an unopened pipe for reading we will not
|
|
|
|
get an EOF. to trigger an EOF we hence open it for
|
|
|
|
reading, but close it right-away which then will
|
|
|
|
trigger the EOF. */
|
|
|
|
|
|
|
|
fd = session_create_fifo(s);
|
|
|
|
if (fd >= 0)
|
|
|
|
close_nointr_nofail(fd);
|
|
|
|
}
|
|
|
|
|
2013-06-20 03:45:08 +02:00
|
|
|
if (realtime) {
|
|
|
|
unsigned long long l;
|
|
|
|
if (sscanf(realtime, "%llu", &l) > 0)
|
|
|
|
s->timestamp.realtime = l;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (monotonic) {
|
|
|
|
unsigned long long l;
|
|
|
|
if (sscanf(monotonic, "%llu", &l) > 0)
|
|
|
|
s->timestamp.monotonic = l;
|
|
|
|
}
|
2011-06-17 15:59:18 +02:00
|
|
|
|
|
|
|
return r;
|
2011-05-23 23:55:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int session_activate(Session *s) {
|
|
|
|
assert(s);
|
2013-06-20 03:45:08 +02:00
|
|
|
assert(s->user);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2013-09-17 17:40:01 +02:00
|
|
|
if (s->vtnr <= 0)
|
2011-05-23 23:55:06 +02:00
|
|
|
return -ENOTSUP;
|
|
|
|
|
|
|
|
if (!s->seat)
|
|
|
|
return -ENOTSUP;
|
|
|
|
|
|
|
|
if (s->seat->active == s)
|
|
|
|
return 0;
|
|
|
|
|
2013-09-17 17:40:02 +02:00
|
|
|
assert(seat_has_vts(s->seat));
|
2011-05-23 23:55:06 +02:00
|
|
|
|
logind: make Session.Activate() lazy
Currently, Activate() calls chvt(), which does an ioctl(VT_ACTIVATE) and
immediately calls seat_set_active(). However, VTs are allowed to prevent
being deactivated. Therefore, logind cannot be sure the VT_ACTIVATE call
was actually successful.
Furthermore, compositors often need to clean up their devices before they
acknowledge the VT switch. The immediate call to seat_set_active() may
modify underlying ACLs, though. Thus, some compositors may fail cleaning
up their stuff. Moreover, the compositor being switched to (if listening
to logind instead of VTs) will not be able to activate its devices if the
old VT still has them active.
We could simply add an VT_WAITACTIVE call, which blocks until the given VT
is active. However, this can block forever if the compositor hangs.
So to fix this, we make Activate() lazy. That is, it only schedules a
session-switch but does not wait for it to complete. The caller can no
longer rely on it being immediate. Instead, a caller is required to wait
for the PropertiesChanged signal and read the "Active" field.
We could make Activate() wait asynchronously for the session-switch to
complete and then send the return-message afterwards. However, this would
add a lot of state-tracking with no real gain:
1) Sessions normally don't care whether Activate() was actually
successful as they currently _must_ wait for the VT activation to do
anything for real.
2) Error messages for failed session switches can be printed by logind
instead of the session issuing Activate().
3) Sessions that require synchronous Activate() calls can simply issue
the call and then wait for "Active" properties to change. This also
allows them to implement their own timeout.
This change prepares for multi-session on seats without VTs. Forced VT
switches are always bad as compositors cannot perform any cleanup. This
isn't strictly required, but may lead to loss of information and ambiguous
error messages.
So for multi-session on seats without VTs, we must wait for the current
session to clean-up before finalizing the session-switch. This requires
Activate() to be lazy as we cannot block here.
Note that we can always implement a timeout which allows us to guarantee
the session switch to happen. Nevertheless, this calls for a lazy
Activate().
2013-09-17 17:39:57 +02:00
|
|
|
return chvt(s->vtnr);
|
2011-05-23 23:55:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int session_link_x11_socket(Session *s) {
|
2013-08-25 05:48:34 +02:00
|
|
|
_cleanup_free_ char *t = NULL, *f = NULL;
|
|
|
|
char *c;
|
2011-05-23 23:55:06 +02:00
|
|
|
size_t k;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
assert(s->user);
|
|
|
|
assert(s->user->runtime_path);
|
|
|
|
|
|
|
|
if (s->user->display)
|
|
|
|
return 0;
|
|
|
|
|
2011-06-27 22:44:12 +02:00
|
|
|
if (!s->display || !display_is_local(s->display))
|
2011-05-23 23:55:06 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
k = strspn(s->display+1, "0123456789");
|
|
|
|
f = new(char, sizeof("/tmp/.X11-unix/X") + k);
|
2012-07-25 23:55:59 +02:00
|
|
|
if (!f)
|
|
|
|
return log_oom();
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
c = stpcpy(f, "/tmp/.X11-unix/X");
|
|
|
|
memcpy(c, s->display+1, k);
|
|
|
|
c[k] = 0;
|
|
|
|
|
|
|
|
if (access(f, F_OK) < 0) {
|
2012-05-21 15:22:28 +02:00
|
|
|
log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
|
2011-05-23 23:55:06 +02:00
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
2012-03-22 01:43:36 +01:00
|
|
|
/* Note that this cannot be in a subdir to avoid
|
|
|
|
* vulnerabilities since we are privileged but the runtime
|
|
|
|
* path is owned by the user */
|
|
|
|
|
2012-01-17 14:03:00 +01:00
|
|
|
t = strappend(s->user->runtime_path, "/X11-display");
|
2013-08-25 05:48:34 +02:00
|
|
|
if (!t)
|
2012-07-25 23:55:59 +02:00
|
|
|
return log_oom();
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
log_info("Linked %s to %s.", f, t);
|
|
|
|
s->user->display = s;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-02 01:46:30 +02:00
|
|
|
static int session_start_scope(Session *s) {
|
|
|
|
DBusError error;
|
2011-06-24 18:50:50 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
2013-06-20 03:45:08 +02:00
|
|
|
assert(s->user);
|
2013-07-02 01:46:30 +02:00
|
|
|
assert(s->user->slice);
|
2011-06-24 18:50:50 +02:00
|
|
|
|
2013-07-02 01:46:30 +02:00
|
|
|
dbus_error_init(&error);
|
2013-04-23 04:10:13 +02:00
|
|
|
|
2013-07-02 01:46:30 +02:00
|
|
|
if (!s->scope) {
|
2013-07-02 17:17:35 +02:00
|
|
|
_cleanup_free_ char *description = NULL;
|
2013-08-13 17:59:28 +02:00
|
|
|
const char *kill_mode;
|
2013-07-02 17:17:35 +02:00
|
|
|
char *scope, *job;
|
|
|
|
|
2013-08-13 17:59:28 +02:00
|
|
|
description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
|
|
|
|
if (!description)
|
|
|
|
return log_oom();
|
|
|
|
|
2013-07-02 17:17:35 +02:00
|
|
|
scope = strjoin("session-", s->id, ".scope", NULL);
|
|
|
|
if (!scope)
|
2013-04-23 04:10:13 +02:00
|
|
|
return log_oom();
|
|
|
|
|
2013-08-13 17:59:28 +02:00
|
|
|
kill_mode = manager_shall_kill(s->manager, s->user->name) ? "control-group" : "none";
|
2011-06-24 18:50:50 +02:00
|
|
|
|
2013-08-13 17:59:28 +02:00
|
|
|
r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", kill_mode, &error, &job);
|
2013-07-02 17:17:35 +02:00
|
|
|
if (r < 0) {
|
2013-08-24 16:52:23 +02:00
|
|
|
log_error("Failed to start session scope %s: %s %s",
|
|
|
|
scope, bus_error(&error, r), error.name);
|
2013-07-02 17:17:35 +02:00
|
|
|
dbus_error_free(&error);
|
2011-06-29 01:47:55 +02:00
|
|
|
|
2013-07-02 17:17:35 +02:00
|
|
|
free(scope);
|
2013-07-10 23:33:17 +02:00
|
|
|
return r;
|
2013-07-02 17:17:35 +02:00
|
|
|
} else {
|
|
|
|
s->scope = scope;
|
|
|
|
|
|
|
|
free(s->scope_job);
|
|
|
|
s->scope_job = job;
|
|
|
|
}
|
2011-05-23 23:55:06 +02:00
|
|
|
}
|
|
|
|
|
2013-07-02 17:17:35 +02:00
|
|
|
if (s->scope)
|
|
|
|
hashmap_put(s->manager->session_units, s->scope, s);
|
|
|
|
|
2011-05-23 23:55:06 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int session_start(Session *s) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
2013-06-20 03:45:08 +02:00
|
|
|
|
|
|
|
if (!s->user)
|
|
|
|
return -ESTALE;
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2011-06-21 21:46:13 +02:00
|
|
|
if (s->started)
|
|
|
|
return 0;
|
|
|
|
|
2011-06-24 19:42:45 +02:00
|
|
|
r = user_start(s->user);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2013-07-02 01:46:30 +02:00
|
|
|
/* Create cgroup */
|
|
|
|
r = session_start_scope(s);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2012-08-24 22:21:20 +02:00
|
|
|
log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
|
2012-10-08 19:02:30 +02:00
|
|
|
MESSAGE_ID(SD_MESSAGE_SESSION_START),
|
2012-08-24 22:21:20 +02:00
|
|
|
"SESSION_ID=%s", s->id,
|
|
|
|
"USER_ID=%s", s->user->name,
|
|
|
|
"LEADER=%lu", (unsigned long) s->leader,
|
|
|
|
"MESSAGE=New session %s of user %s.", s->id, s->user->name,
|
|
|
|
NULL);
|
2011-06-24 18:50:50 +02:00
|
|
|
|
2011-05-23 23:55:06 +02:00
|
|
|
/* Create X11 symlink */
|
|
|
|
session_link_x11_socket(s);
|
2011-05-25 00:55:58 +02:00
|
|
|
|
2013-06-20 03:45:08 +02:00
|
|
|
if (!dual_timestamp_is_set(&s->timestamp))
|
|
|
|
dual_timestamp_get(&s->timestamp);
|
2011-05-25 00:55:58 +02:00
|
|
|
|
2011-06-27 23:07:13 +02:00
|
|
|
if (s->seat)
|
|
|
|
seat_read_active_vt(s->seat);
|
|
|
|
|
2011-06-21 21:46:13 +02:00
|
|
|
s->started = true;
|
|
|
|
|
2011-06-27 23:07:13 +02:00
|
|
|
/* Save session data */
|
|
|
|
session_save(s);
|
2011-06-28 03:52:22 +02:00
|
|
|
user_save(s->user);
|
2011-06-27 23:07:13 +02:00
|
|
|
|
2011-06-21 20:43:34 +02:00
|
|
|
session_send_signal(s, true);
|
|
|
|
|
2011-06-21 21:46:13 +02:00
|
|
|
if (s->seat) {
|
2011-06-28 03:52:22 +02:00
|
|
|
seat_save(s->seat);
|
|
|
|
|
2011-06-21 21:46:13 +02:00
|
|
|
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");
|
|
|
|
|
2011-05-23 23:55:06 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-02 01:46:30 +02:00
|
|
|
static int session_stop_scope(Session *s) {
|
|
|
|
DBusError error;
|
|
|
|
char *job;
|
2011-05-23 23:55:06 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2013-07-02 01:46:30 +02:00
|
|
|
dbus_error_init(&error);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2013-07-02 01:46:30 +02:00
|
|
|
if (!s->scope)
|
|
|
|
return 0;
|
2012-01-31 23:51:16 +01:00
|
|
|
|
2013-07-02 01:46:30 +02:00
|
|
|
r = manager_stop_unit(s->manager, s->scope, &error, &job);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error("Failed to stop session scope: %s", bus_error(&error, r));
|
|
|
|
dbus_error_free(&error);
|
|
|
|
return r;
|
2011-05-23 23:55:06 +02:00
|
|
|
}
|
|
|
|
|
2013-07-02 01:46:30 +02:00
|
|
|
free(s->scope_job);
|
|
|
|
s->scope_job = job;
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2012-01-31 23:51:16 +01:00
|
|
|
return 0;
|
2011-05-23 23:55:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int session_unlink_x11_socket(Session *s) {
|
2013-08-25 05:48:34 +02:00
|
|
|
_cleanup_free_ char *t = NULL;
|
2011-05-23 23:55:06 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
assert(s->user);
|
|
|
|
|
|
|
|
if (s->user->display != s)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
s->user->display = NULL;
|
|
|
|
|
2012-01-17 14:03:00 +01:00
|
|
|
t = strappend(s->user->runtime_path, "/X11-display");
|
2012-07-25 23:55:59 +02:00
|
|
|
if (!t)
|
|
|
|
return log_oom();
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
r = unlink(t);
|
|
|
|
return r < 0 ? -errno : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int session_stop(Session *s) {
|
2013-08-13 17:59:28 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
if (!s->user)
|
|
|
|
return -ESTALE;
|
|
|
|
|
|
|
|
/* Kill cgroup */
|
|
|
|
r = session_stop_scope(s);
|
|
|
|
|
|
|
|
session_save(s);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
int session_finalize(Session *s) {
|
|
|
|
int r = 0;
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2013-06-20 03:45:08 +02:00
|
|
|
if (!s->user)
|
|
|
|
return -ESTALE;
|
|
|
|
|
2011-06-24 19:42:45 +02:00
|
|
|
if (s->started)
|
2012-08-24 22:21:20 +02:00
|
|
|
log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
|
2012-10-08 19:02:30 +02:00
|
|
|
MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
|
2012-08-24 22:21:20 +02:00
|
|
|
"SESSION_ID=%s", s->id,
|
|
|
|
"USER_ID=%s", s->user->name,
|
|
|
|
"LEADER=%lu", (unsigned long) s->leader,
|
|
|
|
"MESSAGE=Removed session %s.", s->id,
|
|
|
|
NULL);
|
2011-06-24 18:50:50 +02:00
|
|
|
|
2011-05-23 23:55:06 +02:00
|
|
|
/* Remove X11 symlink */
|
|
|
|
session_unlink_x11_socket(s);
|
|
|
|
|
2011-05-25 00:58:55 +02:00
|
|
|
unlink(s->state_file);
|
|
|
|
session_add_to_gc_queue(s);
|
2011-06-24 19:42:45 +02:00
|
|
|
user_add_to_gc_queue(s->user);
|
2011-05-25 00:55:58 +02:00
|
|
|
|
2013-08-13 17:59:28 +02:00
|
|
|
if (s->started) {
|
2011-06-24 19:42:45 +02:00
|
|
|
session_send_signal(s, false);
|
2013-08-13 17:59:28 +02:00
|
|
|
s->started = false;
|
|
|
|
}
|
2013-04-10 09:49:24 +02:00
|
|
|
|
2011-06-21 21:46:13 +02:00
|
|
|
if (s->seat) {
|
|
|
|
if (s->seat->active == s)
|
|
|
|
seat_set_active(s->seat, NULL);
|
|
|
|
|
|
|
|
seat_send_changed(s->seat, "Sessions\0");
|
2012-09-04 02:37:27 +02:00
|
|
|
seat_save(s->seat);
|
2011-06-21 21:46:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
user_send_changed(s->user, "Sessions\0");
|
2012-09-04 02:37:27 +02:00
|
|
|
user_save(s->user);
|
2011-06-21 21:46:13 +02:00
|
|
|
|
2011-05-23 23:55:06 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool session_is_active(Session *s) {
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
if (!s->seat)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return s->seat->active == s;
|
|
|
|
}
|
|
|
|
|
2012-12-23 22:32:48 +01:00
|
|
|
static int get_tty_atime(const char *tty, usec_t *atime) {
|
|
|
|
_cleanup_free_ char *p = NULL;
|
2011-06-17 15:59:18 +02:00
|
|
|
struct stat st;
|
2012-12-23 22:32:48 +01:00
|
|
|
|
|
|
|
assert(tty);
|
|
|
|
assert(atime);
|
|
|
|
|
|
|
|
if (!path_is_absolute(tty)) {
|
|
|
|
p = strappend("/dev/", tty);
|
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
tty = p;
|
|
|
|
} else if (!path_startswith(tty, "/dev/"))
|
|
|
|
return -ENOENT;
|
|
|
|
|
|
|
|
if (lstat(tty, &st) < 0)
|
|
|
|
return -errno;
|
|
|
|
|
|
|
|
*atime = timespec_load(&st.st_atim);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
|
|
|
|
_cleanup_free_ char *p = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(pid > 0);
|
|
|
|
assert(atime);
|
|
|
|
|
|
|
|
r = get_ctty(pid, NULL, &p);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return get_tty_atime(p, atime);
|
|
|
|
}
|
|
|
|
|
|
|
|
int session_get_idle_hint(Session *s, dual_timestamp *t) {
|
|
|
|
usec_t atime = 0, n;
|
|
|
|
int r;
|
2011-06-17 15:59:18 +02:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2012-12-23 22:32:48 +01:00
|
|
|
/* Explicit idle hint is set */
|
2011-06-17 15:59:18 +02:00
|
|
|
if (s->idle_hint) {
|
|
|
|
if (t)
|
|
|
|
*t = s->idle_hint_timestamp;
|
|
|
|
|
|
|
|
return s->idle_hint;
|
|
|
|
}
|
|
|
|
|
2013-01-11 17:06:23 +01:00
|
|
|
/* Graphical sessions should really implement a real
|
2012-12-23 22:32:48 +01:00
|
|
|
* idle hint logic */
|
|
|
|
if (s->display)
|
2011-06-17 15:59:18 +02:00
|
|
|
goto dont_know;
|
|
|
|
|
2012-12-23 22:32:48 +01:00
|
|
|
/* For sessions with an explicitly configured tty, let's check
|
|
|
|
* its atime */
|
|
|
|
if (s->tty) {
|
|
|
|
r = get_tty_atime(s->tty, &atime);
|
|
|
|
if (r >= 0)
|
|
|
|
goto found_atime;
|
|
|
|
}
|
2011-06-17 15:59:18 +02:00
|
|
|
|
2012-12-23 22:32:48 +01:00
|
|
|
/* For sessions with a leader but no explicitly configured
|
|
|
|
* tty, let's check the controlling tty of the leader */
|
|
|
|
if (s->leader > 0) {
|
|
|
|
r = get_process_ctty_atime(s->leader, &atime);
|
|
|
|
if (r >= 0)
|
|
|
|
goto found_atime;
|
2011-06-17 15:59:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
dont_know:
|
|
|
|
if (t)
|
|
|
|
*t = s->idle_hint_timestamp;
|
|
|
|
|
|
|
|
return 0;
|
2012-12-23 22:32:48 +01:00
|
|
|
|
|
|
|
found_atime:
|
|
|
|
if (t)
|
|
|
|
dual_timestamp_from_realtime(t, atime);
|
|
|
|
|
|
|
|
n = now(CLOCK_REALTIME);
|
|
|
|
|
|
|
|
if (s->manager->idle_action_usec <= 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return atime + s->manager->idle_action_usec <= n;
|
2011-06-17 15:59:18 +02:00
|
|
|
}
|
|
|
|
|
2011-06-21 19:20:05 +02:00
|
|
|
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);
|
2011-06-21 21:46:13 +02:00
|
|
|
|
|
|
|
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");
|
2011-06-21 19:20:05 +02:00
|
|
|
}
|
|
|
|
|
2011-06-29 00:06:04 +02:00
|
|
|
int session_create_fifo(Session *s) {
|
|
|
|
int r;
|
|
|
|
|
2011-06-24 23:25:28 +02:00
|
|
|
assert(s);
|
|
|
|
|
2011-06-29 03:48:53 +02:00
|
|
|
/* Create FIFO */
|
2011-06-29 00:06:04 +02:00
|
|
|
if (!s->fifo_path) {
|
2012-05-31 12:40:20 +02:00
|
|
|
r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
|
2011-06-30 02:16:07 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2011-06-29 00:06:04 +02:00
|
|
|
if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
|
|
|
|
return -ENOMEM;
|
2011-06-24 23:25:28 +02:00
|
|
|
|
2011-06-29 00:06:04 +02:00
|
|
|
if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
|
|
|
|
return -errno;
|
|
|
|
}
|
2011-06-24 23:25:28 +02:00
|
|
|
|
2011-06-29 00:06:04 +02:00
|
|
|
/* Open reading side */
|
2011-06-29 03:48:53 +02:00
|
|
|
if (s->fifo_fd < 0) {
|
2013-03-25 00:59:00 +01:00
|
|
|
struct epoll_event ev = {};
|
2011-06-29 03:48:53 +02:00
|
|
|
|
|
|
|
s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
|
|
|
|
if (s->fifo_fd < 0)
|
|
|
|
return -errno;
|
|
|
|
|
2012-04-16 16:47:33 +02:00
|
|
|
r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
|
2011-06-29 03:48:53 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
ev.events = 0;
|
2012-05-30 15:01:51 +02:00
|
|
|
ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
|
2011-06-29 03:48:53 +02:00
|
|
|
|
|
|
|
if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
|
|
|
|
return -errno;
|
|
|
|
}
|
2011-06-29 00:06:04 +02:00
|
|
|
|
|
|
|
/* Open writing side */
|
|
|
|
r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
|
|
|
|
if (r < 0)
|
|
|
|
return -errno;
|
2011-06-24 23:25:28 +02:00
|
|
|
|
2011-06-29 00:06:04 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_remove_fifo(Session *s) {
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
if (s->fifo_fd >= 0) {
|
2012-04-16 16:47:33 +02:00
|
|
|
assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
|
2011-06-29 00:06:04 +02:00
|
|
|
assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
|
|
|
|
close_nointr_nofail(s->fifo_fd);
|
|
|
|
s->fifo_fd = -1;
|
2012-09-04 02:37:27 +02:00
|
|
|
|
|
|
|
session_save(s);
|
|
|
|
user_save(s->user);
|
2011-06-29 00:06:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (s->fifo_path) {
|
|
|
|
unlink(s->fifo_path);
|
|
|
|
free(s->fifo_path);
|
|
|
|
s->fifo_path = NULL;
|
|
|
|
}
|
2011-06-24 23:25:28 +02:00
|
|
|
}
|
|
|
|
|
2011-06-29 03:48:16 +02:00
|
|
|
int session_check_gc(Session *s, bool drop_not_started) {
|
2011-05-23 23:55:06 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2011-06-29 03:48:16 +02:00
|
|
|
if (drop_not_started && !s->started)
|
2011-06-29 00:06:04 +02:00
|
|
|
return 0;
|
|
|
|
|
2013-06-20 03:45:08 +02:00
|
|
|
if (!s->user)
|
|
|
|
return 0;
|
|
|
|
|
2011-06-29 00:06:04 +02:00
|
|
|
if (s->fifo_fd >= 0) {
|
|
|
|
r = pipe_eof(s->fifo_fd);
|
2011-05-23 23:55:06 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2011-05-25 00:55:58 +02:00
|
|
|
if (r == 0)
|
2011-05-23 23:55:06 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-07-02 01:46:30 +02:00
|
|
|
if (s->scope_job)
|
|
|
|
return 1;
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2013-07-02 01:46:30 +02:00
|
|
|
if (s->scope)
|
|
|
|
return manager_unit_is_active(s->manager, s->scope) != 0;
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-05-25 00:55:58 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-06-21 16:14:53 +02:00
|
|
|
SessionState session_get_state(Session *s) {
|
|
|
|
assert(s);
|
|
|
|
|
2013-08-13 17:59:28 +02:00
|
|
|
if (s->closing)
|
|
|
|
return SESSION_CLOSING;
|
|
|
|
|
2013-07-02 01:46:30 +02:00
|
|
|
if (s->scope_job)
|
2013-08-13 17:59:28 +02:00
|
|
|
return SESSION_OPENING;
|
2013-07-02 01:46:30 +02:00
|
|
|
|
2012-06-21 16:14:53 +02:00
|
|
|
if (s->fifo_fd < 0)
|
|
|
|
return SESSION_CLOSING;
|
|
|
|
|
|
|
|
if (session_is_active(s))
|
|
|
|
return SESSION_ACTIVE;
|
|
|
|
|
|
|
|
return SESSION_ONLINE;
|
|
|
|
}
|
|
|
|
|
2011-07-13 19:58:35 +02:00
|
|
|
int session_kill(Session *s, KillWho who, int signo) {
|
|
|
|
assert(s);
|
|
|
|
|
2013-07-02 01:46:30 +02:00
|
|
|
if (!s->scope)
|
2011-07-13 19:58:35 +02:00
|
|
|
return -ESRCH;
|
|
|
|
|
2013-07-02 01:46:30 +02:00
|
|
|
return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
|
2011-07-13 19:58:35 +02:00
|
|
|
}
|
|
|
|
|
2013-09-17 17:39:56 +02:00
|
|
|
bool session_is_controller(Session *s, const char *sender)
|
|
|
|
{
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
return streq_ptr(s->controller, sender);
|
|
|
|
}
|
|
|
|
|
|
|
|
int session_set_controller(Session *s, const char *sender, bool force) {
|
|
|
|
char *t;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
assert(sender);
|
|
|
|
|
|
|
|
if (session_is_controller(s, sender))
|
|
|
|
return 0;
|
|
|
|
if (s->controller && !force)
|
|
|
|
return -EBUSY;
|
|
|
|
|
|
|
|
t = strdup(sender);
|
|
|
|
if (!t)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
r = manager_watch_busname(s->manager, sender);
|
|
|
|
if (r) {
|
|
|
|
free(t);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
session_drop_controller(s);
|
|
|
|
|
|
|
|
s->controller = t;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_drop_controller(Session *s) {
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
if (!s->controller)
|
|
|
|
return;
|
|
|
|
|
|
|
|
manager_drop_busname(s->manager, s->controller);
|
|
|
|
free(s->controller);
|
|
|
|
s->controller = NULL;
|
|
|
|
}
|
|
|
|
|
2013-07-02 01:46:30 +02:00
|
|
|
static const char* const session_state_table[_SESSION_STATE_MAX] = {
|
|
|
|
[SESSION_OPENING] = "opening",
|
2012-06-21 16:14:53 +02:00
|
|
|
[SESSION_ONLINE] = "online",
|
|
|
|
[SESSION_ACTIVE] = "active",
|
|
|
|
[SESSION_CLOSING] = "closing"
|
|
|
|
};
|
|
|
|
|
|
|
|
DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
|
|
|
|
|
2011-05-23 23:55:06 +02:00
|
|
|
static const char* const session_type_table[_SESSION_TYPE_MAX] = {
|
2011-05-26 02:21:16 +02:00
|
|
|
[SESSION_TTY] = "tty",
|
2011-06-24 18:50:50 +02:00
|
|
|
[SESSION_X11] = "x11",
|
2011-06-24 23:50:39 +02:00
|
|
|
[SESSION_UNSPECIFIED] = "unspecified"
|
2011-05-23 23:55:06 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
|
2011-07-13 19:58:35 +02:00
|
|
|
|
2012-02-14 21:33:51 +01:00
|
|
|
static const char* const session_class_table[_SESSION_CLASS_MAX] = {
|
|
|
|
[SESSION_USER] = "user",
|
|
|
|
[SESSION_GREETER] = "greeter",
|
2013-04-09 22:18:16 +02:00
|
|
|
[SESSION_LOCK_SCREEN] = "lock-screen",
|
|
|
|
[SESSION_BACKGROUND] = "background"
|
2012-02-14 21:33:51 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
|
|
|
|
|
2011-07-13 19:58:35 +02:00
|
|
|
static const char* const kill_who_table[_KILL_WHO_MAX] = {
|
|
|
|
[KILL_LEADER] = "leader",
|
|
|
|
[KILL_ALL] = "all"
|
|
|
|
};
|
|
|
|
|
|
|
|
DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
|