prlimit: new command
This program uses the prlimit() system call to get and/or set resource limits for a given process. [kzak@redhat,com: - improve <soft:hard> parsing, - use short cmdline options compatible with ulimits - add --verbose mode - fix gcc warnings] Signed-off-by: Davidlohr Bueso <dave@gnu.org> Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
6a2f2f58a4
commit
6bac2825af
|
@ -26,6 +26,7 @@ pivot_root
|
|||
ppc32.8
|
||||
ppc64.8
|
||||
ppc.8
|
||||
prlimit
|
||||
readprofile
|
||||
renice
|
||||
rtcwake
|
||||
|
|
|
@ -2,11 +2,11 @@ include $(top_srcdir)/config/include-Makefile.am
|
|||
|
||||
bin_PROGRAMS =
|
||||
sbin_PROGRAMS =
|
||||
usrbin_exec_PROGRAMS = flock ipcrm ipcs ipcmk renice setsid
|
||||
usrbin_exec_PROGRAMS = flock ipcrm ipcs ipcmk renice setsid prlimit
|
||||
usrsbin_exec_PROGRAMS = readprofile
|
||||
|
||||
dist_man_MANS = flock.1 ipcrm.1 ipcs.1 ipcmk.1 renice.1 setsid.1 \
|
||||
readprofile.8
|
||||
readprofile.8 prlimit.1
|
||||
|
||||
if LINUX
|
||||
bin_PROGRAMS += dmesg
|
||||
|
@ -41,6 +41,9 @@ dmesg_SOURCES = dmesg.c $(top_srcdir)/lib/strutils.c
|
|||
ipcmk_SOURCES = ipcmk.c $(top_srcdir)/lib/strutils.c
|
||||
ipcrm_SOURCES = ipcrm.c $(top_srcdir)/lib/strutils.c
|
||||
flock_SOURCES = flock.c $(top_srcdir)/lib/strutils.c
|
||||
prlimit_SOURCES = prlimit.c $(top_srcdir)/lib/strutils.c \
|
||||
$(top_srcdir)/lib/mbsalign.c \
|
||||
$(top_srcdir)/lib/tt.c
|
||||
|
||||
if BUILD_MOUNTPOINT
|
||||
bin_PROGRAMS += mountpoint
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
.\" prlimit.1 --
|
||||
.\" Copyright 2011 Davidlohr Bueso <dave@gnu.org>
|
||||
.\" May be distributed under the GNU General Public License
|
||||
|
||||
.TH PRLIMIT 1 "October 2011" "util-linux" "User Commands"
|
||||
.SH NAME
|
||||
prlimit \-
|
||||
get and set a process resource limits.
|
||||
.SH SYNOPSIS
|
||||
.B prlimit
|
||||
.RB [options]
|
||||
.RB [ \-\-{resource_name}[=limits] ]
|
||||
|
||||
.SH DESCRIPTION
|
||||
Given a process id and one or more resources, \fBprlimit\fP tries to retrieve
|
||||
and/or modify the limits.
|
||||
|
||||
The \fIlimits\fP format is composed by a soft and a hard (ceiling) value, separated
|
||||
by a semicolon (:), in order to modify the existing value(s). If no limits are
|
||||
used, \fBprlimit\fP will only display the current values. If one of the values
|
||||
is not used, then the existing one will be used. To specify the unlimited or
|
||||
infinity limit (RLIM_INFINITY), the -1 or 'unlimited' string can be passed.
|
||||
|
||||
Because of the nature of limits, the soft value must be lower or equal to the
|
||||
high limit. To see all the available resource limits, refer to the RESOURCE
|
||||
OPTIONS section.
|
||||
|
||||
.IP "\fB<soft>:<hard>\fP Specify both limits"
|
||||
.IP "\fB<soft>:\fP Specify only the soft limit"
|
||||
.IP "\fB:<hard>\fP Specify only the hard limit"
|
||||
.IP "\fB<value>\fP Specify both soft and hard limits to the same value"
|
||||
|
||||
.SH GENERAL OPTIONS
|
||||
.IP "\fB\-p, \-\-pid\fP"
|
||||
Specify the process id, if none is given, it will use the running process.
|
||||
.IP "\fB\-o, \-\-output \fIlist\fP"
|
||||
Define the output columns to use. If no output arrangement is specified, then a default set is used.
|
||||
Use \fB\-\-help\fP to get list of all supported columns.
|
||||
.IP "\fB\-V, \-\-version\fP"
|
||||
Output version information and exit.
|
||||
.IP "\fB\-v, \-\-verbose\fP"
|
||||
Vebose mode.
|
||||
.IP "\fB\-h, \-\-help\fP"
|
||||
Print a help text and exit.
|
||||
|
||||
.SH RESOURCE OPTIONS
|
||||
.IP "\fB\-c, \-\-core\fP[=limits]"
|
||||
Maximum size of a core file.
|
||||
.IP "\fB\-d, \-\-data\fP[=limits]"
|
||||
Maximum data size.
|
||||
.IP "\fB\-e, \-\-nice\fP[=limits]"
|
||||
Maximum nice priority allowed to raise.
|
||||
.IP "\fB\-f, \-\-fsize\fP[=limits]"
|
||||
Maximum file size.
|
||||
.IP "\fB\-i, \-\-sigpending\fP[=limits]"
|
||||
Maximum amount of pending signals.
|
||||
.IP "\fB\-l, \-\-memlock\fP[=limits]"
|
||||
Maximum locked-in-memory address space.
|
||||
.IP "\fB\-m, \-\-rss\fP[=limits]"
|
||||
Maximum Resident Set Size (RSS).
|
||||
.IP "\fB\-n, \-\-nofile\fP[=limits]"
|
||||
Maximum amount of open files.
|
||||
.IP "\fB\-q, \-\-msgqueue\fP[=limits]"
|
||||
Maximum amount of bytes in POSIX message queues.
|
||||
.IP "\fB\-r, \-\-rtprio\fP[=limits]"
|
||||
Maximum real-time priority.
|
||||
.IP "\fB\-s, \-\-stack\fP[=limits]"
|
||||
Maximum size of the stack.
|
||||
.IP "\fB\-t, \-\-cpu\fP[=limits]"
|
||||
CPU time, in seconds.
|
||||
.IP "\fB\-u, \-\-nproc\fP[=limits]"
|
||||
Maximum amount of processes.
|
||||
.IP "\fB\-v, \-\-as\fP[=limits]"
|
||||
Address space limit.
|
||||
.IP "\fB\-x, \-\-locks\fP[=limits]"
|
||||
Maximum amount of file locks held.
|
||||
.IP "\fB\-y, \-\-rttime\fP[=limits]"
|
||||
Timeout for real-time tasks.
|
||||
|
||||
.RE
|
||||
.SH EXAMPLES
|
||||
.IP "\fBprlimit \-\-pid 13134\fP"
|
||||
Display limit values for all current resources.
|
||||
.IP "\fBprlimit \-\-pid 13134 \--rss --nofile=1024:4095\fP"
|
||||
Display the limits of the RSS and set the soft and hard limits for the amount
|
||||
of open files to 1024 and 4095, respectively.
|
||||
.IP "\fBprlimit \-\-pid 13134 --nproc=512:\fP"
|
||||
Modify only the soft limit for the amount of processes.
|
||||
.IP "\fBprlimit \-\-pid $$ --nproc=unlimited\fP"
|
||||
Set the amount of processes for both soft and ceiling values to unlimited.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR prlimit (2),
|
||||
.BR ulimit (1)
|
||||
|
||||
.SH NOTES
|
||||
.nf
|
||||
The prlimit system call is supported since Linux 2.6.36, previous kernels will
|
||||
break this program.
|
||||
.fi
|
||||
|
||||
.SH AUTHORS
|
||||
.nf
|
||||
Davidlohr Bueso <dave@gnu.org> - In memory of Dennis M. Ritchie.
|
||||
.fi
|
||||
.SH AVAILABILITY
|
||||
The prlimit command is part of the util-linux package and is available from
|
||||
ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
|
|
@ -0,0 +1,571 @@
|
|||
/*
|
||||
* prlimit - get/set process resource limits.
|
||||
*
|
||||
* Copyright (C) 2011 Davidlohr Bueso <dave@gnu.org>
|
||||
*
|
||||
* 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 2 of the License, 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "c.h"
|
||||
#include "nls.h"
|
||||
#include "tt.h"
|
||||
#include "xalloc.h"
|
||||
#include "strutils.h"
|
||||
|
||||
enum {
|
||||
AS,
|
||||
CORE,
|
||||
CPU,
|
||||
DATA,
|
||||
FSIZE,
|
||||
LOCKS,
|
||||
MEMLOCK,
|
||||
MSGQUEUE,
|
||||
NICE,
|
||||
NOFILE,
|
||||
NPROC,
|
||||
RSS,
|
||||
RTPRIO,
|
||||
RTTIME,
|
||||
SIGPENDING,
|
||||
STACK
|
||||
};
|
||||
|
||||
struct prlimit_desc {
|
||||
const char *name;
|
||||
const char *help;
|
||||
int resource;
|
||||
};
|
||||
|
||||
static struct prlimit_desc prlimit_desc[] =
|
||||
{
|
||||
[AS] = { "AS", N_("address space limit"), RLIMIT_AS },
|
||||
[CORE] = { "CORE", N_("max core file size"), RLIMIT_CORE },
|
||||
[CPU] = { "CPU", N_("CPU time in secs"), RLIMIT_CPU },
|
||||
[DATA] = { "DATA", N_("max data size"), RLIMIT_DATA },
|
||||
[FSIZE] = { "FSIZE", N_("max file size"), RLIMIT_FSIZE },
|
||||
[LOCKS] = { "LOCKS", N_("max amount of file locks held"), RLIMIT_LOCKS },
|
||||
[MEMLOCK] = { "MEMLOCK", N_("max locked-in-memory address space"), RLIMIT_MEMLOCK },
|
||||
[MSGQUEUE] = { "MSGQUEUE", N_("max bytes in POSIX mqueues"), RLIMIT_MSGQUEUE },
|
||||
[NICE] = { "NICE", N_("max nice prio allowed to raise"), RLIMIT_NICE },
|
||||
[NOFILE] = { "NOFILE", N_("max amount of open files"), RLIMIT_NOFILE },
|
||||
[NPROC] = { "NPROC", N_("max number of processes"), RLIMIT_NPROC },
|
||||
[RSS] = { "RSS", N_("max resident set size"), RLIMIT_RSS },
|
||||
[RTPRIO] = { "RTPRIO", N_("max real-time priority"), RLIMIT_RTPRIO },
|
||||
[RTTIME] = { "RTTIME", N_("timeout for real-time tasks"), RLIMIT_RTTIME },
|
||||
[SIGPENDING] = { "SIGPENDING", N_("max amount of pending signals"), RLIMIT_SIGPENDING },
|
||||
[STACK] = { "STACK", N_("max stack size"), RLIMIT_STACK }
|
||||
};
|
||||
|
||||
struct prlimit {
|
||||
struct rlimit rlim;
|
||||
struct prlimit_desc *desc;
|
||||
int modify;
|
||||
};
|
||||
|
||||
#define PRLIMIT_EMPTY_LIMIT {{ 0, 0, }, NULL, 0 }
|
||||
|
||||
enum {
|
||||
COL_HELP,
|
||||
COL_RES,
|
||||
COL_SOFT,
|
||||
COL_HARD,
|
||||
};
|
||||
|
||||
/* column names */
|
||||
struct colinfo {
|
||||
const char *name; /* header */
|
||||
double whint; /* width hint (N < 1 is in percent of termwidth) */
|
||||
int flags; /* TT_FL_* */
|
||||
const char *help;
|
||||
};
|
||||
|
||||
/* columns descriptions */
|
||||
struct colinfo infos[] = {
|
||||
[COL_RES] = { "RESOURCE", 0.25, TT_FL_TRUNC, N_("resource name") },
|
||||
[COL_HELP] = { "DESCRIPTION", 0.1, TT_FL_TRUNC, N_("resource description")},
|
||||
[COL_SOFT] = { "SOFT", 0.1, TT_FL_RIGHT, N_("soft limit")},
|
||||
[COL_HARD] = { "HARD", 1, TT_FL_RIGHT, N_("hard limit (ceiling)")},
|
||||
};
|
||||
|
||||
#define NCOLS ARRAY_SIZE(infos)
|
||||
#define MAX_RESOURCES ARRAY_SIZE(prlimit_desc)
|
||||
|
||||
#define INFINITY_STR "unlimited"
|
||||
#define INFINITY_STRLEN (sizeof(INFINITY_STR) - 1)
|
||||
|
||||
#define PRLIMIT_SOFT (1 << 1)
|
||||
#define PRLIMIT_HARD (1 << 2)
|
||||
|
||||
/* array with IDs of enabled columns */
|
||||
static int columns[NCOLS], ncolumns;
|
||||
static pid_t pid; /* calling process (default) */
|
||||
static int verbose;
|
||||
|
||||
static void __attribute__ ((__noreturn__)) usage(FILE * out)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
fputs(USAGE_HEADER, out);
|
||||
|
||||
fprintf(out,
|
||||
_(" %s [options]\n"), program_invocation_short_name);
|
||||
|
||||
fputs(_("\nGeneral Options:\n"), out);
|
||||
fputs(_(" -p, --pid <pid> process id\n"
|
||||
" -o, --output <type> define which output columns to use\n"
|
||||
" --verbose verbose output\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
" -V, --version output version information and exit\n"), out);
|
||||
|
||||
fputs(_("\nResources Options:\n"), out);
|
||||
fputs(_(" -c, --core maximum size of core files created\n"
|
||||
" -d, --data maximum size of a process's data segment\n"
|
||||
" -e, --nice maximum nice priority allowed to raise\n"
|
||||
" -f, --fsize maximum size of files written by the process\n"
|
||||
" -i, --sigpending maximum amount of pending signals\n"
|
||||
" -l, --memlock maximum size a process may lock into memory\n"
|
||||
" -m, --rss maximum resident set size\n"
|
||||
" -n, --nofile maximum amount of open files\n"
|
||||
" -q, --msgqueue maximum bytes in POSIX message queues\n"
|
||||
" -r, --rtprio maximum real-time scheduling priority\n"
|
||||
" -s, --stack maximum stack size\n"
|
||||
" -t, --cpu maximum amount of CPU time in seconds\n"
|
||||
" -u, --nproc maximum number of user processes\n"
|
||||
" -v, --as size of virtual memory\n"
|
||||
" -x, --locks maximum number of file locks\n"
|
||||
" -y, --rttime CPU time in microseconds a process scheduled\n"
|
||||
" under real-time scheduling\n"), out);
|
||||
|
||||
fputs(_("\nAvailable columns (for --output):\n"), out);
|
||||
|
||||
for (i = 0; i < NCOLS; i++)
|
||||
fprintf(out, " %11s %s\n", infos[i].name, _(infos[i].help));
|
||||
|
||||
fprintf(out, USAGE_MAN_TAIL("prlimit(1)"));
|
||||
|
||||
exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static inline int get_column_id(int num)
|
||||
{
|
||||
assert(ARRAY_SIZE(columns) == NCOLS);
|
||||
assert(num < ncolumns);
|
||||
assert(columns[num] < (int) NCOLS);
|
||||
|
||||
return columns[num];
|
||||
}
|
||||
|
||||
static inline struct colinfo *get_column_info(unsigned num)
|
||||
{
|
||||
return &infos[ get_column_id(num) ];
|
||||
}
|
||||
|
||||
static void add_tt_line(struct tt *tt, struct prlimit *l)
|
||||
{
|
||||
int i;
|
||||
struct tt_line *line;
|
||||
|
||||
assert(tt);
|
||||
assert(l);
|
||||
|
||||
line = tt_add_line(tt, NULL);
|
||||
if (!line) {
|
||||
warn(_("failed to add line to output"));
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < ncolumns; i++) {
|
||||
char *str = NULL;
|
||||
int rc = 0;
|
||||
|
||||
switch (get_column_id(i)) {
|
||||
case COL_RES:
|
||||
rc = asprintf(&str, "%s", l->desc->name);
|
||||
break;
|
||||
case COL_HELP:
|
||||
rc = asprintf(&str, "%s", l->desc->help);
|
||||
break;
|
||||
case COL_SOFT:
|
||||
rc = l->rlim.rlim_cur == RLIM_INFINITY ?
|
||||
asprintf(&str, "%s", "unlimited") :
|
||||
asprintf(&str, "%llu", (unsigned long long) l->rlim.rlim_cur);
|
||||
break;
|
||||
case COL_HARD:
|
||||
rc = l->rlim.rlim_max == RLIM_INFINITY ?
|
||||
asprintf(&str, "%s", "unlimited") :
|
||||
asprintf(&str, "%llu", (unsigned long long) l->rlim.rlim_max);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc || str)
|
||||
tt_line_set_data(line, i, str);
|
||||
}
|
||||
}
|
||||
|
||||
static int column_name_to_id(const char *name, size_t namesz)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
assert(name);
|
||||
|
||||
for (i = 0; i < NCOLS; i++) {
|
||||
const char *cn = infos[i].name;
|
||||
|
||||
if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
|
||||
return i;
|
||||
}
|
||||
warnx(_("unknown column: %s"), name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int show_limits(struct prlimit lims[], int tt_flags, size_t n)
|
||||
{
|
||||
int i;
|
||||
struct tt *tt;
|
||||
|
||||
tt = tt_new_table(tt_flags);
|
||||
if (!tt) {
|
||||
warn(_("failed to initialize output table"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < ncolumns; i++) {
|
||||
struct colinfo *col = get_column_info(i);
|
||||
|
||||
if (!tt_define_column(tt, col->name, col->whint, col->flags)) {
|
||||
warnx(_("failed to initialize output column"));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; (size_t) i < n; i++)
|
||||
if (!lims[i].modify) /* only display old limits */
|
||||
add_tt_line(tt, &lims[i]);
|
||||
|
||||
tt_print_table(tt);
|
||||
done:
|
||||
tt_free_table(tt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void do_prlimit(struct prlimit lims[], size_t n)
|
||||
{
|
||||
size_t i, nshows = 0;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
struct rlimit *new = NULL;
|
||||
|
||||
if (lims[i].modify)
|
||||
new = &lims[i].rlim;
|
||||
else
|
||||
nshows++;
|
||||
|
||||
if (verbose && new) {
|
||||
printf(_("New %s limit: "), lims[i].desc->name);
|
||||
if (new->rlim_cur == RLIM_INFINITY)
|
||||
printf("<%s", _("unlimited"));
|
||||
else
|
||||
printf("<%ju", new->rlim_cur);
|
||||
|
||||
if (new->rlim_max == RLIM_INFINITY)
|
||||
printf(":%s>\n", _("unlimited"));
|
||||
else
|
||||
printf(":%ju>\n", new->rlim_max);
|
||||
}
|
||||
|
||||
if (prlimit(pid, lims[i].desc->resource, new, &lims[i].rlim) == -1)
|
||||
err(EXIT_FAILURE, _("failed to get resource limits for PID %d"), pid);
|
||||
}
|
||||
|
||||
if (nshows)
|
||||
show_limits(lims, 0, n);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int get_range(char *str, rlim_t *soft, rlim_t *hard, int *found)
|
||||
{
|
||||
char *end = NULL;
|
||||
|
||||
if (!str)
|
||||
return 0;
|
||||
|
||||
*found = errno = 0;
|
||||
*soft = *hard = RLIM_INFINITY;
|
||||
|
||||
if (!strcmp(str, INFINITY_STR)) { /* <unlimited> */
|
||||
*found |= PRLIMIT_SOFT | PRLIMIT_HARD;
|
||||
return 0;
|
||||
|
||||
} else if (*str == ':') { /* <:hard> */
|
||||
str++;
|
||||
|
||||
if (strcmp(str, INFINITY_STR) != 0) {
|
||||
*hard = strtoull(str, &end, 10);
|
||||
|
||||
if (errno || !end || *end || end == str)
|
||||
return -1;
|
||||
}
|
||||
*found |= PRLIMIT_HARD;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
if (strncmp(str, INFINITY_STR, INFINITY_STRLEN) == 0) {
|
||||
/* <unlimited> or <unlimited:> */
|
||||
end = str + INFINITY_STRLEN;
|
||||
} else {
|
||||
/* <value> or <soft:> */
|
||||
*hard = *soft = strtoull(str, &end, 10);
|
||||
if (errno || !end || end == str)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*end == ':' && !*(end + 1)) /* <soft:> */
|
||||
*found |= PRLIMIT_SOFT;
|
||||
|
||||
else if (*end == ':') { /* <soft:hard> */
|
||||
str = end + 1;
|
||||
|
||||
if (!strcmp(str, INFINITY_STR))
|
||||
*hard = RLIM_INFINITY;
|
||||
else {
|
||||
end = NULL;
|
||||
errno = 0;
|
||||
*hard = strtoull(str, &end, 10);
|
||||
|
||||
if (errno || !end || *end || end == str)
|
||||
return -1;
|
||||
}
|
||||
*found |= PRLIMIT_SOFT | PRLIMIT_HARD;
|
||||
|
||||
} else /* <value> */
|
||||
*found |= PRLIMIT_SOFT | PRLIMIT_HARD;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int parse_prlim(struct rlimit *lim, char *ops, size_t id)
|
||||
{
|
||||
rlim_t soft, hard;
|
||||
int found = 0;
|
||||
|
||||
if (get_range(ops, &soft, &hard, &found))
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a resource limit to the limits array
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
size_t n = 0;
|
||||
struct prlimit lims[MAX_RESOURCES] = { PRLIMIT_EMPTY_LIMIT };
|
||||
|
||||
enum {
|
||||
VERBOSE_OPTION = CHAR_MAX + 1
|
||||
};
|
||||
|
||||
static const struct option longopts[] = {
|
||||
{ "pid", required_argument, NULL, 'p' },
|
||||
{ "output", required_argument, NULL, 'o' },
|
||||
{ "as", optional_argument, NULL, 'v' },
|
||||
{ "core", optional_argument, NULL, 'c' },
|
||||
{ "cpu", optional_argument, NULL, 't' },
|
||||
{ "data", optional_argument, NULL, 'd' },
|
||||
{ "fsize", optional_argument, NULL, 'f' },
|
||||
{ "locks", optional_argument, NULL, 'x' },
|
||||
{ "memlock", optional_argument, NULL, 'l' },
|
||||
{ "msgqueue", optional_argument, NULL, 'q' },
|
||||
{ "nice", optional_argument, NULL, 'e' },
|
||||
{ "nofile", optional_argument, NULL, 'n' },
|
||||
{ "nproc", optional_argument, NULL, 'u' },
|
||||
{ "rss", optional_argument, NULL, 'm' },
|
||||
{ "rtprio", optional_argument, NULL, 'r' },
|
||||
{ "rttime", optional_argument, NULL, 'y' },
|
||||
{ "sigpending", optional_argument, NULL, 'i' },
|
||||
{ "stack", optional_argument, NULL, 's' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "verbose", no_argument, NULL, VERBOSE_OPTION },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
/*
|
||||
* Something is very wrong if this doesn't succeed,
|
||||
* assuming STACK is the last resource, of course.
|
||||
*/
|
||||
assert(MAX_RESOURCES == STACK + 1);
|
||||
|
||||
while((opt = getopt_long(argc, argv,
|
||||
"c::d::e::f::i::l::m::n::q::r::s::t::u::v::x::y::p:o:vVh",
|
||||
longopts, NULL)) != -1) {
|
||||
switch(opt) {
|
||||
case 'c':
|
||||
add_prlim(optarg, &lims[n++], CORE);
|
||||
break;
|
||||
case 'd':
|
||||
add_prlim(optarg, &lims[n++], DATA);
|
||||
break;
|
||||
case 'e':
|
||||
add_prlim(optarg, &lims[n++], NICE);
|
||||
break;
|
||||
case 'f':
|
||||
add_prlim(optarg, &lims[n++], FSIZE);
|
||||
break;
|
||||
case 'i':
|
||||
add_prlim(optarg, &lims[n++], SIGPENDING);
|
||||
break;
|
||||
case 'l':
|
||||
add_prlim(optarg, &lims[n++], MEMLOCK);
|
||||
break;
|
||||
case 'm':
|
||||
add_prlim(optarg, &lims[n++], RSS);
|
||||
break;
|
||||
case 'n':
|
||||
add_prlim(optarg, &lims[n++], NOFILE);
|
||||
break;
|
||||
case 'q':
|
||||
add_prlim(optarg, &lims[n++], MSGQUEUE);
|
||||
break;
|
||||
case 'r':
|
||||
add_prlim(optarg, &lims[n++], RTPRIO);
|
||||
break;
|
||||
case 's':
|
||||
add_prlim(optarg, &lims[n++], STACK);
|
||||
break;
|
||||
case 't':
|
||||
add_prlim(optarg, &lims[n++], CPU);
|
||||
break;
|
||||
case 'u':
|
||||
add_prlim(optarg, &lims[n++], NPROC);
|
||||
break;
|
||||
case 'v':
|
||||
add_prlim(optarg, &lims[n++], AS);
|
||||
break;
|
||||
case 'x':
|
||||
add_prlim(optarg, &lims[n++], LOCKS);
|
||||
break;
|
||||
case 'y':
|
||||
add_prlim(optarg, &lims[n++], RTTIME);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
if (pid) /* we only work one pid at a time */
|
||||
errx(EXIT_FAILURE, _("only use one PID at a time"));
|
||||
|
||||
pid = strtol_or_err(optarg, _("cannot parse PID"));
|
||||
break;
|
||||
case 'h':
|
||||
usage(stdout);
|
||||
break;
|
||||
case 'o':
|
||||
ncolumns = string_to_idarray(optarg,
|
||||
columns, ARRAY_SIZE(columns),
|
||||
column_name_to_id);
|
||||
if (ncolumns < 0)
|
||||
return EXIT_FAILURE;
|
||||
break;
|
||||
case 'V':
|
||||
printf(UTIL_LINUX_VERSION);
|
||||
return EXIT_SUCCESS;
|
||||
case VERBOSE_OPTION:
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(stderr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc == 1)
|
||||
usage(stderr);
|
||||
|
||||
if (!ncolumns) {
|
||||
/* default columns */
|
||||
columns[ncolumns++] = COL_RES;
|
||||
columns[ncolumns++] = COL_HELP;
|
||||
columns[ncolumns++] = COL_SOFT;
|
||||
columns[ncolumns++] = COL_HARD;
|
||||
}
|
||||
|
||||
if (!n) {
|
||||
/* default is to print all resources */
|
||||
for (; n < MAX_RESOURCES; n++)
|
||||
add_prlim(NULL, &lims[n], n);
|
||||
}
|
||||
|
||||
do_prlimit(lims, n);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Loading…
Reference in New Issue