16ec54a57SEdward Tomasz Napierala /*- 26ec54a57SEdward Tomasz Napierala * Copyright (c) 2010 The FreeBSD Foundation 36ec54a57SEdward Tomasz Napierala * All rights reserved. 46ec54a57SEdward Tomasz Napierala * 56ec54a57SEdward Tomasz Napierala * This software was developed by Edward Tomasz Napierala under sponsorship 66ec54a57SEdward Tomasz Napierala * from the FreeBSD Foundation. 76ec54a57SEdward Tomasz Napierala * 86ec54a57SEdward Tomasz Napierala * Redistribution and use in source and binary forms, with or without 96ec54a57SEdward Tomasz Napierala * modification, are permitted provided that the following conditions 106ec54a57SEdward Tomasz Napierala * are met: 116ec54a57SEdward Tomasz Napierala * 1. Redistributions of source code must retain the above copyright 126ec54a57SEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer. 136ec54a57SEdward Tomasz Napierala * 2. Redistributions in binary form must reproduce the above copyright 146ec54a57SEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer in the 156ec54a57SEdward Tomasz Napierala * documentation and/or other materials provided with the distribution. 166ec54a57SEdward Tomasz Napierala * 176ec54a57SEdward Tomasz Napierala * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 186ec54a57SEdward Tomasz Napierala * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 196ec54a57SEdward Tomasz Napierala * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 206ec54a57SEdward Tomasz Napierala * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 216ec54a57SEdward Tomasz Napierala * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 226ec54a57SEdward Tomasz Napierala * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 236ec54a57SEdward Tomasz Napierala * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 246ec54a57SEdward Tomasz Napierala * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 256ec54a57SEdward Tomasz Napierala * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 266ec54a57SEdward Tomasz Napierala * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 276ec54a57SEdward Tomasz Napierala * SUCH DAMAGE. 286ec54a57SEdward Tomasz Napierala * 296ec54a57SEdward Tomasz Napierala * $FreeBSD$ 306ec54a57SEdward Tomasz Napierala */ 316ec54a57SEdward Tomasz Napierala 326ec54a57SEdward Tomasz Napierala #include <sys/cdefs.h> 336ec54a57SEdward Tomasz Napierala __FBSDID("$FreeBSD$"); 346ec54a57SEdward Tomasz Napierala 356ec54a57SEdward Tomasz Napierala #include <sys/types.h> 366ec54a57SEdward Tomasz Napierala #include <sys/rctl.h> 37*aae2a24bSEdward Tomasz Napierala #include <sys/sysctl.h> 386ec54a57SEdward Tomasz Napierala #include <assert.h> 396ec54a57SEdward Tomasz Napierala #include <ctype.h> 406ec54a57SEdward Tomasz Napierala #include <err.h> 416ec54a57SEdward Tomasz Napierala #include <errno.h> 426ec54a57SEdward Tomasz Napierala #include <getopt.h> 436ec54a57SEdward Tomasz Napierala #include <grp.h> 446ec54a57SEdward Tomasz Napierala #include <libutil.h> 456ec54a57SEdward Tomasz Napierala #include <pwd.h> 466ec54a57SEdward Tomasz Napierala #include <stdint.h> 476ec54a57SEdward Tomasz Napierala #include <stdio.h> 486ec54a57SEdward Tomasz Napierala #include <stdlib.h> 496ec54a57SEdward Tomasz Napierala #include <string.h> 506ec54a57SEdward Tomasz Napierala 516ec54a57SEdward Tomasz Napierala #define RCTL_DEFAULT_BUFSIZE 4096 526ec54a57SEdward Tomasz Napierala 536ec54a57SEdward Tomasz Napierala static id_t 546ec54a57SEdward Tomasz Napierala parse_user(const char *s) 556ec54a57SEdward Tomasz Napierala { 566ec54a57SEdward Tomasz Napierala id_t id; 576ec54a57SEdward Tomasz Napierala char *end; 586ec54a57SEdward Tomasz Napierala struct passwd *pwd; 596ec54a57SEdward Tomasz Napierala 606ec54a57SEdward Tomasz Napierala pwd = getpwnam(s); 616ec54a57SEdward Tomasz Napierala if (pwd != NULL) 626ec54a57SEdward Tomasz Napierala return (pwd->pw_uid); 636ec54a57SEdward Tomasz Napierala 646ec54a57SEdward Tomasz Napierala if (!isnumber(s[0])) 656ec54a57SEdward Tomasz Napierala errx(1, "uknown user '%s'", s); 666ec54a57SEdward Tomasz Napierala 676ec54a57SEdward Tomasz Napierala id = strtod(s, &end); 686ec54a57SEdward Tomasz Napierala if ((size_t)(end - s) != strlen(s)) 696ec54a57SEdward Tomasz Napierala errx(1, "trailing characters after numerical id"); 706ec54a57SEdward Tomasz Napierala 716ec54a57SEdward Tomasz Napierala return (id); 726ec54a57SEdward Tomasz Napierala } 736ec54a57SEdward Tomasz Napierala 746ec54a57SEdward Tomasz Napierala static id_t 756ec54a57SEdward Tomasz Napierala parse_group(const char *s) 766ec54a57SEdward Tomasz Napierala { 776ec54a57SEdward Tomasz Napierala id_t id; 786ec54a57SEdward Tomasz Napierala char *end; 796ec54a57SEdward Tomasz Napierala struct group *grp; 806ec54a57SEdward Tomasz Napierala 816ec54a57SEdward Tomasz Napierala grp = getgrnam(s); 826ec54a57SEdward Tomasz Napierala if (grp != NULL) 836ec54a57SEdward Tomasz Napierala return (grp->gr_gid); 846ec54a57SEdward Tomasz Napierala 856ec54a57SEdward Tomasz Napierala if (!isnumber(s[0])) 866ec54a57SEdward Tomasz Napierala errx(1, "uknown group '%s'", s); 876ec54a57SEdward Tomasz Napierala 886ec54a57SEdward Tomasz Napierala id = strtod(s, &end); 896ec54a57SEdward Tomasz Napierala if ((size_t)(end - s) != strlen(s)) 906ec54a57SEdward Tomasz Napierala errx(1, "trailing characters after numerical id"); 916ec54a57SEdward Tomasz Napierala 926ec54a57SEdward Tomasz Napierala return (id); 936ec54a57SEdward Tomasz Napierala } 946ec54a57SEdward Tomasz Napierala 956ec54a57SEdward Tomasz Napierala /* 966ec54a57SEdward Tomasz Napierala * This routine replaces user/group name with numeric id. 976ec54a57SEdward Tomasz Napierala */ 986ec54a57SEdward Tomasz Napierala static char * 996ec54a57SEdward Tomasz Napierala resolve_ids(char *rule) 1006ec54a57SEdward Tomasz Napierala { 1016ec54a57SEdward Tomasz Napierala id_t id; 1026ec54a57SEdward Tomasz Napierala const char *subject, *textid, *rest; 1036ec54a57SEdward Tomasz Napierala char *resolved; 1046ec54a57SEdward Tomasz Napierala 1056ec54a57SEdward Tomasz Napierala subject = strsep(&rule, ":"); 1066ec54a57SEdward Tomasz Napierala textid = strsep(&rule, ":"); 1076ec54a57SEdward Tomasz Napierala if (textid == NULL) 1086ec54a57SEdward Tomasz Napierala errx(1, "error in rule specification -- no subject"); 1096ec54a57SEdward Tomasz Napierala if (rule != NULL) 1106ec54a57SEdward Tomasz Napierala rest = rule; 1116ec54a57SEdward Tomasz Napierala else 1126ec54a57SEdward Tomasz Napierala rest = ""; 1136ec54a57SEdward Tomasz Napierala 1146ec54a57SEdward Tomasz Napierala if (strcasecmp(subject, "u") == 0) 1156ec54a57SEdward Tomasz Napierala subject = "user"; 1166ec54a57SEdward Tomasz Napierala else if (strcasecmp(subject, "g") == 0) 1176ec54a57SEdward Tomasz Napierala subject = "group"; 1186ec54a57SEdward Tomasz Napierala else if (strcasecmp(subject, "p") == 0) 1196ec54a57SEdward Tomasz Napierala subject = "process"; 1206ec54a57SEdward Tomasz Napierala else if (strcasecmp(subject, "l") == 0 || 1216ec54a57SEdward Tomasz Napierala strcasecmp(subject, "c") == 0 || 1226ec54a57SEdward Tomasz Napierala strcasecmp(subject, "class") == 0) 1236ec54a57SEdward Tomasz Napierala subject = "loginclass"; 1246ec54a57SEdward Tomasz Napierala else if (strcasecmp(subject, "j") == 0) 1256ec54a57SEdward Tomasz Napierala subject = "jail"; 1266ec54a57SEdward Tomasz Napierala 1276ec54a57SEdward Tomasz Napierala if (strcasecmp(subject, "user") == 0 && strlen(textid) > 0) { 1286ec54a57SEdward Tomasz Napierala id = parse_user(textid); 1296ec54a57SEdward Tomasz Napierala asprintf(&resolved, "%s:%d:%s", subject, (int)id, rest); 1306ec54a57SEdward Tomasz Napierala } else if (strcasecmp(subject, "group") == 0 && strlen(textid) > 0) { 1316ec54a57SEdward Tomasz Napierala id = parse_group(textid); 1326ec54a57SEdward Tomasz Napierala asprintf(&resolved, "%s:%d:%s", subject, (int)id, rest); 1336ec54a57SEdward Tomasz Napierala } else 1346ec54a57SEdward Tomasz Napierala asprintf(&resolved, "%s:%s:%s", subject, textid, rest); 1356ec54a57SEdward Tomasz Napierala 1366ec54a57SEdward Tomasz Napierala if (resolved == NULL) 1376ec54a57SEdward Tomasz Napierala err(1, "asprintf"); 1386ec54a57SEdward Tomasz Napierala 1396ec54a57SEdward Tomasz Napierala return (resolved); 1406ec54a57SEdward Tomasz Napierala } 1416ec54a57SEdward Tomasz Napierala 1426ec54a57SEdward Tomasz Napierala /* 1436ec54a57SEdward Tomasz Napierala * This routine replaces "human-readable" number with its expanded form. 1446ec54a57SEdward Tomasz Napierala */ 1456ec54a57SEdward Tomasz Napierala static char * 1466ec54a57SEdward Tomasz Napierala expand_amount(char *rule) 1476ec54a57SEdward Tomasz Napierala { 1486ec54a57SEdward Tomasz Napierala uint64_t num; 1496ec54a57SEdward Tomasz Napierala const char *subject, *subject_id, *resource, *action, *amount, *per; 1506ec54a57SEdward Tomasz Napierala char *copy, *expanded; 1516ec54a57SEdward Tomasz Napierala 1526ec54a57SEdward Tomasz Napierala copy = strdup(rule); 1536ec54a57SEdward Tomasz Napierala if (copy == NULL) 1546ec54a57SEdward Tomasz Napierala err(1, "strdup"); 1556ec54a57SEdward Tomasz Napierala 1566ec54a57SEdward Tomasz Napierala subject = strsep(©, ":"); 1576ec54a57SEdward Tomasz Napierala subject_id = strsep(©, ":"); 1586ec54a57SEdward Tomasz Napierala resource = strsep(©, ":"); 1596ec54a57SEdward Tomasz Napierala action = strsep(©, "=/"); 1606ec54a57SEdward Tomasz Napierala amount = strsep(©, "/"); 1616ec54a57SEdward Tomasz Napierala per = copy; 1626ec54a57SEdward Tomasz Napierala 1636ec54a57SEdward Tomasz Napierala if (amount == NULL || strlen(amount) == 0) { 1646ec54a57SEdward Tomasz Napierala free(copy); 1656ec54a57SEdward Tomasz Napierala return (rule); 1666ec54a57SEdward Tomasz Napierala } 1676ec54a57SEdward Tomasz Napierala 1686ec54a57SEdward Tomasz Napierala assert(subject != NULL); 1696ec54a57SEdward Tomasz Napierala assert(subject_id != NULL); 1706ec54a57SEdward Tomasz Napierala assert(resource != NULL); 1716ec54a57SEdward Tomasz Napierala assert(action != NULL); 1726ec54a57SEdward Tomasz Napierala 1736ec54a57SEdward Tomasz Napierala if (expand_number(amount, &num)) 1746ec54a57SEdward Tomasz Napierala err(1, "expand_number"); 1756ec54a57SEdward Tomasz Napierala 1766ec54a57SEdward Tomasz Napierala if (per == NULL) 1776ec54a57SEdward Tomasz Napierala asprintf(&expanded, "%s:%s:%s:%s=%ju", subject, subject_id, 1786ec54a57SEdward Tomasz Napierala resource, action, (uintmax_t)num); 1796ec54a57SEdward Tomasz Napierala else 1806ec54a57SEdward Tomasz Napierala asprintf(&expanded, "%s:%s:%s:%s=%ju/%s", subject, subject_id, 1816ec54a57SEdward Tomasz Napierala resource, action, (uintmax_t)num, per); 1826ec54a57SEdward Tomasz Napierala 1836ec54a57SEdward Tomasz Napierala if (expanded == NULL) 1846ec54a57SEdward Tomasz Napierala err(1, "asprintf"); 1856ec54a57SEdward Tomasz Napierala 1866ec54a57SEdward Tomasz Napierala return (expanded); 1876ec54a57SEdward Tomasz Napierala } 1886ec54a57SEdward Tomasz Napierala 1896ec54a57SEdward Tomasz Napierala static char * 1906ec54a57SEdward Tomasz Napierala humanize_ids(char *rule) 1916ec54a57SEdward Tomasz Napierala { 1926ec54a57SEdward Tomasz Napierala id_t id; 1936ec54a57SEdward Tomasz Napierala struct passwd *pwd; 1946ec54a57SEdward Tomasz Napierala struct group *grp; 1956ec54a57SEdward Tomasz Napierala const char *subject, *textid, *rest; 1966ec54a57SEdward Tomasz Napierala char *humanized; 1976ec54a57SEdward Tomasz Napierala 1986ec54a57SEdward Tomasz Napierala subject = strsep(&rule, ":"); 1996ec54a57SEdward Tomasz Napierala textid = strsep(&rule, ":"); 2006ec54a57SEdward Tomasz Napierala if (textid == NULL) 2016ec54a57SEdward Tomasz Napierala errx(1, "rule passed from the kernel didn't contain subject"); 2026ec54a57SEdward Tomasz Napierala if (rule != NULL) 2036ec54a57SEdward Tomasz Napierala rest = rule; 2046ec54a57SEdward Tomasz Napierala else 2056ec54a57SEdward Tomasz Napierala rest = ""; 2066ec54a57SEdward Tomasz Napierala 2076ec54a57SEdward Tomasz Napierala /* Replace numerical user and group ids with names. */ 2086ec54a57SEdward Tomasz Napierala if (strcasecmp(subject, "user") == 0) { 2096ec54a57SEdward Tomasz Napierala id = parse_user(textid); 2106ec54a57SEdward Tomasz Napierala pwd = getpwuid(id); 2116ec54a57SEdward Tomasz Napierala if (pwd != NULL) 2126ec54a57SEdward Tomasz Napierala textid = pwd->pw_name; 2136ec54a57SEdward Tomasz Napierala } else if (strcasecmp(subject, "group") == 0) { 2146ec54a57SEdward Tomasz Napierala id = parse_group(textid); 2156ec54a57SEdward Tomasz Napierala grp = getgrgid(id); 2166ec54a57SEdward Tomasz Napierala if (grp != NULL) 2176ec54a57SEdward Tomasz Napierala textid = grp->gr_name; 2186ec54a57SEdward Tomasz Napierala } 2196ec54a57SEdward Tomasz Napierala 2206ec54a57SEdward Tomasz Napierala asprintf(&humanized, "%s:%s:%s", subject, textid, rest); 2216ec54a57SEdward Tomasz Napierala 2226ec54a57SEdward Tomasz Napierala if (humanized == NULL) 2236ec54a57SEdward Tomasz Napierala err(1, "asprintf"); 2246ec54a57SEdward Tomasz Napierala 2256ec54a57SEdward Tomasz Napierala return (humanized); 2266ec54a57SEdward Tomasz Napierala } 2276ec54a57SEdward Tomasz Napierala 2286ec54a57SEdward Tomasz Napierala static int 2296ec54a57SEdward Tomasz Napierala str2int64(const char *str, int64_t *value) 2306ec54a57SEdward Tomasz Napierala { 2316ec54a57SEdward Tomasz Napierala char *end; 2326ec54a57SEdward Tomasz Napierala 2336ec54a57SEdward Tomasz Napierala if (str == NULL) 2346ec54a57SEdward Tomasz Napierala return (EINVAL); 2356ec54a57SEdward Tomasz Napierala 2366ec54a57SEdward Tomasz Napierala *value = strtoul(str, &end, 10); 2376ec54a57SEdward Tomasz Napierala if ((size_t)(end - str) != strlen(str)) 2386ec54a57SEdward Tomasz Napierala return (EINVAL); 2396ec54a57SEdward Tomasz Napierala 2406ec54a57SEdward Tomasz Napierala return (0); 2416ec54a57SEdward Tomasz Napierala } 2426ec54a57SEdward Tomasz Napierala 2436ec54a57SEdward Tomasz Napierala static char * 2446ec54a57SEdward Tomasz Napierala humanize_amount(char *rule) 2456ec54a57SEdward Tomasz Napierala { 2466ec54a57SEdward Tomasz Napierala int64_t num; 2476ec54a57SEdward Tomasz Napierala const char *subject, *subject_id, *resource, *action, *amount, *per; 2486ec54a57SEdward Tomasz Napierala char *copy, *humanized, buf[6]; 2496ec54a57SEdward Tomasz Napierala 2506ec54a57SEdward Tomasz Napierala copy = strdup(rule); 2516ec54a57SEdward Tomasz Napierala if (copy == NULL) 2526ec54a57SEdward Tomasz Napierala err(1, "strdup"); 2536ec54a57SEdward Tomasz Napierala 2546ec54a57SEdward Tomasz Napierala subject = strsep(©, ":"); 2556ec54a57SEdward Tomasz Napierala subject_id = strsep(©, ":"); 2566ec54a57SEdward Tomasz Napierala resource = strsep(©, ":"); 2576ec54a57SEdward Tomasz Napierala action = strsep(©, "=/"); 2586ec54a57SEdward Tomasz Napierala amount = strsep(©, "/"); 2596ec54a57SEdward Tomasz Napierala per = copy; 2606ec54a57SEdward Tomasz Napierala 2616ec54a57SEdward Tomasz Napierala if (amount == NULL || strlen(amount) == 0 || 2626ec54a57SEdward Tomasz Napierala str2int64(amount, &num) != 0) { 2636ec54a57SEdward Tomasz Napierala free(copy); 2646ec54a57SEdward Tomasz Napierala return (rule); 2656ec54a57SEdward Tomasz Napierala } 2666ec54a57SEdward Tomasz Napierala 2676ec54a57SEdward Tomasz Napierala assert(subject != NULL); 2686ec54a57SEdward Tomasz Napierala assert(subject_id != NULL); 2696ec54a57SEdward Tomasz Napierala assert(resource != NULL); 2706ec54a57SEdward Tomasz Napierala assert(action != NULL); 2716ec54a57SEdward Tomasz Napierala 2726ec54a57SEdward Tomasz Napierala if (humanize_number(buf, sizeof(buf), num, "", HN_AUTOSCALE, 2736ec54a57SEdward Tomasz Napierala HN_DECIMAL | HN_NOSPACE) == -1) 2746ec54a57SEdward Tomasz Napierala err(1, "humanize_number"); 2756ec54a57SEdward Tomasz Napierala 2766ec54a57SEdward Tomasz Napierala if (per == NULL) 2776ec54a57SEdward Tomasz Napierala asprintf(&humanized, "%s:%s:%s:%s=%s", subject, subject_id, 2786ec54a57SEdward Tomasz Napierala resource, action, buf); 2796ec54a57SEdward Tomasz Napierala else 2806ec54a57SEdward Tomasz Napierala asprintf(&humanized, "%s:%s:%s:%s=%s/%s", subject, subject_id, 2816ec54a57SEdward Tomasz Napierala resource, action, buf, per); 2826ec54a57SEdward Tomasz Napierala 2836ec54a57SEdward Tomasz Napierala if (humanized == NULL) 2846ec54a57SEdward Tomasz Napierala err(1, "asprintf"); 2856ec54a57SEdward Tomasz Napierala 2866ec54a57SEdward Tomasz Napierala return (humanized); 2876ec54a57SEdward Tomasz Napierala } 2886ec54a57SEdward Tomasz Napierala 2896ec54a57SEdward Tomasz Napierala /* 2906ec54a57SEdward Tomasz Napierala * Print rules, one per line. 2916ec54a57SEdward Tomasz Napierala */ 2926ec54a57SEdward Tomasz Napierala static void 2936ec54a57SEdward Tomasz Napierala print_rules(char *rules, int hflag, int nflag) 2946ec54a57SEdward Tomasz Napierala { 2956ec54a57SEdward Tomasz Napierala char *rule; 2966ec54a57SEdward Tomasz Napierala 2976ec54a57SEdward Tomasz Napierala while ((rule = strsep(&rules, ",")) != NULL) { 2986ec54a57SEdward Tomasz Napierala if (rule[0] == '\0') 2996ec54a57SEdward Tomasz Napierala break; /* XXX */ 3006ec54a57SEdward Tomasz Napierala if (nflag == 0) 3016ec54a57SEdward Tomasz Napierala rule = humanize_ids(rule); 3026ec54a57SEdward Tomasz Napierala if (hflag) 3036ec54a57SEdward Tomasz Napierala rule = humanize_amount(rule); 3046ec54a57SEdward Tomasz Napierala printf("%s\n", rule); 3056ec54a57SEdward Tomasz Napierala } 3066ec54a57SEdward Tomasz Napierala } 3076ec54a57SEdward Tomasz Napierala 3086ec54a57SEdward Tomasz Napierala static void 309*aae2a24bSEdward Tomasz Napierala enosys(void) 310*aae2a24bSEdward Tomasz Napierala { 311*aae2a24bSEdward Tomasz Napierala int error, racct_enable; 312*aae2a24bSEdward Tomasz Napierala size_t racct_enable_len; 313*aae2a24bSEdward Tomasz Napierala 314*aae2a24bSEdward Tomasz Napierala racct_enable_len = sizeof(racct_enable); 315*aae2a24bSEdward Tomasz Napierala error = sysctlbyname("kern.racct.enable", 316*aae2a24bSEdward Tomasz Napierala &racct_enable, &racct_enable_len, NULL, 0); 317*aae2a24bSEdward Tomasz Napierala 318*aae2a24bSEdward Tomasz Napierala if (error != 0) { 319*aae2a24bSEdward Tomasz Napierala if (errno == ENOENT) 320*aae2a24bSEdward Tomasz Napierala errx(1, "RACCT/RCTL support not present in kernel; see rctl(8) for details."); 321*aae2a24bSEdward Tomasz Napierala 322*aae2a24bSEdward Tomasz Napierala err(1, "sysctlbyname"); 323*aae2a24bSEdward Tomasz Napierala } 324*aae2a24bSEdward Tomasz Napierala 325*aae2a24bSEdward Tomasz Napierala if (racct_enable == 0) 326*aae2a24bSEdward Tomasz Napierala errx(1, "RACCT/RCTL present, but disabled; enable using kern.racct.enable=1 tunable"); 327*aae2a24bSEdward Tomasz Napierala } 328*aae2a24bSEdward Tomasz Napierala 329*aae2a24bSEdward Tomasz Napierala static void 3306ec54a57SEdward Tomasz Napierala add_rule(char *rule) 3316ec54a57SEdward Tomasz Napierala { 3326ec54a57SEdward Tomasz Napierala int error; 3336ec54a57SEdward Tomasz Napierala 3346ec54a57SEdward Tomasz Napierala error = rctl_add_rule(rule, strlen(rule) + 1, NULL, 0); 335*aae2a24bSEdward Tomasz Napierala if (error != 0) { 336*aae2a24bSEdward Tomasz Napierala if (errno == ENOSYS) 337*aae2a24bSEdward Tomasz Napierala enosys(); 3386ec54a57SEdward Tomasz Napierala err(1, "rctl_add_rule"); 339*aae2a24bSEdward Tomasz Napierala } 3406ec54a57SEdward Tomasz Napierala free(rule); 3416ec54a57SEdward Tomasz Napierala } 3426ec54a57SEdward Tomasz Napierala 3436ec54a57SEdward Tomasz Napierala static void 3446ec54a57SEdward Tomasz Napierala show_limits(char *filter, int hflag, int nflag) 3456ec54a57SEdward Tomasz Napierala { 3466ec54a57SEdward Tomasz Napierala int error; 3476ec54a57SEdward Tomasz Napierala char *outbuf = NULL; 3486ec54a57SEdward Tomasz Napierala size_t outbuflen = RCTL_DEFAULT_BUFSIZE / 4; 3496ec54a57SEdward Tomasz Napierala 3506ec54a57SEdward Tomasz Napierala do { 3516ec54a57SEdward Tomasz Napierala outbuflen *= 4; 3526ec54a57SEdward Tomasz Napierala outbuf = realloc(outbuf, outbuflen); 3536ec54a57SEdward Tomasz Napierala if (outbuf == NULL) 3546ec54a57SEdward Tomasz Napierala err(1, "realloc"); 3556ec54a57SEdward Tomasz Napierala 3566ec54a57SEdward Tomasz Napierala error = rctl_get_limits(filter, strlen(filter) + 1, outbuf, 3576ec54a57SEdward Tomasz Napierala outbuflen); 358*aae2a24bSEdward Tomasz Napierala if (error && errno != ERANGE) { 359*aae2a24bSEdward Tomasz Napierala if (errno == ENOSYS) 360*aae2a24bSEdward Tomasz Napierala enosys(); 3616ec54a57SEdward Tomasz Napierala err(1, "rctl_get_limits"); 362*aae2a24bSEdward Tomasz Napierala } 3636ec54a57SEdward Tomasz Napierala } while (error && errno == ERANGE); 3646ec54a57SEdward Tomasz Napierala 3656ec54a57SEdward Tomasz Napierala print_rules(outbuf, hflag, nflag); 3666ec54a57SEdward Tomasz Napierala free(filter); 3676ec54a57SEdward Tomasz Napierala free(outbuf); 3686ec54a57SEdward Tomasz Napierala } 3696ec54a57SEdward Tomasz Napierala 3706ec54a57SEdward Tomasz Napierala static void 3716ec54a57SEdward Tomasz Napierala remove_rule(char *filter) 3726ec54a57SEdward Tomasz Napierala { 3736ec54a57SEdward Tomasz Napierala int error; 3746ec54a57SEdward Tomasz Napierala 3756ec54a57SEdward Tomasz Napierala error = rctl_remove_rule(filter, strlen(filter) + 1, NULL, 0); 376*aae2a24bSEdward Tomasz Napierala if (error != 0) { 377*aae2a24bSEdward Tomasz Napierala if (errno == ENOSYS) 378*aae2a24bSEdward Tomasz Napierala enosys(); 3796ec54a57SEdward Tomasz Napierala err(1, "rctl_remove_rule"); 380*aae2a24bSEdward Tomasz Napierala } 3816ec54a57SEdward Tomasz Napierala free(filter); 3826ec54a57SEdward Tomasz Napierala } 3836ec54a57SEdward Tomasz Napierala 3846ec54a57SEdward Tomasz Napierala static char * 3856ec54a57SEdward Tomasz Napierala humanize_usage_amount(char *usage) 3866ec54a57SEdward Tomasz Napierala { 3876ec54a57SEdward Tomasz Napierala int64_t num; 3886ec54a57SEdward Tomasz Napierala const char *resource, *amount; 3896ec54a57SEdward Tomasz Napierala char *copy, *humanized, buf[6]; 3906ec54a57SEdward Tomasz Napierala 3916ec54a57SEdward Tomasz Napierala copy = strdup(usage); 3926ec54a57SEdward Tomasz Napierala if (copy == NULL) 3936ec54a57SEdward Tomasz Napierala err(1, "strdup"); 3946ec54a57SEdward Tomasz Napierala 3956ec54a57SEdward Tomasz Napierala resource = strsep(©, "="); 3966ec54a57SEdward Tomasz Napierala amount = copy; 3976ec54a57SEdward Tomasz Napierala 3986ec54a57SEdward Tomasz Napierala assert(resource != NULL); 3996ec54a57SEdward Tomasz Napierala assert(amount != NULL); 4006ec54a57SEdward Tomasz Napierala 4016ec54a57SEdward Tomasz Napierala if (str2int64(amount, &num) != 0 || 4026ec54a57SEdward Tomasz Napierala humanize_number(buf, sizeof(buf), num, "", HN_AUTOSCALE, 4036ec54a57SEdward Tomasz Napierala HN_DECIMAL | HN_NOSPACE) == -1) { 4046ec54a57SEdward Tomasz Napierala free(copy); 4056ec54a57SEdward Tomasz Napierala return (usage); 4066ec54a57SEdward Tomasz Napierala } 4076ec54a57SEdward Tomasz Napierala 4086ec54a57SEdward Tomasz Napierala asprintf(&humanized, "%s=%s", resource, buf); 4096ec54a57SEdward Tomasz Napierala if (humanized == NULL) 4106ec54a57SEdward Tomasz Napierala err(1, "asprintf"); 4116ec54a57SEdward Tomasz Napierala 4126ec54a57SEdward Tomasz Napierala return (humanized); 4136ec54a57SEdward Tomasz Napierala } 4146ec54a57SEdward Tomasz Napierala 4156ec54a57SEdward Tomasz Napierala /* 4166ec54a57SEdward Tomasz Napierala * Query the kernel about a resource usage and print it out. 4176ec54a57SEdward Tomasz Napierala */ 4186ec54a57SEdward Tomasz Napierala static void 4196ec54a57SEdward Tomasz Napierala show_usage(char *filter, int hflag) 4206ec54a57SEdward Tomasz Napierala { 4216ec54a57SEdward Tomasz Napierala int error; 4226ec54a57SEdward Tomasz Napierala char *outbuf = NULL, *tmp; 4236ec54a57SEdward Tomasz Napierala size_t outbuflen = RCTL_DEFAULT_BUFSIZE / 4; 4246ec54a57SEdward Tomasz Napierala 4256ec54a57SEdward Tomasz Napierala do { 4266ec54a57SEdward Tomasz Napierala outbuflen *= 4; 4276ec54a57SEdward Tomasz Napierala outbuf = realloc(outbuf, outbuflen); 4286ec54a57SEdward Tomasz Napierala if (outbuf == NULL) 4296ec54a57SEdward Tomasz Napierala err(1, "realloc"); 4306ec54a57SEdward Tomasz Napierala 4316ec54a57SEdward Tomasz Napierala error = rctl_get_racct(filter, strlen(filter) + 1, outbuf, 4326ec54a57SEdward Tomasz Napierala outbuflen); 433*aae2a24bSEdward Tomasz Napierala if (error && errno != ERANGE) { 434*aae2a24bSEdward Tomasz Napierala if (errno == ENOSYS) 435*aae2a24bSEdward Tomasz Napierala enosys(); 4366ec54a57SEdward Tomasz Napierala err(1, "rctl_get_racct"); 437*aae2a24bSEdward Tomasz Napierala } 4386ec54a57SEdward Tomasz Napierala } while (error && errno == ERANGE); 4396ec54a57SEdward Tomasz Napierala 4406ec54a57SEdward Tomasz Napierala while ((tmp = strsep(&outbuf, ",")) != NULL) { 4416ec54a57SEdward Tomasz Napierala if (tmp[0] == '\0') 4426ec54a57SEdward Tomasz Napierala break; /* XXX */ 4436ec54a57SEdward Tomasz Napierala 4446ec54a57SEdward Tomasz Napierala if (hflag) 4456ec54a57SEdward Tomasz Napierala tmp = humanize_usage_amount(tmp); 4466ec54a57SEdward Tomasz Napierala 4476ec54a57SEdward Tomasz Napierala printf("%s\n", tmp); 4486ec54a57SEdward Tomasz Napierala } 4496ec54a57SEdward Tomasz Napierala 4506ec54a57SEdward Tomasz Napierala free(filter); 4516ec54a57SEdward Tomasz Napierala free(outbuf); 4526ec54a57SEdward Tomasz Napierala } 4536ec54a57SEdward Tomasz Napierala 4546ec54a57SEdward Tomasz Napierala /* 4556ec54a57SEdward Tomasz Napierala * Query the kernel about resource limit rules and print them out. 4566ec54a57SEdward Tomasz Napierala */ 4576ec54a57SEdward Tomasz Napierala static void 4586ec54a57SEdward Tomasz Napierala show_rules(char *filter, int hflag, int nflag) 4596ec54a57SEdward Tomasz Napierala { 4606ec54a57SEdward Tomasz Napierala int error; 4616ec54a57SEdward Tomasz Napierala char *outbuf = NULL; 4626ec54a57SEdward Tomasz Napierala size_t filterlen, outbuflen = RCTL_DEFAULT_BUFSIZE / 4; 4636ec54a57SEdward Tomasz Napierala 4646ec54a57SEdward Tomasz Napierala if (filter != NULL) 4656ec54a57SEdward Tomasz Napierala filterlen = strlen(filter) + 1; 4666ec54a57SEdward Tomasz Napierala else 4676ec54a57SEdward Tomasz Napierala filterlen = 0; 4686ec54a57SEdward Tomasz Napierala 4696ec54a57SEdward Tomasz Napierala do { 4706ec54a57SEdward Tomasz Napierala outbuflen *= 4; 4716ec54a57SEdward Tomasz Napierala outbuf = realloc(outbuf, outbuflen); 4726ec54a57SEdward Tomasz Napierala if (outbuf == NULL) 4736ec54a57SEdward Tomasz Napierala err(1, "realloc"); 4746ec54a57SEdward Tomasz Napierala 4756ec54a57SEdward Tomasz Napierala error = rctl_get_rules(filter, filterlen, outbuf, outbuflen); 476*aae2a24bSEdward Tomasz Napierala if (error && errno != ERANGE) { 477*aae2a24bSEdward Tomasz Napierala if (errno == ENOSYS) 478*aae2a24bSEdward Tomasz Napierala enosys(); 4796ec54a57SEdward Tomasz Napierala err(1, "rctl_get_rules"); 480*aae2a24bSEdward Tomasz Napierala } 4816ec54a57SEdward Tomasz Napierala } while (error && errno == ERANGE); 4826ec54a57SEdward Tomasz Napierala 4836ec54a57SEdward Tomasz Napierala print_rules(outbuf, hflag, nflag); 4846ec54a57SEdward Tomasz Napierala free(outbuf); 4856ec54a57SEdward Tomasz Napierala } 4866ec54a57SEdward Tomasz Napierala 4876ec54a57SEdward Tomasz Napierala static void 4886ec54a57SEdward Tomasz Napierala usage(void) 4896ec54a57SEdward Tomasz Napierala { 4906ec54a57SEdward Tomasz Napierala 4916ec54a57SEdward Tomasz Napierala fprintf(stderr, "usage: rctl [ -h ] [-a rule | -l filter | -r filter " 4926ec54a57SEdward Tomasz Napierala "| -u filter | filter]\n"); 4936ec54a57SEdward Tomasz Napierala exit(1); 4946ec54a57SEdward Tomasz Napierala } 4956ec54a57SEdward Tomasz Napierala 4966ec54a57SEdward Tomasz Napierala int 4976ec54a57SEdward Tomasz Napierala main(int argc __unused, char **argv __unused) 4986ec54a57SEdward Tomasz Napierala { 4996ec54a57SEdward Tomasz Napierala int ch, aflag = 0, hflag = 0, nflag = 0, lflag = 0, rflag = 0, 5006ec54a57SEdward Tomasz Napierala uflag = 0; 5016ec54a57SEdward Tomasz Napierala char *rule = NULL; 5026ec54a57SEdward Tomasz Napierala 5036ec54a57SEdward Tomasz Napierala while ((ch = getopt(argc, argv, "a:hl:nr:u:")) != -1) { 5046ec54a57SEdward Tomasz Napierala switch (ch) { 5056ec54a57SEdward Tomasz Napierala case 'a': 5066ec54a57SEdward Tomasz Napierala aflag = 1; 5076ec54a57SEdward Tomasz Napierala rule = strdup(optarg); 5086ec54a57SEdward Tomasz Napierala break; 5096ec54a57SEdward Tomasz Napierala case 'h': 5106ec54a57SEdward Tomasz Napierala hflag = 1; 5116ec54a57SEdward Tomasz Napierala break; 5126ec54a57SEdward Tomasz Napierala case 'l': 5136ec54a57SEdward Tomasz Napierala lflag = 1; 5146ec54a57SEdward Tomasz Napierala rule = strdup(optarg); 5156ec54a57SEdward Tomasz Napierala break; 5166ec54a57SEdward Tomasz Napierala case 'n': 5176ec54a57SEdward Tomasz Napierala nflag = 1; 5186ec54a57SEdward Tomasz Napierala break; 5196ec54a57SEdward Tomasz Napierala case 'r': 5206ec54a57SEdward Tomasz Napierala rflag = 1; 5216ec54a57SEdward Tomasz Napierala rule = strdup(optarg); 5226ec54a57SEdward Tomasz Napierala break; 5236ec54a57SEdward Tomasz Napierala case 'u': 5246ec54a57SEdward Tomasz Napierala uflag = 1; 5256ec54a57SEdward Tomasz Napierala rule = strdup(optarg); 5266ec54a57SEdward Tomasz Napierala break; 5276ec54a57SEdward Tomasz Napierala 5286ec54a57SEdward Tomasz Napierala case '?': 5296ec54a57SEdward Tomasz Napierala default: 5306ec54a57SEdward Tomasz Napierala usage(); 5316ec54a57SEdward Tomasz Napierala } 5326ec54a57SEdward Tomasz Napierala } 5336ec54a57SEdward Tomasz Napierala 5346ec54a57SEdward Tomasz Napierala argc -= optind; 5356ec54a57SEdward Tomasz Napierala argv += optind; 5366ec54a57SEdward Tomasz Napierala 5376ec54a57SEdward Tomasz Napierala if (argc > 1) 5386ec54a57SEdward Tomasz Napierala usage(); 5396ec54a57SEdward Tomasz Napierala 5406ec54a57SEdward Tomasz Napierala if (rule == NULL) { 5416ec54a57SEdward Tomasz Napierala if (argc == 1) 5426ec54a57SEdward Tomasz Napierala rule = strdup(argv[0]); 5436ec54a57SEdward Tomasz Napierala else 5446ec54a57SEdward Tomasz Napierala rule = strdup("::"); 5456ec54a57SEdward Tomasz Napierala } 5466ec54a57SEdward Tomasz Napierala 5476ec54a57SEdward Tomasz Napierala if (aflag + lflag + rflag + uflag + argc > 1) 5486ec54a57SEdward Tomasz Napierala errx(1, "only one flag or argument may be specified " 5496ec54a57SEdward Tomasz Napierala "at the same time"); 5506ec54a57SEdward Tomasz Napierala 5516ec54a57SEdward Tomasz Napierala rule = resolve_ids(rule); 5526ec54a57SEdward Tomasz Napierala rule = expand_amount(rule); 5536ec54a57SEdward Tomasz Napierala 5546ec54a57SEdward Tomasz Napierala if (aflag) { 5556ec54a57SEdward Tomasz Napierala add_rule(rule); 5566ec54a57SEdward Tomasz Napierala return (0); 5576ec54a57SEdward Tomasz Napierala } 5586ec54a57SEdward Tomasz Napierala 5596ec54a57SEdward Tomasz Napierala if (lflag) { 5606ec54a57SEdward Tomasz Napierala show_limits(rule, hflag, nflag); 5616ec54a57SEdward Tomasz Napierala return (0); 5626ec54a57SEdward Tomasz Napierala } 5636ec54a57SEdward Tomasz Napierala 5646ec54a57SEdward Tomasz Napierala if (rflag) { 5656ec54a57SEdward Tomasz Napierala remove_rule(rule); 5666ec54a57SEdward Tomasz Napierala return (0); 5676ec54a57SEdward Tomasz Napierala } 5686ec54a57SEdward Tomasz Napierala 5696ec54a57SEdward Tomasz Napierala if (uflag) { 5706ec54a57SEdward Tomasz Napierala show_usage(rule, hflag); 5716ec54a57SEdward Tomasz Napierala return (0); 5726ec54a57SEdward Tomasz Napierala } 5736ec54a57SEdward Tomasz Napierala 5746ec54a57SEdward Tomasz Napierala show_rules(rule, hflag, nflag); 5756ec54a57SEdward Tomasz Napierala return (0); 5766ec54a57SEdward Tomasz Napierala } 577