diff options
Diffstat (limited to 'src/limits.c')
-rw-r--r-- | src/limits.c | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/src/limits.c b/src/limits.c new file mode 100644 index 0000000..90d6459 --- /dev/null +++ b/src/limits.c @@ -0,0 +1,299 @@ +/* This file is part of Mailfromd. + Copyright (C) 2008 Sergey Poznyakoff + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <pies.h> + +#define SET_LIMIT_AS 0x0001 +#define SET_LIMIT_CPU 0x0002 +#define SET_LIMIT_DATA 0x0004 +#define SET_LIMIT_FSIZE 0x0008 +#define SET_LIMIT_NPROC 0x0010 +#define SET_LIMIT_CORE 0x0020 +#define SET_LIMIT_MEMLOCK 0x0040 +#define SET_LIMIT_NOFILE 0x0080 +#define SET_LIMIT_RSS 0x0100 +#define SET_LIMIT_STACK 0x0200 +#define SET_LIMIT_LOGINS 0x0400 +#define SET_LIMIT_PRIO 0x0800 + +struct limits_rec { + unsigned set; + rlim_t limit_as; + rlim_t limit_cpu; + rlim_t limit_data; + rlim_t limit_fsize; + rlim_t limit_nproc; + rlim_t limit_core; + rlim_t limit_memlock; + rlim_t limit_nofile; + rlim_t limit_rss; + rlim_t limit_stack; + int limit_logins; + int limit_prio; +}; + +int +do_set_limit (int rlimit, rlim_t limit) +{ + struct rlimit rlim; + + MU_DEBUG2 (pies_debug, MU_DEBUG_TRACE1, + "Setting limit %d to %lu\n", rlimit, (unsigned long) limit); + rlim.rlim_cur = limit; + rlim.rlim_max = limit; + + if (setrlimit(rlimit, &rlim)) + { + mu_diag_output (MU_DIAG_NOTICE, _("error setting limit: %s"), + mu_strerror (errno)); + return 1; + } + return 0; +} + +static int +set_prio (int prio) +{ + MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE2, "Setting priority to %d\n", prio); + if (setpriority (PRIO_PROCESS, 0, prio)) + { + mu_diag_output (MU_DIAG_NOTICE, _("error setting priority: %s"), + mu_strerror (errno)); + return 1; + } + return 0; +} + +/* Counts the number of user logins and check against the limit */ +static int +check_logins (const char *name, int limit) +{ + mu_diag_output (MU_DIAG_NOTICE, _("L limit is not implemented")); + return 0; +} + +int +set_limits (const char *name, struct limits_rec *lrec) +{ + int rc = 0; + + if (!lrec) + return 0; + + MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE2, "Setting limits for %s\n", name); + +#if defined(RLIMIT_AS) + if (lrec->set & SET_LIMIT_AS) + rc |= do_set_limit(RLIMIT_AS, lrec->limit_as); +#endif +#if defined(RLIMIT_CPU) + if (lrec->set & SET_LIMIT_CPU) + rc |= do_set_limit(RLIMIT_CPU, lrec->limit_cpu); +#endif +#if defined(RLIMIT_DATA) + if (lrec->set & SET_LIMIT_DATA) + rc |= do_set_limit(RLIMIT_DATA, lrec->limit_data); +#endif +#if defined(RLIMIT_FSIZE) + if (lrec->set & SET_LIMIT_FSIZE) + rc |= do_set_limit(RLIMIT_FSIZE, lrec->limit_fsize); +#endif +#if defined(RLIMIT_NPROC) + if (lrec->set & SET_LIMIT_NPROC) + rc |= do_set_limit(RLIMIT_NPROC, lrec->limit_nproc); +#endif +#if defined(RLIMIT_CORE) + if (lrec->set & SET_LIMIT_CORE) + rc |= do_set_limit(RLIMIT_CORE, lrec->limit_core); +#endif +#if defined(RLIMIT_MEMLOCK) + if (lrec->set & SET_LIMIT_MEMLOCK) + rc |= do_set_limit(RLIMIT_MEMLOCK, lrec->limit_memlock); +#endif +#if defined(RLIMIT_NOFILE) + if (lrec->set & SET_LIMIT_NOFILE) + rc |= do_set_limit(RLIMIT_NOFILE, lrec->limit_nofile); +#endif +#if defined(RLIMIT_RSS) + if (lrec->set & SET_LIMIT_RSS) + rc |= do_set_limit(RLIMIT_RSS, lrec->limit_rss); +#endif +#if defined(RLIMIT_STACK) + if (lrec->set & SET_LIMIT_STACK) + rc |= do_set_limit(RLIMIT_STACK, lrec->limit_stack); +#endif + if (lrec->set & SET_LIMIT_LOGINS) + rc |= check_logins(name, lrec->limit_logins); + if (lrec->set & SET_LIMIT_PRIO) + rc |= set_prio(lrec->limit_logins); + return rc; +} + +int +getlimit (char **ptr, rlim_t *rlim, int mul) +{ + if (**ptr == '-') + { + *rlim = RLIM_INFINITY; + ++*ptr; + } + else + { + unsigned long val; + + val = strtoul (*ptr, ptr, 10); + if (val == 0) + return 1; + *rlim = val * mul; + } + return 0; +} + +/* Parse limits string and fill appropriate fields in lrec. + + The string consists of _commands_, optionally separated by any amount + of whitespace. A command has the following form: + + [AaCcDdFfMmNnRrSsTtUuLlPp](-|[0-9]+) + + i.e. a letter followed by number or a dash. The latters stands for + 'unlimited'. Commands are interpreted as follows: + + Command ulimit setrlimit() The limit it sets + option arg + ------------------------------------------------------------- + [Aa] a RLIMIT_AS max address space (KB) + [Cc] c RLIMIT_CORE max core file size (KB) + [Dd] d RLIMIT_DATA max data size (KB) + [Ff] f RLIMIT_FSIZE Maximum filesize (KB) + [Mm] m RLIMIT_MEMLOCK max locked-in-memory address + space (KB) + [Nn] n RLIMIT_NOFILE max number of open files + [Rr] r RLIMIT_RSS max resident set size (KB) + [Ss] s RLIMIT_STACK max stack size (KB) + [Tt] t RLIMIT_CPU max CPU time (MIN) + [Uu] u RLIMIT_NPROC max number of processes + [Ll] l (none) max number of logins (N/A) + [Pp] p (none) process priority -20..20 + (negative = high priority) + */ +int +parse_limits (limits_record_t *plrec, char *str, char **endp) +{ + int c; + struct limits_rec *lrec = xmalloc (sizeof (*lrec)); + *plrec = lrec; + lrec->set = 0; + while ((c = *str++)) + { + if (c == ' ' || c == '\t') + continue; + switch (c) + { + case 'a': + case 'A': + /* RLIMIT_AS - max address space (KB) */ + if (!getlimit (&str, &lrec->limit_as, 1024)) + lrec->set |= SET_LIMIT_AS; + break; + + case 't': + case 'T': + /* RLIMIT_CPU - max CPU time (MIN) */ + if (!getlimit (&str, &lrec->limit_cpu, 60)) + lrec->set |= SET_LIMIT_CPU; + break; + + case 'd': + case 'D': + /* RLIMIT_DATA - max data size (KB) */ + if (!getlimit (&str, &lrec->limit_data, 1024)) + lrec->set |= SET_LIMIT_DATA; + break; + + case 'f': + case 'F': + /* RLIMIT_FSIZE - Maximum filesize (KB) */ + if (!getlimit (&str, &lrec->limit_fsize, 1024)) + lrec->set |= SET_LIMIT_FSIZE; + break; + + case 'u': + case 'U': + /* RLIMIT_NPROC - max number of processes */ + if (!getlimit (&str, &lrec->limit_nproc, 1)) + lrec->set |= SET_LIMIT_NPROC; + break; + + case 'c': + case 'C': + /* RLIMIT_CORE - max core file size (KB) */ + if (!getlimit (&str, &lrec->limit_core, 1024)) + lrec->set |= SET_LIMIT_CORE; + break; + + case 'm': + case 'M': + /* RLIMIT_MEMLOCK - max locked-in-memory + * address space (KB) + */ + if (!getlimit (&str, &lrec->limit_memlock, 1024)) + lrec->set |= SET_LIMIT_MEMLOCK; + break; + + case 'n': + case 'N': + /* RLIMIT_NOFILE - max number of open files */ + if (!getlimit (&str, &lrec->limit_nofile, 1)) + lrec->set |= SET_LIMIT_NOFILE; + break; + + case 'r': + case 'R': + /* RLIMIT_RSS - max resident set size (KB) */ + if (!getlimit (&str, &lrec->limit_rss, 1024)) + lrec->set |= SET_LIMIT_RSS; + break; + + case 's': + case 'S': + /* RLIMIT_STACK - max stack size (KB) */ + if (!getlimit (&str, &lrec->limit_stack, 1024)) + lrec->set |= SET_LIMIT_STACK; + break; + + case 'l': + case 'L': + lrec->limit_logins = strtol (str, &str, 10); + if (lrec->limit_logins >= 0) + lrec->set |= SET_LIMIT_LOGINS; + break; + + case 'p': + case 'P': + lrec->limit_prio = strtol (str, &str, 10); + if (lrec->limit_prio > 0) + lrec->set |= SET_LIMIT_PRIO; + break; + + default: + *endp = str-1; + return 1; + } + } + return 0; +} + |