From 6d84fd010e0e2e603c76b7ba1efc97082363b1b0 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Thu, 28 Apr 2016 09:06:43 +0200 Subject: [PATCH] Resource limit manipulation (setrlimit) Add support for changing the initial hard and soft resource limits for finit and any processes it launches. See /etc/finit.conf section in README.md for more information. --- README.md | 18 ++++++++++++ conf.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/README.md b/README.md index 4c93b56f..9a3c7e67 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,24 @@ Syntax: * `network ` Script or program to bring up networking, with optional arguments +* `rlimit RESOURCE ` + Modify the specified resource's hard or soft limit to be the + specifed limit. `RESOURCE` is a lower-case string matching the + constants in `setrlimit(2)` with the `RLIMIT_` prefix + removed. E.g. to select `RLIMIT_CPU`, `RESOURCE` would be + `cpu`. `LIMIT` is an integer whose unit depends on the resource + being modified, see `setrlimit(2)` for more information. The special + limit `infinity` means the there should be no limit on the resource, + i.e. `RLIM_INFINITY` is passed to `setrlimit(2)`. + +```shell + # No process is allowed more than 8MB of address space + rlimit hard as 8388608 + + # Core dumps may be arbitrarily large + rlimit soft core infinity +``` + * `runlevel ` N is the runlevel number 1-9, where 6 is reserved for reboot. Default is 2. diff --git a/conf.c b/conf.c index e8f66476..1e461320 100644 --- a/conf.c +++ b/conf.c @@ -27,6 +27,8 @@ #include #include +#include + #include "finit.h" #include "cond.h" #include "service.h" @@ -150,6 +152,86 @@ void conf_parse_cond(svc_t *svc, char *cond) strlcpy(svc->cond, ptr, sizeof(svc->cond)); } +struct rlimit_name { + char *name; + int val; +}; + +static const struct rlimit_name rlimit_names[] = { + { "as", RLIMIT_AS }, + { "core", RLIMIT_CORE }, + { "cpu", RLIMIT_CPU }, + { "data", RLIMIT_DATA }, + { "fsize", RLIMIT_FSIZE }, + { "locks", RLIMIT_LOCKS }, + { "memlock", RLIMIT_MEMLOCK }, + { "msgqueue", RLIMIT_MSGQUEUE }, + { "nice", RLIMIT_NICE }, + { "nofile", RLIMIT_NOFILE }, + { "nproc", RLIMIT_NPROC }, + { "rss", RLIMIT_RSS }, + { "rtprio", RLIMIT_RTPRIO }, + { "rttime", RLIMIT_RTTIME }, + { "sigpending", RLIMIT_SIGPENDING }, + { "stack", RLIMIT_STACK }, + + { NULL } +}; + +void conf_parse_rlimit(char *line) +{ + struct rlimit rlim; + rlim_t new, *set; + const struct rlimit_name *name; + int resource = -1; + + char *tok = strtok(line, " \t"); + + if (tok && !strcmp(tok, "soft")) + set = &rlim.rlim_cur; + else if (tok && !strcmp(tok, "hard")) + set = &rlim.rlim_max; + else + goto fail; + + tok = strtok(NULL, " \t"); + if (!tok) + goto fail; + + for (name = rlimit_names; name->name; name++) + if (!strcmp(tok, name->name)) + resource = name->val; + + if (resource < 0) + goto fail; + + tok = strtok(NULL, " \t"); + if (!tok) + goto fail; + + if (!strcmp(tok, "infinity")) + new = RLIM_INFINITY; + else { + const char *err = NULL; + + new = strtonum(tok, 0, 2 << 31, &err); + if (err) + goto fail; + } + + if (getrlimit(resource, &rlim)) + goto fail; + + *set = new; + if (setrlimit(resource, &rlim)) + goto fail; + + return; + +fail: + FLOG_WARN("Failed parsing/setting %s rlimit", name->name ? : "unknown"); +} + static void parse_static(char *line) { char *x; @@ -302,6 +384,11 @@ static void parse_dynamic(char *line, time_t mtime) #endif return; } + + if (MATCH_CMD(line, "rlimit ", x)) { + conf_parse_rlimit(x); + return; + } } static int parse_conf_dynamic(char *file, time_t mtime)