mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-03-12 08:58:20 +03:00
rlimit-util: rework rlimit_{from|to}_string() to work without "Limit" prefix
let's make the call more generic, so that we can also easily use it for parsing "RLIMIT_xyz" style constants.
This commit is contained in:
parent
0e960f9b5c
commit
6550c24c7f
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
n = strndupa(suffix, soft - suffix);
|
||||
ri = rlimit_from_string(n);
|
||||
if (ri >= 0)
|
||||
name = strjoina("Limit", n);
|
||||
}
|
||||
}
|
||||
|
||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||
_cleanup_free_ char *f = NULL;
|
||||
struct rlimit nl;
|
||||
if (ri >= 0) {
|
||||
uint64_t rl;
|
||||
rlim_t x;
|
||||
|
||||
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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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")) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user