File 0001-logind-keep-backward-compatibility-with-UserTasksMax.patch of Package systemd

From ce59acc7743f1897a335449b718f9ede33add394 Mon Sep 17 00:00:00 2001
From: Franck Bui <fbui@suse.com>
Date: Tue, 6 Nov 2018 11:51:26 +0100
Subject: [PATCH] logind: keep backward compatibility with UserTasksMax= in
 logind.conf

Since commit 284149392755f086d0a71, UserTasksMax= support has been simply
dropped.

A generator is used to automatically create an appropriate dropin that has the
same effect. However since the snippet is generated in /run, sysadmin is
encouraged to copy it in /etc to make it persistent.

The main advantages to use a generator are:

 - sysadmin is aware of this backward incompatible change

 - he will be the one who will fix logind.conf manually (to remove the use of
   UserTasksMax=)

 - he will decide how to name the snippet and possibly merge it with an
   existing one

Expect this generator to be dropped in the future.
---
 meson.build                            |  8 +++
 src/login/compat-tasks-max-generator.c | 68 ++++++++++++++++++++++++++
 src/login/logind-user.c                | 43 ++++++++++++++--
 3 files changed, 114 insertions(+), 5 deletions(-)
 create mode 100644 src/login/compat-tasks-max-generator.c

diff --git a/meson.build b/meson.build
index dc6e970095..d834108f24 100644
--- a/meson.build
+++ b/meson.build
@@ -1885,6 +1885,14 @@ if conf.get('ENABLE_LOGIND') == 1
                 endif
         endif
 
+        executable('logind-compat-tasks-max-generator',
+                   'src/login/compat-tasks-max-generator.c',
+                   include_directories : includes,
+                   link_with : [libshared, liblogind_core],
+                   install_rpath : rootlibexecdir,
+                   install : true,
+                   install_dir : systemgeneratordir)
+
         executable('systemd-user-runtime-dir',
                    user_runtime_dir_sources,
                    include_directories : includes,
diff --git a/src/login/compat-tasks-max-generator.c b/src/login/compat-tasks-max-generator.c
new file mode 100644
index 0000000000..964d0596fb
--- /dev/null
+++ b/src/login/compat-tasks-max-generator.c
@@ -0,0 +1,68 @@
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "alloc-util.h"
+#include "dropin.h"
+#include "logind.h"
+#include "path-util.h"
+
+static const char *arg_dest = "/tmp";
+
+static int read_manager_configuration(uint64_t *user_tasks_max) {
+        Manager m = {};
+        int r;
+
+        manager_reset_config(&m);
+        m.user_tasks_max = 0;
+
+        r = manager_parse_config_file(&m);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to parse logind.conf: %m");
+
+        if (m.user_tasks_max == 0)
+                return 0;
+
+        *user_tasks_max = m.user_tasks_max;
+        return 1;
+}
+
+int main(int argc, char *argv[]) {
+        _cleanup_free_ char *p = NULL;
+        uint64_t user_tasks_max;
+        int r = 0;
+
+        if (argc > 1 && argc != 4) {
+                log_error("This program takes three or no arguments.");
+                return EXIT_FAILURE;
+        }
+
+        if (argc > 1)
+                arg_dest = argv[1];
+
+        log_set_prohibit_ipc(true);
+        log_set_target(LOG_TARGET_AUTO);
+        log_parse_environment();
+        log_open();
+
+        umask(0022);
+
+        r = read_manager_configuration(&user_tasks_max);
+        if (r == 0)
+                return EXIT_SUCCESS;
+        if (r < 0)
+                return EXIT_FAILURE;
+
+        p = path_join(arg_dest, "user-.slice.d", "50-limits.conf");
+        if (!p)
+                return EXIT_FAILURE;
+
+        log_warning("Creating %s to keep compability\n"
+                    "Consider copying the snippet in /etc/systemd/system/user-.slice.d/\n", p);
+
+        r = write_drop_in_format(arg_dest, "user-.slice", 50, "limits",
+                                 "# Automatically generated by logind-compat-tasks-max-generator\n\n"
+                                 "[Slice]\nTasksMax=%" PRIu64, user_tasks_max);
+
+        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
index 045b6f0e17..1c19d6512b 100644
--- a/src/login/logind-user.c
+++ b/src/login/logind-user.c
@@ -847,17 +847,50 @@ int config_parse_compat_user_tasks_max(
                 void *data,
                 void *userdata) {
 
+        uint64_t *m = data;
+        uint64_t k;
+        int r;
+
         assert(filename);
         assert(lvalue);
         assert(rvalue);
         assert(data);
 
-        log_syntax(unit, LOG_NOTICE, filename, line, 0,
+        log_syntax(unit, LOG_WARNING, filename, line, 0,
                    "Support for option %s= has been removed.",
                    lvalue);
-        log_info("Hint: try creating /etc/systemd/system/user-.slice.d/50-limits.conf with:\n"
-                 "        [Slice]\n"
-                 "        TasksMax=%s",
-                 rvalue);
+
+        if (isempty(rvalue)) {
+                *m = system_tasks_max_scale(DEFAULT_USER_TASKS_MAX_PERCENTAGE, 100U);
+                return 0;
+        }
+
+        if (streq(rvalue, "infinity")) {
+                *m = CGROUP_LIMIT_MAX;
+                return 0;
+        }
+
+        /* Try to parse as percentage */
+        r = parse_percent(rvalue);
+        if (r >= 0)
+                k = system_tasks_max_scale(r, 100U);
+        else {
+
+                /* If the passed argument was not a percentage, or out of range, parse as byte size */
+
+                r = safe_atou64(rvalue, &k);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse tasks maximum, ignoring: %s", rvalue);
+                        return 0;
+                }
+        }
+
+        if (k <= 0 || k >= UINT64_MAX) {
+                log_syntax(unit, LOG_ERR, filename, line, 0, "Tasks maximum out of range, ignoring: %s", rvalue);
+                return 0;
+        }
+
+        *m = k;
+
         return 0;
 }
-- 
2.21.0