Browse Source

Use systemd/elogind to set brightness if possible

Since version 243, systemd-logind supports setting the brightness of an
"leds" or "backlight" kernel class device [1]. This method call requires
no privileges to call, but a caller can only change the brightness on
sessions that are currently active, and they must own the session.

Using systemd/elogind for unprivileged brightness changes is a nice
feature to have since it allows to changes brightness without giving
explicit permissions to users via groups or setting SUID bit.

[1] https://github.com/systemd/systemd/commit/2a66c2a1eda48433cb7f4ac6e9b9abcf4bd41bf3
Ihor Kalnytskyi 4 years ago
parent
commit
bce9c8f175
No account linked to committer's email
4 changed files with 70 additions and 0 deletions
  1. 20
    0
      configure.ac
  2. 43
    0
      src/helpers.c
  3. 3
    0
      src/helpers.h
  4. 4
    0
      src/impl/sysfs.c

+ 20
- 0
configure.ac View File

13
 AC_ARG_WITH([udev],
13
 AC_ARG_WITH([udev],
14
 	AS_HELP_STRING([--with-udev@<:@=PATH@:>@], [use udev instead of SUID root, optional rules.d path]),
14
 	AS_HELP_STRING([--with-udev@<:@=PATH@:>@], [use udev instead of SUID root, optional rules.d path]),
15
 	[udev=$withval], [udev=no])
15
 	[udev=$withval], [udev=no])
16
+AC_ARG_WITH([systemd],
17
+	AS_HELP_STRING([--with-systemd], [use systemd-logind for unprivileged brightness changes]),
18
+	[], [systemd=no])
19
+AC_ARG_WITH([elogind],
20
+	AS_HELP_STRING([--with-elogind], [use elogind for unprivileged brightness changes]),
21
+	[], [elogind=no])
16
 
22
 
17
 AC_MSG_CHECKING(for udev rules.d)
23
 AC_MSG_CHECKING(for udev rules.d)
18
 AS_IF([test "x$udev" != "xno"], [
24
 AS_IF([test "x$udev" != "xno"], [
27
 	AC_MSG_RESULT([disabled, classic SUID root mode])
33
 	AC_MSG_RESULT([disabled, classic SUID root mode])
28
 ])
34
 ])
29
 
35
 
36
+AC_MSG_CHECKING(for systemd)
37
+AS_IF([test "x$systemd" != "xno"], [
38
+	AC_CHECK_LIB([systemd], [sd_bus_call_method])
39
+],[
40
+	AC_MSG_RESULT([disabled])
41
+])
42
+
43
+AC_MSG_CHECKING(for elogind)
44
+AS_IF([test "x$elogind" != "xno"], [
45
+	AC_CHECK_LIB([elogind], [sd_bus_call_method])
46
+],[
47
+	AC_MSG_RESULT([disabled])
48
+])
49
+
30
 # Allow classic SUID root behavior if udev rule is not used
50
 # Allow classic SUID root behavior if udev rule is not used
31
 AM_CONDITIONAL(UDEV,    [test "x$udev" != "xno"])
51
 AM_CONDITIONAL(UDEV,    [test "x$udev" != "xno"])
32
 AM_CONDITIONAL(CLASSIC, [test "x$udev"  = "xno"])
52
 AM_CONDITIONAL(CLASSIC, [test "x$udev"  = "xno"])

+ 43
- 0
src/helpers.c View File

1
+#include "light.h"
1
 #include "helpers.h"
2
 #include "helpers.h"
2
 
3
 
3
 #include <stdio.h>
4
 #include <stdio.h>
9
 #include <errno.h> // errno
10
 #include <errno.h> // errno
10
 #include <libgen.h> // dirname 
11
 #include <libgen.h> // dirname 
11
 
12
 
13
+#if HAVE_LIBSYSTEMD
14
+#include <systemd/sd-bus.h>
15
+#elif HAVE_LIBELOGIND
16
+#include <elogind/sd-bus.h>
17
+#endif
12
 
18
 
13
 bool light_file_read_uint64(char const *filename, uint64_t *val)
19
 bool light_file_read_uint64(char const *filename, uint64_t *val)
14
 {
20
 {
146
     return mkdir(dir, mode);
152
     return mkdir(dir, mode);
147
 }
153
 }
148
 
154
 
155
+#if HAVE_LIBSYSTEMD || HAVE_LIBELOGIND
156
+bool light_logind_set_brightness(light_device_target_t *target, uint64_t in_value) {
157
+    sd_bus *bus = NULL;
158
+    sd_bus_message *message = NULL;
159
+    sd_bus_error error = SD_BUS_ERROR_NULL;
160
+
161
+    int ret = sd_bus_default_system(&bus);
162
+
163
+    if (ret < 0) {
164
+        LIGHT_ERR("Failed to open D-Bus connection: %s", strerror(-ret));
165
+        return false;
166
+    }
167
+
168
+    ret = sd_bus_call_method(
169
+        bus,
170
+        "org.freedesktop.login1",
171
+        "/org/freedesktop/login1/session/auto",
172
+        "org.freedesktop.login1.Session",
173
+        "SetBrightness",
174
+        &error,
175
+        &message,
176
+        "ssu",
177
+        target->device->name,
178
+        target->name,
179
+        in_value
180
+    );
181
+
182
+    if (ret < 0) {
183
+        LIGHT_ERR("Failed to set brightness: %s", error.message);
184
+    }
185
+
186
+    sd_bus_error_free(&error);
187
+    sd_bus_message_unref(message);
188
+    sd_bus_unref(bus);
189
+    return ret >= 0;
190
+}
191
+#endif  // HAVE_LIBSYSTEMD || HAVE_LIBELOGIND

+ 3
- 0
src/helpers.h View File

54
 
54
 
55
 int light_mkpath(char *dir, mode_t mode);
55
 int light_mkpath(char *dir, mode_t mode);
56
 
56
 
57
+#if HAVE_LIBSYSTEMD || HAVE_LIBELOGIND
58
+bool light_logind_set_brightness(light_device_target_t *target, uint64_t in_value);
59
+#endif

+ 4
- 0
src/impl/sysfs.c View File

131
     if(!light_file_write_uint64(data->brightness, in_value))
131
     if(!light_file_write_uint64(data->brightness, in_value))
132
     {
132
     {
133
         LIGHT_ERR("failed to write to sysfs device");
133
         LIGHT_ERR("failed to write to sysfs device");
134
+
135
+#if HAVE_LIBSYSTEMD || HAVE_LIBELOGIND
136
+        return light_logind_set_brightness(target, in_value);
137
+#endif
134
         return false;
138
         return false;
135
     }
139
     }
136
     
140