From 044bc8de2d22a06f7253888460e7a32d4b367c8e Mon Sep 17 00:00:00 2001 From: Bernhard Voelker Date: Wed, 16 Nov 2011 11:55:43 +0100 Subject: prlimit: fix case when PID is given later # prlimit --nofile=:4000 --pid $$ When the PID is given later than a partially given limit, then prlimit used the current PID for getting the missing part (hard, soft) of the limit. Factored out the retrieval of the unknown limit from parse_prlim() to new get_unknown_hardsoft() which is to be called by do_prlimit() based on the struct prlimit member 'modify' set by add_prlim(). [kzak@redhat.com: - use prlimit->mofify as mask - add soft vs. hard limit check from another Bernhard's patch] Signed-off-by: Bernhard Voelker Signed-off-by: Karel Zak --- sys-utils/prlimit.c | 62 ++++++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 29 deletions(-) (limited to 'sys-utils/prlimit.c') diff --git a/sys-utils/prlimit.c b/sys-utils/prlimit.c index 02e520a3b..c60ba7b3d 100644 --- a/sys-utils/prlimit.c +++ b/sys-utils/prlimit.c @@ -86,7 +86,7 @@ static struct prlimit_desc prlimit_desc[] = struct prlimit { struct rlimit rlim; struct prlimit_desc *desc; - int modify; + int modify; /* PRLIMIT_{SOFT,HARD} mask */ }; #define PRLIMIT_EMPTY_LIMIT {{ 0, 0, }, NULL, 0 } @@ -294,6 +294,25 @@ done: return 0; } +/* + * If one of the limits is unknown (default value for not being passed), we + * need to get the current limit and use it. I see no other way other than + * using prlimit(2). + */ +static void get_unknown_hardsoft(struct prlimit *lim) +{ + struct rlimit old; + + if (prlimit(pid, lim->desc->resource, NULL, &old) == -1) + err(EXIT_FAILURE, _("failed to get old %s limit"), + lim->desc->name); + + if (!(lim->modify & PRLIMIT_SOFT)) + lim->rlim.rlim_cur = old.rlim_cur; + else if (!(lim->modify & PRLIMIT_HARD)) + lim->rlim.rlim_max = old.rlim_max; +} + static void do_prlimit(struct prlimit lims[], size_t n, int tt_flags) { size_t i, nshows = 0; @@ -301,9 +320,17 @@ static void do_prlimit(struct prlimit lims[], size_t n, int tt_flags) for (i = 0; i < n; i++) { struct rlimit *new = NULL; - if (lims[i].modify) + if (lims[i].modify) { + if (lims[i].modify != (PRLIMIT_HARD | PRLIMIT_SOFT)) + get_unknown_hardsoft(&lims[i]); + + if ((lims[i].rlim.rlim_cur > lims[i].rlim.rlim_max) && + (lims[i].rlim.rlim_cur != RLIM_INFINITY || + lims[i].rlim.rlim_max != RLIM_INFINITY)) + errx(EXIT_FAILURE, _("the soft limit %s cannot exceed the hard limit"), + lims[i].desc->name); new = &lims[i].rlim; - else + } else nshows++; if (verbose && new) { @@ -404,31 +431,10 @@ static int parse_prlim(struct rlimit *lim, char *ops, size_t id) errx(EXIT_FAILURE, _("failed to parse %s limit"), prlimit_desc[id].name); - /* - * If one of the limits is unknown (default value for not being passed), we need - * to get the current limit and use it. - * I see no other way other than using prlimit(2). - */ - if (found != (PRLIMIT_HARD | PRLIMIT_SOFT)) { - struct rlimit old; - - if (prlimit(pid, prlimit_desc[id].resource, NULL, &old) == -1) - errx(EXIT_FAILURE, _("failed to get old %s limit"), - prlimit_desc[id].name); - - if (!(found & PRLIMIT_SOFT)) - soft = old.rlim_cur; - else if (!(found & PRLIMIT_HARD)) - hard = old.rlim_max; - } - - if (soft > hard && (soft != RLIM_INFINITY || hard != RLIM_INFINITY)) - errx(EXIT_FAILURE, _("the soft limit cannot exceed the ceiling value")); - lim->rlim_cur = soft; lim->rlim_max = hard; - return 0; + return found; } /* @@ -438,10 +444,8 @@ static int add_prlim(char *ops, struct prlimit *lim, size_t id) { lim->desc = &prlimit_desc[id]; - if (ops) { /* planning on modifying a limit? */ - lim->modify = 1; - parse_prlim(&lim->rlim, ops, id); - } + if (ops) + lim->modify = parse_prlim(&lim->rlim, ops, id); return 0; } -- cgit v1.2.3-55-g7522