logind-core.c revision 157f50577fbee094eb8ca18f3f0af4e82af8558f
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2011 Lennart Poettering
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
(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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <fcntl.h>
#include <pwd.h>
#include "alloc-util.h"
#include "bus-error.h"
#include "bus-util.h"
#include "cgroup-util.h"
#include "fd-util.h"
#include "logind.h"
#include "strv.h"
#include "terminal-util.h"
#include "udev-util.h"
#include "user-util.h"
Device *d;
assert(m);
if (d)
/* we support adding master-flags, but not removing them */
else {
if (!d)
return -ENOMEM;
}
if (_device)
*_device = d;
return 0;
}
Seat *s;
assert(m);
if (!s) {
if (!s)
return -ENOMEM;
}
if (_seat)
*_seat = s;
return 0;
}
Session *s;
assert(m);
if (!s) {
s = session_new(m, id);
if (!s)
return -ENOMEM;
}
if (_session)
*_session = s;
return 0;
}
User *u;
int r;
assert(m);
if (!u) {
if (r < 0)
return r;
}
if (_user)
*_user = u;
return 0;
}
int r;
assert(m);
if (r < 0)
return r;
}
struct passwd *p;
assert(m);
errno = 0;
if (!p)
}
Inhibitor *i;
assert(m);
if (i) {
if (_inhibitor)
*_inhibitor = i;
return 0;
}
i = inhibitor_new(m, id);
if (!i)
return -ENOMEM;
if (_inhibitor)
*_inhibitor = i;
return 0;
}
Button *b;
assert(m);
if (!b) {
b = button_new(m, name);
if (!b)
return -ENOMEM;
}
if (_button)
*_button = b;
return 0;
}
int r;
assert(m);
if (!device)
return 0;
} else {
const char *sn;
bool master;
sn = "seat0";
if (!seat_name_is_valid(sn)) {
return 0;
}
/* Ignore non-master devices for unknown seats */
return 0;
if (r < 0)
return r;
if (!seat) {
if (r < 0) {
return r;
}
}
}
return 0;
}
Button *b;
int r;
assert(m);
if (!b)
return 0;
button_free(b);
} else {
const char *sn;
r = manager_add_button(m, udev_device_get_sysname(d), &b);
if (r < 0)
return r;
sn = "seat0";
button_set_seat(b, sn);
button_open(b);
}
return 0;
}
Session *s;
int r;
assert(m);
if (pid < 1)
return -EINVAL;
if (r < 0)
return 0;
if (!s)
return 0;
if (session)
*session = s;
return 1;
}
User *u;
int r;
assert(m);
if (pid < 1)
return -EINVAL;
if (r < 0)
return 0;
if (!u)
return 0;
*user = u;
return 1;
}
Session *s;
bool idle_hint;
Iterator i;
assert(m);
HASHMAP_FOREACH(s, m->sessions, i) {
int ih;
ih = session_get_idle_hint(s, &k);
if (ih < 0)
return ih;
if (!ih) {
if (!idle_hint) {
ts = k;
} else {
idle_hint = false;
ts = k;
}
} else if (idle_hint) {
ts = k;
}
}
if (t)
*t = ts;
return idle_hint;
}
assert(m);
if (!m->kill_user_processes)
return false;
return false;
if (strv_isempty(m->kill_only_users))
return true;
}
static int vt_is_busy(unsigned int vtnr) {
int r = 0;
_cleanup_close_ int fd;
* we'd open the latter we'd open the foreground tty which
* we avoid this. Since tty1 is special and needs to be an
* explicitly loaded getty or DM this is safe. */
if (fd < 0)
return -errno;
r = -errno;
else
return r;
}
int r;
assert(m);
vtnr != m->reserve_vt)
return 0;
if (vtnr != m->reserve_vt) {
/* If this is the reserved TTY, we'll start the getty
* on it in any case, but otherwise only if it is not
* busy. */
r = vt_is_busy(vtnr);
if (r < 0)
return r;
else if (r > 0)
return -EBUSY;
}
r = sd_bus_call_method(
m->bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"StartUnit",
&error,
NULL,
if (r < 0)
return r;
}
static bool manager_is_docked(Manager *m) {
Iterator i;
Button *b;
HASHMAP_FOREACH(b, m->buttons, i)
if (b->docked)
return true;
return false;
}
static int manager_count_external_displays(Manager *m) {
int r;
int n = 0;
e = udev_enumerate_new(m->udev);
if (!e)
return -ENOMEM;
r = udev_enumerate_add_match_subsystem(e, "drm");
if (r < 0)
return r;
r = udev_enumerate_scan_devices(e);
if (r < 0)
return r;
struct udev_device *p;
bool external = false;
if (!d)
return -ENOMEM;
p = udev_device_get_parent(d);
if (!p)
continue;
/* If the parent shares the same subsystem as the
* device we are looking at then it is a connector,
* which is what we are interested in. */
continue;
nn = udev_device_get_sysname(d);
if (!nn)
continue;
/* Ignore internal displays: the type is encoded in
* the sysfs name, as the second dash seperated item
* (the first is the card name, the last the connector
* number). We implement a whitelist of external
* displays here, rather than a whitelist, to ensure
* we don't block suspends too eagerly. */
if (!dash)
continue;
dash++;
"Composite-", "SVIDEO-", "Component-",
"DIN-", "DP-", "HDMI-A-", "HDMI-B-", "TV-") {
if (startswith(dash, i)) {
external = true;
break;
}
}
if (!external)
continue;
/* Ignore ports that are not enabled */
if (!enabled)
continue;
continue;
/* We count any connector which is not explicitly
* "disconnected" as connected. */
n++;
}
return n;
}
bool manager_is_docked_or_external_displays(Manager *m) {
int n;
/* If we are docked don't react to lid closing */
if (manager_is_docked(m)) {
log_debug("System is docked.");
return true;
}
/* If we have more than one display connected,
* assume that we are docked. */
n = manager_count_external_displays(m);
if (n < 0)
log_warning_errno(n, "Display counting failed: %m");
else if (n >= 1) {
log_debug("External (%i) displays connected.", n);
return true;
}
return false;
}