[PATCH 07/15] prlimit: fix case when getting missing limit is needed and
PID is given later
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. Example:
$ ps
PID TTY TIME CMD
555 pts/6 00:00:00 bash
...
$ prlimit -p555 -n --noheadings
NOFILE max amount of open files 1024 8192
$ sleep 100000&
[1] 650
$ prlimit -p555 -n:5000
$ prlimit -n4000: -p650
$ prlimit -p650 -n --noheadings
NOFILE max amount of open files 4000 5000
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 new struct prlimit member 'found' set by add_prlim().
Signed-off-by: Bernhard Voelker <mail@xxxxxxxxxxxxxxxxxxx>
---
sys-utils/prlimit.c | 57
++++++++++++++++++++++++++++++--------------------
1 files changed, 34 insertions(+), 23 deletions(-)
diff --git a/sys-utils/prlimit.c b/sys-utils/prlimit.c
index 611f3e8..622a318 100644
--- a/sys-utils/prlimit.c
+++ b/sys-utils/prlimit.c
@@ -85,6 +85,7 @@ static struct prlimit_desc prlimit_desc[] =
struct prlimit {
struct rlimit rlim;
+ int found;
struct prlimit_desc *desc;
int modify;
};
@@ -294,6 +295,26 @@ done:
return 0;
}
+static void get_unknown_hardsoft(struct prlimit *lim)
+{
+ /*
+ * 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 (lim->found != (PRLIMIT_HARD | PRLIMIT_SOFT)) {
+ struct rlimit old;
+
+ if (prlimit(pid, lim->desc->resource, NULL, &old) == -1)
+ errx(EXIT_FAILURE, _("failed to get old %s limit"),
+ lim->desc->resource);
+
+ if (!(lim->found & PRLIMIT_SOFT))
+ lim->rlim.rlim_cur = old.rlim_cur;
+ else if (!(lim->found & PRLIMIT_HARD))
+ lim->rlim.rlim_max = old.rlim_max;
+ }
+}
static void do_prlimit(struct prlimit lims[], size_t n, int tt_flags)
{
@@ -305,6 +326,17 @@ static void do_prlimit(struct prlimit lims[],
size_t n, int tt_flags)
if (lims[i].modify) {
if (!pid)
warnx(_("setting limits of the prlimit process is pointless"));
+
+ get_unknown_hardsoft(&lims[i]);
+
+ /* final soft vs. hard limit check to have a
+ * better diagnostic than "invalid argument".
+ */
+ 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 cannot exceed the ceiling
value"));
+
new = &lims[i].rlim;
} else {
nshows++;
@@ -420,31 +452,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;
}
/*
@@ -456,7 +467,7 @@ static int add_prlim(char *ops, struct prlimit *lim,
size_t id)
if (ops) { /* planning on modifying a limit? */
lim->modify = 1;
- parse_prlim(&lim->rlim, ops, id);
+ lim->found = parse_prlim(&lim->rlim, ops, id);
}
return 0;
--
To unsubscribe from this list: send the line "unsubscribe util-linux" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html