]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
rlimit-util: rework rlimit_{from|to}_string() to work without "Limit" prefix
authorLennart Poettering <lennart@poettering.net>
Thu, 3 May 2018 16:45:39 +0000 (18:45 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 17 May 2018 18:36:52 +0000 (20:36 +0200)
let's make the call more generic, so that we can also easily use it for
parsing "RLIMIT_xyz" style constants.

src/basic/rlimit-util.c
src/basic/rlimit-util.h
src/core/dbus-execute.c
src/core/execute.c
src/shared/bus-unit-util.c
src/shared/bus-util.c
src/test/test-rlimit-util.c

index d371f0a550a3691aa6444c15dcdfa64a52ad3a2e..154b34b8c1b54c2bbbcd4372e111ecc6d3842c11 100644 (file)
@@ -289,22 +289,38 @@ int rlimit_format(const struct rlimit *rl, char **ret) {
 }
 
 static const char* const rlimit_table[_RLIMIT_MAX] = {
-        [RLIMIT_CPU] = "LimitCPU",
-        [RLIMIT_FSIZE] = "LimitFSIZE",
-        [RLIMIT_DATA] = "LimitDATA",
-        [RLIMIT_STACK] = "LimitSTACK",
-        [RLIMIT_CORE] = "LimitCORE",
-        [RLIMIT_RSS] = "LimitRSS",
-        [RLIMIT_NOFILE] = "LimitNOFILE",
-        [RLIMIT_AS] = "LimitAS",
-        [RLIMIT_NPROC] = "LimitNPROC",
-        [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
-        [RLIMIT_LOCKS] = "LimitLOCKS",
-        [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
-        [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
-        [RLIMIT_NICE] = "LimitNICE",
-        [RLIMIT_RTPRIO] = "LimitRTPRIO",
-        [RLIMIT_RTTIME] = "LimitRTTIME"
+        [RLIMIT_AS]         = "AS",
+        [RLIMIT_CORE]       = "CORE",
+        [RLIMIT_CPU]        = "CPU",
+        [RLIMIT_DATA]       = "DATA",
+        [RLIMIT_FSIZE]      = "FSIZE",
+        [RLIMIT_LOCKS]      = "LOCKS",
+        [RLIMIT_MEMLOCK]    = "MEMLOCK",
+        [RLIMIT_MSGQUEUE]   = "MSGQUEUE",
+        [RLIMIT_NICE]       = "NICE",
+        [RLIMIT_NOFILE]     = "NOFILE",
+        [RLIMIT_NPROC]      = "NPROC",
+        [RLIMIT_RSS]        = "RSS",
+        [RLIMIT_RTPRIO]     = "RTPRIO",
+        [RLIMIT_RTTIME]     = "RTTIME",
+        [RLIMIT_SIGPENDING] = "SIGPENDING",
+        [RLIMIT_STACK]      = "STACK",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
+
+int rlimit_from_string_harder(const char *s) {
+        const char *suffix;
+
+        /* The official prefix */
+        suffix = startswith(s, "RLIMIT_");
+        if (suffix)
+                return rlimit_from_string(suffix);
+
+        /* Our own unit file setting prefix */
+        suffix = startswith(s, "Limit");
+        if (suffix)
+                return rlimit_from_string(suffix);
+
+        return rlimit_from_string(s);
+}
index 3766f78d5854af18c372d6c8ba4fbdfd1f2f57b4..42f2e0e5471cd0dcbff0c3ff9821dcc34127a426 100644 (file)
@@ -13,6 +13,7 @@
 
 const char *rlimit_to_string(int i) _const_;
 int rlimit_from_string(const char *s) _pure_;
+int rlimit_from_string_harder(const char *s) _pure_;
 
 int setrlimit_closest(int resource, const struct rlimit *rlim);
 
index 3b1c77e967659e6b3aa1e65e815e0c5d404f13a4..143fca71b03a1885a67bb8db80bf56583f0421d5 100644 (file)
@@ -1091,8 +1091,8 @@ int bus_exec_context_set_transient_property(
                 UnitWriteFlags flags,
                 sd_bus_error *error) {
 
-        const char *soft = NULL;
-        int r, ri;
+        const char *suffix;
+        int r;
 
         assert(u);
         assert(c);
@@ -2313,73 +2313,77 @@ int bus_exec_context_set_transient_property(
                 }
 
                 return 1;
-        }
 
-        ri = rlimit_from_string(name);
-        if (ri < 0) {
-                soft = endswith(name, "Soft");
-                if (soft) {
-                        const char *n;
+        } else if ((suffix = startswith(name, "Limit"))) {
+                const char *soft = NULL;
+                int ri;
 
-                        n = strndupa(name, soft - name);
-                        ri = rlimit_from_string(n);
-                        if (ri >= 0)
-                                name = n;
+                ri = rlimit_from_string(suffix);
+                if (ri < 0) {
+                        soft = endswith(suffix, "Soft");
+                        if (soft) {
+                                const char *n;
 
+                                n = strndupa(suffix, soft - suffix);
+                                ri = rlimit_from_string(n);
+                                if (ri >= 0)
+                                        name = strjoina("Limit", n);
+                        }
                 }
-        }
-
-        if (ri >= 0) {
-                uint64_t rl;
-                rlim_t x;
-
-                r = sd_bus_message_read(message, "t", &rl);
-                if (r < 0)
-                        return r;
-
-                if (rl == (uint64_t) -1)
-                        x = RLIM_INFINITY;
-                else {
-                        x = (rlim_t) rl;
 
-                        if ((uint64_t) x != rl)
-                                return -ERANGE;
-                }
+                if (ri >= 0) {
+                        uint64_t rl;
+                        rlim_t x;
 
-                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
-                        _cleanup_free_ char *f = NULL;
-                        struct rlimit nl;
-
-                        if (c->rlimit[ri]) {
-                                nl = *c->rlimit[ri];
-
-                                if (soft)
-                                        nl.rlim_cur = x;
-                                else
-                                        nl.rlim_max = x;
-                        } else
-                                /* When the resource limit is not initialized yet, then assign the value to both fields */
-                                nl = (struct rlimit) {
-                                        .rlim_cur = x,
-                                        .rlim_max = x,
-                                };
-
-                        r = rlimit_format(&nl, &f);
+                        r = sd_bus_message_read(message, "t", &rl);
                         if (r < 0)
                                 return r;
 
-                        if (c->rlimit[ri])
-                                *c->rlimit[ri] = nl;
+                        if (rl == (uint64_t) -1)
+                                x = RLIM_INFINITY;
                         else {
-                                c->rlimit[ri] = newdup(struct rlimit, &nl, 1);
-                                if (!c->rlimit[ri])
-                                        return -ENOMEM;
+                                x = (rlim_t) rl;
+
+                                if ((uint64_t) x != rl)
+                                        return -ERANGE;
                         }
 
-                        unit_write_settingf(u, flags, name, "%s=%s", name, f);
+                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                                _cleanup_free_ char *f = NULL;
+                                struct rlimit nl;
+
+                                if (c->rlimit[ri]) {
+                                        nl = *c->rlimit[ri];
+
+                                        if (soft)
+                                                nl.rlim_cur = x;
+                                        else
+                                                nl.rlim_max = x;
+                                } else
+                                        /* When the resource limit is not initialized yet, then assign the value to both fields */
+                                        nl = (struct rlimit) {
+                                                .rlim_cur = x,
+                                                .rlim_max = x,
+                                        };
+
+                                r = rlimit_format(&nl, &f);
+                                if (r < 0)
+                                        return r;
+
+                                if (c->rlimit[ri])
+                                        *c->rlimit[ri] = nl;
+                                else {
+                                        c->rlimit[ri] = newdup(struct rlimit, &nl, 1);
+                                        if (!c->rlimit[ri])
+                                                return -ENOMEM;
+                                }
+
+                                unit_write_settingf(u, flags, name, "%s=%s", name, f);
+                        }
+
+                        return 1;
                 }
 
-                return 1;
         }
 
         return 0;
index fca20c556783a27335366abd53fc47cb08a5f3f5..d60e8f6a1ac947d74a3d3051a46814c4985fae2a 100644 (file)
@@ -3176,7 +3176,7 @@ static int exec_child(
                         r = setrlimit_closest(i, context->rlimit[i]);
                         if (r < 0) {
                                 *exit_status = EXIT_LIMITS;
-                                return log_unit_error_errno(unit, r, "Failed to adjust resource limit %s: %m", rlimit_to_string(i));
+                                return log_unit_error_errno(unit, r, "Failed to adjust resource limit RLIMIT_%s: %m", rlimit_to_string(i));
                         }
                 }
 
@@ -3975,9 +3975,9 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
 
         for (i = 0; i < RLIM_NLIMITS; i++)
                 if (c->rlimit[i]) {
-                        fprintf(f, "%s%s: " RLIM_FMT "\n",
+                        fprintf(f, "Limit%s%s: " RLIM_FMT "\n",
                                 prefix, rlimit_to_string(i), c->rlimit[i]->rlim_max);
-                        fprintf(f, "%s%sSoft: " RLIM_FMT "\n",
+                        fprintf(f, "Limit%s%sSoft: " RLIM_FMT "\n",
                                 prefix, rlimit_to_string(i), c->rlimit[i]->rlim_cur);
                 }
 
index 78d5141053dbe4cff35f19798eb6e125a6a0d6c4..fc035e796ebd24c94b0818de066a1d98dbe80961 100644 (file)
@@ -684,7 +684,8 @@ static int bus_append_automount_property(sd_bus_message *m, const char *field, c
 }
 
 static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) {
-        int r, rl;
+        const char *suffix;
+        int r;
 
         if (STR_IN_SET(field,
                        "User", "Group",
@@ -863,25 +864,29 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
                 return bus_append_byte_array(m, field, decoded, sz);
         }
 
-        rl = rlimit_from_string(field);
-        if (rl >= 0) {
-                const char *sn;
-                struct rlimit l;
+        if ((suffix = startswith(field, "Limit"))) {
+                int rl;
 
-                r = rlimit_parse(rl, eq, &l);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to parse resource limit: %s", eq);
+                rl = rlimit_from_string(suffix);
+                if (rl >= 0) {
+                        const char *sn;
+                        struct rlimit l;
 
-                r = sd_bus_message_append(m, "(sv)", field, "t", l.rlim_max);
-                if (r < 0)
-                        return bus_log_create_error(r);
+                        r = rlimit_parse(rl, eq, &l);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse resource limit: %s", eq);
 
-                sn = strjoina(field, "Soft");
-                r = sd_bus_message_append(m, "(sv)", sn, "t", l.rlim_cur);
-                if (r < 0)
-                        return bus_log_create_error(r);
+                        r = sd_bus_message_append(m, "(sv)", field, "t", l.rlim_max);
+                        if (r < 0)
+                                return bus_log_create_error(r);
 
-                return 1;
+                        sn = strjoina(field, "Soft");
+                        r = sd_bus_message_append(m, "(sv)", sn, "t", l.rlim_cur);
+                        if (r < 0)
+                                return bus_log_create_error(r);
+
+                        return 1;
+                }
         }
 
         if (STR_IN_SET(field, "AppArmorProfile", "SmackProcessLabel")) {
index 66724d0e7841c2eac75c98c0d52d6b7b609a2dc9..c80fc4fcbb6c0c6f39930758fe7bba12355b6aee 100644 (file)
@@ -1613,36 +1613,40 @@ int bus_property_get_rlimit(
                 void *userdata,
                 sd_bus_error *error) {
 
+        const char *is_soft;
         struct rlimit *rl;
         uint64_t u;
         rlim_t x;
-        const char *is_soft;
 
         assert(bus);
         assert(reply);
         assert(userdata);
 
         is_soft = endswith(property, "Soft");
+
         rl = *(struct rlimit**) userdata;
         if (rl)
                 x = is_soft ? rl->rlim_cur : rl->rlim_max;
         else {
                 struct rlimit buf = {};
+                const char *s, *p;
                 int z;
-                const char *s;
 
+                /* Chop off "Soft" suffix */
                 s = is_soft ? strndupa(property, is_soft - property) : property;
 
-                z = rlimit_from_string(strstr(s, "Limit"));
+                /* Skip over any prefix, such as "Default" */
+                assert_se(p = strstr(s, "Limit"));
+
+                z = rlimit_from_string(p + 5);
                 assert(z >= 0);
 
-                getrlimit(z, &buf);
+                (void) getrlimit(z, &buf);
                 x = is_soft ? buf.rlim_cur : buf.rlim_max;
         }
 
-        /* rlim_t might have different sizes, let's map
-         * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
-         * all archs */
+        /* rlim_t might have different sizes, let's map RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on all
+         * archs */
         u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
 
         return sd_bus_message_append(reply, "t", u);
index 09c35b4f8b27c9a80cded0a12b9ad07c78bd4bd6..38de758cb6ac469dade2cec25562d782abf8965c 100644 (file)
@@ -42,6 +42,7 @@ int main(int argc, char *argv[]) {
                 .rlim_cur = 10,
                 .rlim_max = 5,
         };
+        int i;
 
         log_parse_environment();
         log_open();
@@ -53,10 +54,41 @@ int main(int argc, char *argv[]) {
         new.rlim_max = old.rlim_max;
         assert_se(setrlimit(RLIMIT_NOFILE, &new) >= 0);
 
-        assert_se(rlimit_from_string("LimitNOFILE") == RLIMIT_NOFILE);
+        assert_se(rlimit_from_string("NOFILE") == RLIMIT_NOFILE);
+        assert_se(rlimit_from_string("LimitNOFILE") == -1);
+        assert_se(rlimit_from_string("RLIMIT_NOFILE") == -1);
+        assert_se(rlimit_from_string("xxxNOFILE") == -1);
         assert_se(rlimit_from_string("DefaultLimitNOFILE") == -1);
 
-        assert_se(streq_ptr(rlimit_to_string(RLIMIT_NOFILE), "LimitNOFILE"));
+        assert_se(rlimit_from_string_harder("NOFILE") == RLIMIT_NOFILE);
+        assert_se(rlimit_from_string_harder("LimitNOFILE") == RLIMIT_NOFILE);
+        assert_se(rlimit_from_string_harder("RLIMIT_NOFILE") == RLIMIT_NOFILE);
+        assert_se(rlimit_from_string_harder("xxxNOFILE") == -1);
+        assert_se(rlimit_from_string_harder("DefaultLimitNOFILE") == -1);
+
+        for (i = 0; i < _RLIMIT_MAX; i++) {
+                _cleanup_free_ char *prefixed = NULL;
+                const char *p;
+
+                assert_se(p = rlimit_to_string(i));
+                log_info("%i = %s", i, p);
+
+                assert_se(rlimit_from_string(p) == i);
+                assert_se(rlimit_from_string_harder(p) == i);
+
+                assert_se(prefixed = strjoin("Limit", p));
+
+                assert_se(rlimit_from_string(prefixed) < 0);
+                assert_se(rlimit_from_string_harder(prefixed) == i);
+
+                prefixed = mfree(prefixed);
+                assert_se(prefixed = strjoin("RLIMIT_", p));
+
+                assert_se(rlimit_from_string(prefixed) < 0);
+                assert_se(rlimit_from_string_harder(prefixed) == i);
+        }
+
+        assert_se(streq_ptr(rlimit_to_string(RLIMIT_NOFILE), "NOFILE"));
         assert_se(rlimit_to_string(-1) == NULL);
 
         assert_se(getrlimit(RLIMIT_NOFILE, &old) == 0);