Add rctl(8), the utility to manage rctl rules.
Sponsored by: The FreeBSD Foundation Reviewed by: kib (earlier version)
This commit is contained in:
parent
d5fad1aac8
commit
b43344bc6a
@ -126,6 +126,7 @@ SUBDIR= alias \
|
||||
printenv \
|
||||
printf \
|
||||
procstat \
|
||||
rctl \
|
||||
renice \
|
||||
rev \
|
||||
revoke \
|
||||
|
11
usr.bin/rctl/Makefile
Normal file
11
usr.bin/rctl/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= rctl
|
||||
MAN= rctl.8
|
||||
|
||||
DPADD= ${LIBUTIL}
|
||||
LDADD= -lutil
|
||||
|
||||
WARNS?= 6
|
||||
|
||||
.include <bsd.prog.mk>
|
200
usr.bin/rctl/rctl.8
Normal file
200
usr.bin/rctl/rctl.8
Normal file
@ -0,0 +1,200 @@
|
||||
.\"-
|
||||
.\" Copyright (c) 2009 Edward Tomasz Napierala
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE VOICES IN HIS HEAD BE
|
||||
.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd February 13, 2011
|
||||
.Dt RCTL 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm rctl
|
||||
.Nd display and update resource limits database
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl h
|
||||
.Op Fl n
|
||||
.Op Ar filter
|
||||
.Nm
|
||||
.Fl a
|
||||
.Op Ar rule
|
||||
.Nm
|
||||
.Op Fl h
|
||||
.Op Fl n
|
||||
.Fl l
|
||||
.Op Ar filter
|
||||
.Nm
|
||||
.Fl r
|
||||
.Op Ar filter
|
||||
.Nm
|
||||
.Op Fl h
|
||||
.Fl u
|
||||
.Op Ar filter
|
||||
.Sh DESCRIPTION
|
||||
When called without options, the
|
||||
.Nm
|
||||
command writes currently defined RCTL rules to standard output.
|
||||
.Pp
|
||||
If a
|
||||
.Ar filter
|
||||
argument is specified, only rules matching the filter are displayed.
|
||||
The options are as follows:
|
||||
.Bl -tag -width indent
|
||||
.It Fl a Ar rule
|
||||
Add
|
||||
.Ar rule
|
||||
to the RCTL database.
|
||||
.It Fl l Ar filter
|
||||
Display rules applicable to the process defined by
|
||||
.Ar filter .
|
||||
.It Fl r Ar filter
|
||||
Remove rules matching
|
||||
.Ar filter
|
||||
from the RCTL database.
|
||||
.It Fl u Ar filter
|
||||
Display resource usage for a subject (process, user, login class
|
||||
or jail) matching the
|
||||
.Ar filter .
|
||||
.It Fl h
|
||||
"Human-readable" output.
|
||||
Use unit suffixes: Byte, Kilobyte, Megabyte,
|
||||
Gigabyte, Terabyte and Petabyte.
|
||||
.It Fl n
|
||||
Display user IDs numerically rather than converting them to a user name.
|
||||
.Pp
|
||||
.Sh RULE SYNTAX
|
||||
Syntax for a rule is subject:subject-id:resource:action=amount/per.
|
||||
.Pp
|
||||
Subject defines the kind of entity the rule applies to.
|
||||
It can be either process, user, login class, or jail.
|
||||
.Pp
|
||||
Subject ID identifies the subject. It can be user name,
|
||||
numerical user ID, login class name, jail name, or numerical jail ID.
|
||||
.Pp
|
||||
Resource identifies the resource the rule controls.
|
||||
.Pp
|
||||
Action defines what will happen when a process exceeds the allowed amount.
|
||||
.Pp
|
||||
Amount defines how much of the resource a process can use before
|
||||
the defined action triggers.
|
||||
.Pp
|
||||
The per field defines what entity the amount gets accounted for.
|
||||
For example, rule "loginclass:users:vmem:deny=100M/process" means
|
||||
that each process of any user belonging to login class "users" may allocate
|
||||
up to 100MB of virtual memory.
|
||||
Rule "loginclass:users:vmem:deny=100M/user" would mean that for each
|
||||
user belonging to the login class "users", the sum of virtual memory allocated
|
||||
by all the processes of a that user will not exceed 100MB.
|
||||
Rule "loginclass:users:vmem:deny=100M/loginclass" would mean that the sum of
|
||||
virtual memory allocated by all processes of all users belonging to that login
|
||||
class will not exceed 100MB.
|
||||
.Pp
|
||||
Valid rule has all those fields specified, except for the per, which defaults
|
||||
to the value of subject.
|
||||
.Pp
|
||||
A filter is a rule for which one of more fields other than per is left empty.
|
||||
For example, a filter that matches every rule could be written as ":::=/",
|
||||
or, in short, ":".
|
||||
A filter that matches all the login classes would be "loginclass:".
|
||||
A filter that matches all defined rules for nproc resource would be
|
||||
"::nproc".
|
||||
.Pp
|
||||
.Sh RESOURCES
|
||||
.Bl -column -offset 3n "msgqqueued"
|
||||
.It cpu CPU time, in milliseconds
|
||||
.It fsize maximum file size, in bytes
|
||||
.It data data size, in bytes
|
||||
.It stack stack size, in bytes
|
||||
.It core core dump size, in bytes
|
||||
.It rss resident set size, in bytes
|
||||
.It memlock locked memory, in bytes
|
||||
.It nproc number of processes
|
||||
.It nofile file descriptor table size
|
||||
.It sbsize memory consumed by socket buffers, in bytes
|
||||
.It vmem address space limit, in bytes
|
||||
.It npts number of PTYs
|
||||
.It swap swap usage, in bytes
|
||||
.It nthr number of threads
|
||||
.It msgqqueued number of queued SysV messages
|
||||
.It msgqsize SysV message queue size, in bytes
|
||||
.It nmsgq number of SysV message queues
|
||||
.It nsem number of SysV semaphores
|
||||
.It nsemop number of SysV semaphores modified in a single semop(2) call
|
||||
.It nshm number of SysV shared memory segments
|
||||
.It shmsize SysV shared memory size, in bytes
|
||||
.It wallclock wallclock time, in milliseconds
|
||||
.It pctcpu %cpu time
|
||||
.El
|
||||
.Pp
|
||||
.Sh ACTIONS
|
||||
.Bl -column -offset 3n "msgqqueued"
|
||||
.It deny deny the allocation; not supported for cpu and wallclock
|
||||
.It log log a warning to the console
|
||||
.It devctl send notification to
|
||||
.Xr devd 8
|
||||
.It sig* e.g. sigterm; send a signal to the offending process
|
||||
.El
|
||||
.Pp
|
||||
See
|
||||
.Xr signal 3
|
||||
for a list of supported signals.
|
||||
.Pp
|
||||
Not all actions are supported for all resources.
|
||||
Attempt to add rule with action not supported by a given resouce will result
|
||||
in error.
|
||||
.Pp
|
||||
Note that limiting RSS may kill the machine due to thrashing.
|
||||
.Pp
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std
|
||||
.Sh EXAMPLES
|
||||
.Dl rctl -a user:joe:vmem:deny=1g
|
||||
.Pp
|
||||
Prevent user "joe" from allocating more than 1GB of virtual memory.
|
||||
.Pp
|
||||
.Dl rctl -r :
|
||||
.Pp
|
||||
Remove all RCTL rules.
|
||||
.Pp
|
||||
.Dl rctl -hu jail:5
|
||||
.Pp
|
||||
Display resource usage information for jail with JID 5.
|
||||
.Pp
|
||||
.Dl rctl -l process:512
|
||||
.Pp
|
||||
Display all the rules applicable to process with PID 512.
|
||||
.Sh SEE ALSO
|
||||
.Xr jailstat 8 ,
|
||||
.Xr userstat 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
command appeared in
|
||||
.Fx 9.0.
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
The
|
||||
.Nm
|
||||
command was written by
|
||||
.An Edward Tomasz Napierala Aq trasz@FreeBSD.org .
|
539
usr.bin/rctl/rctl.c
Normal file
539
usr.bin/rctl/rctl.c
Normal file
@ -0,0 +1,539 @@
|
||||
/*-
|
||||
* Copyright (c) 2010 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by Edward Tomasz Napierala under sponsorship
|
||||
* from the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/rctl.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <grp.h>
|
||||
#include <libutil.h>
|
||||
#include <pwd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define RCTL_DEFAULT_BUFSIZE 4096
|
||||
|
||||
static id_t
|
||||
parse_user(const char *s)
|
||||
{
|
||||
id_t id;
|
||||
char *end;
|
||||
struct passwd *pwd;
|
||||
|
||||
pwd = getpwnam(s);
|
||||
if (pwd != NULL)
|
||||
return (pwd->pw_uid);
|
||||
|
||||
if (!isnumber(s[0]))
|
||||
errx(1, "uknown user '%s'", s);
|
||||
|
||||
id = strtod(s, &end);
|
||||
if ((size_t)(end - s) != strlen(s))
|
||||
errx(1, "trailing characters after numerical id");
|
||||
|
||||
return (id);
|
||||
}
|
||||
|
||||
static id_t
|
||||
parse_group(const char *s)
|
||||
{
|
||||
id_t id;
|
||||
char *end;
|
||||
struct group *grp;
|
||||
|
||||
grp = getgrnam(s);
|
||||
if (grp != NULL)
|
||||
return (grp->gr_gid);
|
||||
|
||||
if (!isnumber(s[0]))
|
||||
errx(1, "uknown group '%s'", s);
|
||||
|
||||
id = strtod(s, &end);
|
||||
if ((size_t)(end - s) != strlen(s))
|
||||
errx(1, "trailing characters after numerical id");
|
||||
|
||||
return (id);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine replaces user/group name with numeric id.
|
||||
*/
|
||||
static char *
|
||||
resolve_ids(char *rule)
|
||||
{
|
||||
id_t id;
|
||||
const char *subject, *textid, *rest;
|
||||
char *resolved;
|
||||
|
||||
subject = strsep(&rule, ":");
|
||||
textid = strsep(&rule, ":");
|
||||
if (textid == NULL)
|
||||
errx(1, "error in rule specification -- no subject");
|
||||
if (rule != NULL)
|
||||
rest = rule;
|
||||
else
|
||||
rest = "";
|
||||
|
||||
if (strcasecmp(subject, "u") == 0)
|
||||
subject = "user";
|
||||
else if (strcasecmp(subject, "g") == 0)
|
||||
subject = "group";
|
||||
else if (strcasecmp(subject, "p") == 0)
|
||||
subject = "process";
|
||||
else if (strcasecmp(subject, "l") == 0 ||
|
||||
strcasecmp(subject, "c") == 0 ||
|
||||
strcasecmp(subject, "class") == 0)
|
||||
subject = "loginclass";
|
||||
else if (strcasecmp(subject, "j") == 0)
|
||||
subject = "jail";
|
||||
|
||||
if (strcasecmp(subject, "user") == 0 && strlen(textid) > 0) {
|
||||
id = parse_user(textid);
|
||||
asprintf(&resolved, "%s:%d:%s", subject, (int)id, rest);
|
||||
} else if (strcasecmp(subject, "group") == 0 && strlen(textid) > 0) {
|
||||
id = parse_group(textid);
|
||||
asprintf(&resolved, "%s:%d:%s", subject, (int)id, rest);
|
||||
} else
|
||||
asprintf(&resolved, "%s:%s:%s", subject, textid, rest);
|
||||
|
||||
if (resolved == NULL)
|
||||
err(1, "asprintf");
|
||||
|
||||
return (resolved);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine replaces "human-readable" number with its expanded form.
|
||||
*/
|
||||
static char *
|
||||
expand_amount(char *rule)
|
||||
{
|
||||
uint64_t num;
|
||||
const char *subject, *subject_id, *resource, *action, *amount, *per;
|
||||
char *copy, *expanded;
|
||||
|
||||
copy = strdup(rule);
|
||||
if (copy == NULL)
|
||||
err(1, "strdup");
|
||||
|
||||
subject = strsep(©, ":");
|
||||
subject_id = strsep(©, ":");
|
||||
resource = strsep(©, ":");
|
||||
action = strsep(©, "=/");
|
||||
amount = strsep(©, "/");
|
||||
per = copy;
|
||||
|
||||
if (amount == NULL || strlen(amount) == 0) {
|
||||
free(copy);
|
||||
return (rule);
|
||||
}
|
||||
|
||||
assert(subject != NULL);
|
||||
assert(subject_id != NULL);
|
||||
assert(resource != NULL);
|
||||
assert(action != NULL);
|
||||
|
||||
if (expand_number(amount, &num))
|
||||
err(1, "expand_number");
|
||||
|
||||
if (per == NULL)
|
||||
asprintf(&expanded, "%s:%s:%s:%s=%ju", subject, subject_id,
|
||||
resource, action, (uintmax_t)num);
|
||||
else
|
||||
asprintf(&expanded, "%s:%s:%s:%s=%ju/%s", subject, subject_id,
|
||||
resource, action, (uintmax_t)num, per);
|
||||
|
||||
if (expanded == NULL)
|
||||
err(1, "asprintf");
|
||||
|
||||
return (expanded);
|
||||
}
|
||||
|
||||
static char *
|
||||
humanize_ids(char *rule)
|
||||
{
|
||||
id_t id;
|
||||
struct passwd *pwd;
|
||||
struct group *grp;
|
||||
const char *subject, *textid, *rest;
|
||||
char *humanized;
|
||||
|
||||
subject = strsep(&rule, ":");
|
||||
textid = strsep(&rule, ":");
|
||||
if (textid == NULL)
|
||||
errx(1, "rule passed from the kernel didn't contain subject");
|
||||
if (rule != NULL)
|
||||
rest = rule;
|
||||
else
|
||||
rest = "";
|
||||
|
||||
/* Replace numerical user and group ids with names. */
|
||||
if (strcasecmp(subject, "user") == 0) {
|
||||
id = parse_user(textid);
|
||||
pwd = getpwuid(id);
|
||||
if (pwd != NULL)
|
||||
textid = pwd->pw_name;
|
||||
} else if (strcasecmp(subject, "group") == 0) {
|
||||
id = parse_group(textid);
|
||||
grp = getgrgid(id);
|
||||
if (grp != NULL)
|
||||
textid = grp->gr_name;
|
||||
}
|
||||
|
||||
asprintf(&humanized, "%s:%s:%s", subject, textid, rest);
|
||||
|
||||
if (humanized == NULL)
|
||||
err(1, "asprintf");
|
||||
|
||||
return (humanized);
|
||||
}
|
||||
|
||||
static int
|
||||
str2int64(const char *str, int64_t *value)
|
||||
{
|
||||
char *end;
|
||||
|
||||
if (str == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
*value = strtoul(str, &end, 10);
|
||||
if ((size_t)(end - str) != strlen(str))
|
||||
return (EINVAL);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static char *
|
||||
humanize_amount(char *rule)
|
||||
{
|
||||
int64_t num;
|
||||
const char *subject, *subject_id, *resource, *action, *amount, *per;
|
||||
char *copy, *humanized, buf[6];
|
||||
|
||||
copy = strdup(rule);
|
||||
if (copy == NULL)
|
||||
err(1, "strdup");
|
||||
|
||||
subject = strsep(©, ":");
|
||||
subject_id = strsep(©, ":");
|
||||
resource = strsep(©, ":");
|
||||
action = strsep(©, "=/");
|
||||
amount = strsep(©, "/");
|
||||
per = copy;
|
||||
|
||||
if (amount == NULL || strlen(amount) == 0 ||
|
||||
str2int64(amount, &num) != 0) {
|
||||
free(copy);
|
||||
return (rule);
|
||||
}
|
||||
|
||||
assert(subject != NULL);
|
||||
assert(subject_id != NULL);
|
||||
assert(resource != NULL);
|
||||
assert(action != NULL);
|
||||
|
||||
if (humanize_number(buf, sizeof(buf), num, "", HN_AUTOSCALE,
|
||||
HN_DECIMAL | HN_NOSPACE) == -1)
|
||||
err(1, "humanize_number");
|
||||
|
||||
if (per == NULL)
|
||||
asprintf(&humanized, "%s:%s:%s:%s=%s", subject, subject_id,
|
||||
resource, action, buf);
|
||||
else
|
||||
asprintf(&humanized, "%s:%s:%s:%s=%s/%s", subject, subject_id,
|
||||
resource, action, buf, per);
|
||||
|
||||
if (humanized == NULL)
|
||||
err(1, "asprintf");
|
||||
|
||||
return (humanized);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print rules, one per line.
|
||||
*/
|
||||
static void
|
||||
print_rules(char *rules, int hflag, int nflag)
|
||||
{
|
||||
char *rule;
|
||||
|
||||
while ((rule = strsep(&rules, ",")) != NULL) {
|
||||
if (rule[0] == '\0')
|
||||
break; /* XXX */
|
||||
if (nflag == 0)
|
||||
rule = humanize_ids(rule);
|
||||
if (hflag)
|
||||
rule = humanize_amount(rule);
|
||||
printf("%s\n", rule);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_rule(char *rule)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = rctl_add_rule(rule, strlen(rule) + 1, NULL, 0);
|
||||
if (error != 0)
|
||||
err(1, "rctl_add_rule");
|
||||
free(rule);
|
||||
}
|
||||
|
||||
static void
|
||||
show_limits(char *filter, int hflag, int nflag)
|
||||
{
|
||||
int error;
|
||||
char *outbuf = NULL;
|
||||
size_t outbuflen = RCTL_DEFAULT_BUFSIZE / 4;
|
||||
|
||||
do {
|
||||
outbuflen *= 4;
|
||||
outbuf = realloc(outbuf, outbuflen);
|
||||
if (outbuf == NULL)
|
||||
err(1, "realloc");
|
||||
|
||||
error = rctl_get_limits(filter, strlen(filter) + 1, outbuf,
|
||||
outbuflen);
|
||||
if (error && errno != ERANGE)
|
||||
err(1, "rctl_get_limits");
|
||||
} while (error && errno == ERANGE);
|
||||
|
||||
print_rules(outbuf, hflag, nflag);
|
||||
free(filter);
|
||||
free(outbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_rule(char *filter)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = rctl_remove_rule(filter, strlen(filter) + 1, NULL, 0);
|
||||
if (error != 0)
|
||||
err(1, "rctl_remove_rule");
|
||||
free(filter);
|
||||
}
|
||||
|
||||
static char *
|
||||
humanize_usage_amount(char *usage)
|
||||
{
|
||||
int64_t num;
|
||||
const char *resource, *amount;
|
||||
char *copy, *humanized, buf[6];
|
||||
|
||||
copy = strdup(usage);
|
||||
if (copy == NULL)
|
||||
err(1, "strdup");
|
||||
|
||||
resource = strsep(©, "=");
|
||||
amount = copy;
|
||||
|
||||
assert(resource != NULL);
|
||||
assert(amount != NULL);
|
||||
|
||||
if (str2int64(amount, &num) != 0 ||
|
||||
humanize_number(buf, sizeof(buf), num, "", HN_AUTOSCALE,
|
||||
HN_DECIMAL | HN_NOSPACE) == -1) {
|
||||
free(copy);
|
||||
return (usage);
|
||||
}
|
||||
|
||||
asprintf(&humanized, "%s=%s", resource, buf);
|
||||
if (humanized == NULL)
|
||||
err(1, "asprintf");
|
||||
|
||||
return (humanized);
|
||||
}
|
||||
|
||||
/*
|
||||
* Query the kernel about a resource usage and print it out.
|
||||
*/
|
||||
static void
|
||||
show_usage(char *filter, int hflag)
|
||||
{
|
||||
int error;
|
||||
char *outbuf = NULL, *tmp;
|
||||
size_t outbuflen = RCTL_DEFAULT_BUFSIZE / 4;
|
||||
|
||||
do {
|
||||
outbuflen *= 4;
|
||||
outbuf = realloc(outbuf, outbuflen);
|
||||
if (outbuf == NULL)
|
||||
err(1, "realloc");
|
||||
|
||||
error = rctl_get_racct(filter, strlen(filter) + 1, outbuf,
|
||||
outbuflen);
|
||||
if (error && errno != ERANGE)
|
||||
err(1, "rctl_get_racct");
|
||||
} while (error && errno == ERANGE);
|
||||
|
||||
while ((tmp = strsep(&outbuf, ",")) != NULL) {
|
||||
if (tmp[0] == '\0')
|
||||
break; /* XXX */
|
||||
|
||||
if (hflag)
|
||||
tmp = humanize_usage_amount(tmp);
|
||||
|
||||
printf("%s\n", tmp);
|
||||
}
|
||||
|
||||
free(filter);
|
||||
free(outbuf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Query the kernel about resource limit rules and print them out.
|
||||
*/
|
||||
static void
|
||||
show_rules(char *filter, int hflag, int nflag)
|
||||
{
|
||||
int error;
|
||||
char *outbuf = NULL;
|
||||
size_t filterlen, outbuflen = RCTL_DEFAULT_BUFSIZE / 4;
|
||||
|
||||
if (filter != NULL)
|
||||
filterlen = strlen(filter) + 1;
|
||||
else
|
||||
filterlen = 0;
|
||||
|
||||
do {
|
||||
outbuflen *= 4;
|
||||
outbuf = realloc(outbuf, outbuflen);
|
||||
if (outbuf == NULL)
|
||||
err(1, "realloc");
|
||||
|
||||
error = rctl_get_rules(filter, filterlen, outbuf, outbuflen);
|
||||
if (error && errno != ERANGE)
|
||||
err(1, "rctl_get_rules");
|
||||
} while (error && errno == ERANGE);
|
||||
|
||||
print_rules(outbuf, hflag, nflag);
|
||||
free(outbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
fprintf(stderr, "usage: rctl [ -h ] [-a rule | -l filter | -r filter "
|
||||
"| -u filter | filter]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc __unused, char **argv __unused)
|
||||
{
|
||||
int ch, aflag = 0, hflag = 0, nflag = 0, lflag = 0, rflag = 0,
|
||||
uflag = 0;
|
||||
char *rule = NULL;
|
||||
|
||||
while ((ch = getopt(argc, argv, "a:hl:nr:u:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
aflag = 1;
|
||||
rule = strdup(optarg);
|
||||
break;
|
||||
case 'h':
|
||||
hflag = 1;
|
||||
break;
|
||||
case 'l':
|
||||
lflag = 1;
|
||||
rule = strdup(optarg);
|
||||
break;
|
||||
case 'n':
|
||||
nflag = 1;
|
||||
break;
|
||||
case 'r':
|
||||
rflag = 1;
|
||||
rule = strdup(optarg);
|
||||
break;
|
||||
case 'u':
|
||||
uflag = 1;
|
||||
rule = strdup(optarg);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc > 1)
|
||||
usage();
|
||||
|
||||
if (rule == NULL) {
|
||||
if (argc == 1)
|
||||
rule = strdup(argv[0]);
|
||||
else
|
||||
rule = strdup("::");
|
||||
}
|
||||
|
||||
if (aflag + lflag + rflag + uflag + argc > 1)
|
||||
errx(1, "only one flag or argument may be specified "
|
||||
"at the same time");
|
||||
|
||||
rule = resolve_ids(rule);
|
||||
rule = expand_amount(rule);
|
||||
|
||||
if (aflag) {
|
||||
add_rule(rule);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (lflag) {
|
||||
show_limits(rule, hflag, nflag);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (rflag) {
|
||||
remove_rule(rule);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (uflag) {
|
||||
show_usage(rule, hflag);
|
||||
return (0);
|
||||
}
|
||||
|
||||
show_rules(rule, hflag, nflag);
|
||||
return (0);
|
||||
}
|
Loading…
Reference in New Issue
Block a user