summaryrefslogtreecommitdiff
path: root/src/login
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2013-10-01 17:53:43 +0200
committerDavid Herrmann <dh.herrmann@gmail.com>2013-10-01 17:53:43 +0200
commitc2e5d024a380bae6ead301fb4f40787b372ec3e0 (patch)
treeef7ecb86df3823a6996dbecea97c6344fe03a34c /src/login
parent081dfa852fc5cd183a20747f2d8e4ef62d29d181 (diff)
logind: check whether first drmSetMaster succeeded
The initial drmSetMaster may fail if there is an active master already. We must not assume that all existing clients comply to logind rules. We check for this during session-activation already but didn't during device setup. Fix this by checking the return code. As drmSetMaster has had horrible return codes in the past (0 for failure? EINVAL for denied access, ..) we need to be quite pedantic. To guarantee an open file-descriptor we need to close the device and reopen it without master if setting master failed first.
Diffstat (limited to 'src/login')
-rw-r--r--src/login/logind-session-device.c30
1 files changed, 23 insertions, 7 deletions
diff --git a/src/login/logind-session-device.c b/src/login/logind-session-device.c
index 27afafa1aa..546c53710e 100644
--- a/src/login/logind-session-device.c
+++ b/src/login/logind-session-device.c
@@ -144,7 +144,7 @@ static int sd_drmdropmaster(int fd) {
}
static int session_device_open(SessionDevice *sd, bool active) {
- int fd;
+ int fd, r;
assert(sd->type != DEVICE_TYPE_UNKNOWN);
@@ -155,9 +155,17 @@ static int session_device_open(SessionDevice *sd, bool active) {
switch (sd->type) {
case DEVICE_TYPE_DRM:
- if (active)
- sd_drmsetmaster(fd);
- else {
+ if (active) {
+ /* Weird legacy DRM semantics might return an error
+ * even though we're master. No way to detect that so
+ * fail at all times and let caller retry in inactive
+ * state. */
+ r = sd_drmsetmaster(fd);
+ if (r < 0) {
+ close(fd);
+ return r;
+ }
+ } else {
/* DRM-Master is granted to the first user who opens a
* device automatically (ughh, racy!). Hence, we just
* drop DRM-Master in case we were the first. */
@@ -384,9 +392,17 @@ int session_device_new(Session *s, dev_t dev, SessionDevice **out) {
* revoke access and thus invalidate the fd. But this is still needed
* to pass a valid fd back. */
sd->active = session_is_active(s);
- sd->fd = session_device_open(sd, sd->active);
- if (sd->fd < 0)
- goto error;
+ r = session_device_open(sd, sd->active);
+ if (r < 0) {
+ /* EINVAL _may_ mean a master is active; retry inactive */
+ if (sd->active && r == -EINVAL) {
+ sd->active = false;
+ r = session_device_open(sd, false);
+ }
+ if (r < 0)
+ goto error;
+ }
+ sd->fd = r;
LIST_PREPEND(SessionDevice, sd_by_device, sd->device->session_devices, sd);