limits.c revision 182685
156164Sru/*- 2146520Sru * Copyright (c) 1997 by 321495Sjmacd * David L. Nugent <davidn@blaze.net.au> 4116530Sru * All rights reserved. 5146520Sru * 621495Sjmacd * Redistribution and use in source and binary forms, with or without 721495Sjmacd * modification, is permitted provided that the following conditions 821495Sjmacd * are met: 921495Sjmacd * 1. Redistributions of source code must retain the above copyright 1021495Sjmacd * notice immediately at the beginning of the file, without modification, 1121495Sjmacd * this list of conditions, and the following disclaimer. 1221495Sjmacd * 2. Redistributions in binary form must reproduce the above copyright 1321495Sjmacd * notice, this list of conditions and the following disclaimer in the 1421495Sjmacd * documentation and/or other materials provided with the distribution. 1521495Sjmacd * 3. This work was done expressly for inclusion into FreeBSD. Other use 1621495Sjmacd * is permitted provided this notation is included. 1721495Sjmacd * 4. Absolutely no warranty of function or purpose is made by the authors. 1821495Sjmacd * 5. Modifications may be freely made to this file providing the above 1921495Sjmacd * conditions are met. 2021495Sjmacd * 21146520Sru * Display/change(+runprogram)/eval resource limits. 2221495Sjmacd */ 2342664Smarkm 2442664Smarkm#include <sys/cdefs.h> 2542664Smarkm__FBSDID("$FreeBSD: head/usr.bin/limits/limits.c 182685 2008-09-02 19:13:24Z ed $"); 2656164Sru 2756164Sru#include <err.h> 2856164Sru#include <stdio.h> 2956164Sru#include <string.h> 30146520Sru#include <sys/types.h> 3156164Sru#include <sys/stat.h> 3256164Sru#include <sys/param.h> 3356164Sru#include <stdlib.h> 3456164Sru#include <unistd.h> 35116530Sru#include <stdarg.h> 3656164Sru#include <stdint.h> 3756164Sru#include <ctype.h> 38146520Sru#include <errno.h> 3956164Sru#include <pwd.h> 4093142Sru#include <login_cap.h> 4142664Smarkm#include <sys/time.h> 4242664Smarkm#include <sys/resource.h> 4321495Sjmacd 4421495Sjmacdenum 4521495Sjmacd{ 4621495Sjmacd SH_NONE, 4721495Sjmacd SH_SH, /* sh */ 4821495Sjmacd SH_CSH, /* csh */ 4921495Sjmacd SH_BASH, /* gnu bash */ 5021495Sjmacd SH_TCSH, /* tcsh */ 5121495Sjmacd SH_KSH, /* (pd)ksh */ 5221495Sjmacd SH_ZSH, /* zsh */ 5321495Sjmacd SH_RC, /* rc or es */ 5421495Sjmacd SH_NUMBER 5521495Sjmacd}; 5621495Sjmacd 5721495Sjmacd 5821495Sjmacd/* eval emitter for popular shells. 5921495Sjmacd * Why aren't there any standards here? Most shells support either 6021495Sjmacd * the csh 'limit' or sh 'ulimit' command, but each varies just 6121495Sjmacd * enough that they aren't very compatible from one to the other. 6221495Sjmacd */ 6321495Sjmacdstatic struct { 6456164Sru const char * name; /* Name of shell */ 6521495Sjmacd const char * inf; /* Name used for 'unlimited' resource */ 6621495Sjmacd const char * cmd; /* Intro text */ 6756164Sru const char * hard; /* Hard limit text */ 6821495Sjmacd const char * soft; /* Soft limit text */ 6921495Sjmacd const char * both; /* Hard+Soft limit text */ 7021495Sjmacd struct { 7156164Sru const char * pfx; 72100516Sru const char * sfx; 7321495Sjmacd int divisor; 7421495Sjmacd } lprm[RLIM_NLIMITS]; 7521495Sjmacd} shellparm[] = 7621495Sjmacd{ 7721495Sjmacd { "", "infinity", "Resource limits%s%s:\n", "-max", "-cur", "", 7821495Sjmacd { 7921495Sjmacd { " cputime%-4s %8s", " secs\n", 1 }, 8021495Sjmacd { " filesize%-4s %8s", " kB\n", 1024 }, 8121495Sjmacd { " datasize%-4s %8s", " kB\n", 1024 }, 8221495Sjmacd { " stacksize%-4s %8s", " kB\n", 1024 }, 8321495Sjmacd { " coredumpsize%-4s %8s", " kB\n", 1024 }, 8421495Sjmacd { " memoryuse%-4s %8s", " kB\n", 1024 }, 8521495Sjmacd { " memorylocked%-4s %8s", " kB\n", 1024 }, 8621495Sjmacd { " maxprocesses%-4s %8s", "\n", 1 }, 8721495Sjmacd { " openfiles%-4s %8s", "\n", 1 }, 8821495Sjmacd { " sbsize%-4s %8s", " bytes\n", 1 }, 8921495Sjmacd { " vmemoryuse%-4s %8s", " kB\n", 1024 }, 9021495Sjmacd { " pseudo-terminals%-4s %8s", "\n", 1 } 9121495Sjmacd } 9221495Sjmacd }, 9321495Sjmacd { "sh", "unlimited", "", " -H", " -S", "", 9421495Sjmacd { 9521495Sjmacd { "ulimit%s -t %s", ";\n", 1 }, 9621495Sjmacd { "ulimit%s -f %s", ";\n", 512 }, 9721495Sjmacd { "ulimit%s -d %s", ";\n", 1024 }, 9821495Sjmacd { "ulimit%s -s %s", ";\n", 1024 }, 9942664Smarkm { "ulimit%s -c %s", ";\n", 512 }, 10021495Sjmacd { "ulimit%s -m %s", ";\n", 1024 }, 10142664Smarkm { "ulimit%s -l %s", ";\n", 1024 }, 10242664Smarkm { "ulimit%s -u %s", ";\n", 1 }, 10342664Smarkm { "ulimit%s -n %s", ";\n", 1 }, 10442664Smarkm { "ulimit%s -b %s", ";\n", 1 }, 10542664Smarkm { "ulimit%s -v %s", ";\n", 1024 }, 10642664Smarkm { "ulimit%s -p %s", ";\n", 1 } 10721495Sjmacd } 10821495Sjmacd }, 10942664Smarkm { "csh", "unlimited", "", " -h", "", NULL, 11042664Smarkm { 11142664Smarkm { "limit%s cputime %s", ";\n", 1 }, 11221495Sjmacd { "limit%s filesize %s", ";\n", 1024 }, 11321495Sjmacd { "limit%s datasize %s", ";\n", 1024 }, 11421495Sjmacd { "limit%s stacksize %s", ";\n", 1024 }, 11521495Sjmacd { "limit%s coredumpsize %s", ";\n", 1024 }, 11621495Sjmacd { "limit%s memoryuse %s", ";\n", 1024 }, 11721495Sjmacd { "limit%s memorylocked %s", ";\n", 1024 }, 11856164Sru { "limit%s maxproc %s", ";\n", 1 }, 11956164Sru { "limit%s openfiles %s", ";\n", 1 }, 12056164Sru { "limit%s sbsize %s", ";\n", 1 }, 12121495Sjmacd { "limit%s vmemoryuse %s", ";\n", 1024 }, 12256164Sru { "limit%s pseudoterminals %s", ";\n", 1 } 12356164Sru } 12456164Sru }, 12521495Sjmacd { "bash|bash2", "unlimited", "", " -H", " -S", "", 12656164Sru { 12756164Sru { "ulimit%s -t %s", ";\n", 1 }, 12856164Sru { "ulimit%s -f %s", ";\n", 1024 }, 12921495Sjmacd { "ulimit%s -d %s", ";\n", 1024 }, 13056164Sru { "ulimit%s -s %s", ";\n", 1024 }, 13156164Sru { "ulimit%s -c %s", ";\n", 1024 }, 13221495Sjmacd { "ulimit%s -m %s", ";\n", 1024 }, 13393142Sru { "ulimit%s -l %s", ";\n", 1024 }, 13493142Sru { "ulimit%s -u %s", ";\n", 1 }, 13593142Sru { "ulimit%s -n %s", ";\n", 1 }, 136146520Sru { "ulimit%s -b %s", ";\n", 1 }, 137146520Sru { "ulimit%s -v %s", ";\n", 1024 }, 138146520Sru { "ulimit%s -p %s", ";\n", 1 } 139146520Sru } 140114477Sru }, 141114477Sru { "tcsh", "unlimited", "", " -h", "", NULL, 142114477Sru { 143146520Sru { "limit%s cputime %s", ";\n", 1 }, 144146520Sru { "limit%s filesize %s", ";\n", 1024 }, 145146520Sru { "limit%s datasize %s", ";\n", 1024 }, 14621495Sjmacd { "limit%s stacksize %s", ";\n", 1024 }, 14721495Sjmacd { "limit%s coredumpsize %s", ";\n", 1024 }, 14821495Sjmacd { "limit%s memoryuse %s", ";\n", 1024 }, 14921495Sjmacd { "limit%s memorylocked %s", ";\n", 1024 }, 15056164Sru { "limit%s maxproc %s", ";\n", 1 }, 15121495Sjmacd { "limit%s descriptors %s", ";\n", 1 }, 15221495Sjmacd { "limit%s sbsize %s", ";\n", 1 }, 15321495Sjmacd { "limit%s vmemoryuse %s", ";\n", 1024 }, 15421495Sjmacd { "limit%s pseudoterminals %s", ";\n", 1 } 15556164Sru } 15621495Sjmacd }, 157146520Sru { "ksh|pdksh", "unlimited", "", " -H", " -S", "", 158146520Sru { 159146520Sru { "ulimit%s -t %s", ";\n", 1 }, 160146520Sru { "ulimit%s -f %s", ";\n", 512 }, 161146520Sru { "ulimit%s -d %s", ";\n", 1024 }, 162146520Sru { "ulimit%s -s %s", ";\n", 1024 }, 163146520Sru { "ulimit%s -c %s", ";\n", 512 }, 164146520Sru { "ulimit%s -m %s", ";\n", 1024 }, 165146520Sru { "ulimit%s -l %s", ";\n", 1024 }, 166146520Sru { "ulimit%s -p %s", ";\n", 1 }, 167146520Sru { "ulimit%s -n %s", ";\n", 1 }, 16821495Sjmacd { "ulimit%s -b %s", ";\n", 1 }, 169146520Sru { "ulimit%s -v %s", ";\n", 1024 }, 17021495Sjmacd { "ulimit%s -p %s", ";\n", 1 } 17156164Sru } 17221495Sjmacd }, 17342664Smarkm { "zsh", "unlimited", "", " -H", " -S", "", 17442664Smarkm { 17542664Smarkm { "ulimit%s -t %s", ";\n", 1 }, 176146520Sru { "ulimit%s -f %s", ";\n", 512 }, 177146520Sru { "ulimit%s -d %s", ";\n", 1024 }, 178146520Sru { "ulimit%s -s %s", ";\n", 1024 }, 179146520Sru { "ulimit%s -c %s", ";\n", 512 }, 180146520Sru { "ulimit%s -m %s", ";\n", 1024 }, 181146520Sru { "ulimit%s -l %s", ";\n", 1024 }, 182146520Sru { "ulimit%s -u %s", ";\n", 1 }, 183146520Sru { "ulimit%s -n %s", ";\n", 1 }, 184146520Sru { "ulimit%s -b %s", ";\n", 1 }, 185146520Sru { "ulimit%s -v %s", ";\n", 1024 }, 186146520Sru { "ulimit%s -p %s", ";\n", 1 } 187146520Sru } 188146520Sru }, 189146520Sru { "rc|es", "unlimited", "", " -h", "", NULL, 190146520Sru { 191146520Sru { "limit%s cputime %s", ";\n", 1 }, 19242664Smarkm { "limit%s filesize %s", ";\n", 1024 }, 19342664Smarkm { "limit%s datasize %s", ";\n", 1024 }, 194146520Sru { "limit%s stacksize %s", ";\n", 1024 }, 19542664Smarkm { "limit%s coredumpsize %s", ";\n", 1024 }, 19642664Smarkm { "limit%s memoryuse %s", ";\n", 1024 }, 19742664Smarkm { "limit%s lockedmemory %s", ";\n", 1024 }, 19856164Sru { "limit%s processes %s", ";\n", 1 }, 19942664Smarkm { "limit%s descriptors %s", ";\n", 1 }, 20042664Smarkm { "limit%s sbsize %s", ";\n", 1 }, 20142664Smarkm { "limit%s vmemoryuse %s", ";\n", 1024 }, 20242664Smarkm { "limit%s pseudoterminals %s", ";\n", 1 } 20342664Smarkm } 204116530Sru }, 20542664Smarkm { NULL, NULL, NULL, NULL, NULL, NULL, 20642664Smarkm { } 207116530Sru } 20842664Smarkm}; 20942664Smarkm 21042664Smarkmstatic struct { 21142664Smarkm const char * cap; 21242664Smarkm rlim_t (*func)(login_cap_t *, const char *, rlim_t, rlim_t); 21342664Smarkm} resources[RLIM_NLIMITS] = { 21442664Smarkm { "cputime", login_getcaptime }, 21542664Smarkm { "filesize", login_getcapsize }, 21642664Smarkm { "datasize", login_getcapsize }, 21742664Smarkm { "stacksize", login_getcapsize }, 21842664Smarkm { "coredumpsize", login_getcapsize }, 21942664Smarkm { "memoryuse", login_getcapsize }, 22042664Smarkm { "memorylocked", login_getcapsize }, 22142664Smarkm { "maxproc", login_getcapnum }, 22242664Smarkm { "openfiles", login_getcapnum }, 22342664Smarkm { "sbsize", login_getcapsize }, 22442664Smarkm { "vmemoryuse", login_getcapsize }, 22542664Smarkm { "pseudoterminals",login_getcapnum }, 22642664Smarkm}; 22742664Smarkm 22893142Sru/* 22942664Smarkm * One letter for each resource levels. 23042664Smarkm * NOTE: There is a dependancy on the corresponding 231116530Sru * letter index being equal to the resource number. 23293142Sru * If sys/resource.h defines are changed, this needs 23393142Sru * to be modified accordingly! 23493142Sru */ 23593142Sru 236116530Sru#define RCS_STRING "tfdscmlunbvp" 23793142Sru 23893142Srustatic rlim_t resource_num(int which, int ch, const char *str); 23993142Srustatic void usage(void); 24093142Srustatic int getshelltype(void); 24193142Srustatic void print_limit(rlim_t limit, unsigned divisor, const char *inf, 24293142Sru const char *pfx, const char *sfx, const char *which); 24393142Sruextern char **environ; 24493142Sru 24593142Srustatic const char rcs_string[] = RCS_STRING; 24693142Sru 24793142Sruint 24893142Srumain(int argc, char *argv[]) 24993142Sru{ 25093142Sru char *p, *cls = NULL; 25193142Sru char *cleanenv[1]; 25293142Sru struct passwd * pwd = NULL; 25393142Sru int rcswhich, shelltype; 25493142Sru int i, num_limits = 0; 25593142Sru int ch, doeval = 0, doall = 0; 25693142Sru int rtrn; 25793142Sru login_cap_t * lc = NULL; 25893142Sru enum { ANY=0, SOFT=1, HARD=2, BOTH=3, DISPLAYONLY=4 } type = ANY; 25993142Sru enum { RCSUNKNOWN=0, RCSSET=1, RCSSEL=2 } todo = RCSUNKNOWN; 26093142Sru int which_limits[RLIM_NLIMITS]; 26193142Sru rlim_t set_limits[RLIM_NLIMITS]; 262116530Sru struct rlimit limits[RLIM_NLIMITS]; 26342664Smarkm 26442664Smarkm /* init resource tables */ 265116530Sru for (i = 0; i < RLIM_NLIMITS; i++) { 26642664Smarkm which_limits[i] = 0; /* Don't set/display any */ 26742664Smarkm set_limits[i] = RLIM_INFINITY; 26842664Smarkm /* Get current resource values */ 26942664Smarkm getrlimit(i, &limits[i]); 27042664Smarkm } 27142664Smarkm 27242664Smarkm optarg = NULL; 27342664Smarkm while ((ch = getopt(argc, argv, ":EeC:U:BSHab:c:d:f:l:m:n:s:t:u:v:p:")) != -1) { 27442664Smarkm switch(ch) { 27542664Smarkm case 'a': 27642664Smarkm doall = 1; 27742664Smarkm break; 27842664Smarkm case 'E': 27942664Smarkm environ = cleanenv; 28042664Smarkm cleanenv[0] = NULL; 28142664Smarkm break; 28242664Smarkm case 'e': 28342664Smarkm doeval = 1; 28442664Smarkm break; 28542664Smarkm case 'C': 28642664Smarkm cls = optarg; 28742664Smarkm break; 28842664Smarkm case 'U': 289116530Sru if ((pwd = getpwnam(optarg)) == NULL) { 29042664Smarkm if (!isdigit(*optarg) || 29142664Smarkm (pwd = getpwuid(atoi(optarg))) == NULL) { 292116530Sru warnx("invalid user `%s'", optarg); 29342664Smarkm usage(); 29442664Smarkm } 29542664Smarkm } 29642664Smarkm break; 29742664Smarkm case 'H': 29842664Smarkm type = HARD; 29942664Smarkm break; 30042664Smarkm case 'S': 30142664Smarkm type = SOFT; 30242664Smarkm break; 30342664Smarkm case 'B': 30442664Smarkm type = SOFT|HARD; 30542664Smarkm break; 30642664Smarkm default: 30742664Smarkm case ':': /* Without arg */ 30842664Smarkm if ((p = strchr(rcs_string, optopt)) != NULL) { 30942664Smarkm int rcswhich1 = p - rcs_string; 31042664Smarkm if (optarg && *optarg == '-') { /* 'arg' is actually a switch */ 31142664Smarkm --optind; /* back one arg, and make arg NULL */ 31242664Smarkm optarg = NULL; 31342664Smarkm } 31442664Smarkm todo = optarg == NULL ? RCSSEL : RCSSET; 31542664Smarkm if (type == ANY) 31642664Smarkm type = BOTH; 31756164Sru which_limits[rcswhich1] = optarg ? type : DISPLAYONLY; 318146520Sru set_limits[rcswhich1] = resource_num(rcswhich1, optopt, optarg); 319146520Sru num_limits++; 32056164Sru break; 32156164Sru } 32256164Sru /* FALLTHRU */ 32342664Smarkm case '?': 32456164Sru usage(); 32521495Sjmacd } 32656164Sru optarg = NULL; 32756164Sru } 328146520Sru 32956164Sru /* If user was specified, get class from that */ 33056164Sru if (pwd != NULL) 33156164Sru lc = login_getpwclass(pwd); 33256164Sru else if (cls != NULL && *cls != '\0') { 33356164Sru lc = login_getclassbyname(cls, NULL); 33456164Sru if (lc == NULL || strcmp(cls, lc->lc_class) != 0) 33556164Sru fprintf(stderr, "login class '%s' non-existent, using %s\n", 33656164Sru cls, lc?lc->lc_class:"current settings"); 337146520Sru } 33856164Sru 33956164Sru /* If we have a login class, update resource table from that */ 34056164Sru if (lc != NULL) { 34156164Sru for (rcswhich = 0; rcswhich < RLIM_NLIMITS; rcswhich++) { 34256164Sru char str[40]; 34393142Sru rlim_t val; 344116530Sru 345100516Sru /* current value overridden by resourcename or resourcename-cur */ 34693142Sru sprintf(str, "%s-cur", resources[rcswhich].cap); 34793142Sru val = resources[rcswhich].func(lc, resources[rcswhich].cap, limits[rcswhich].rlim_cur, limits[rcswhich].rlim_cur); 34893142Sru limits[rcswhich].rlim_cur = resources[rcswhich].func(lc, str, val, val); 34993142Sru /* maximum value overridden by resourcename or resourcename-max */ 35056164Sru sprintf(str, "%s-max", resources[rcswhich].cap); 35193142Sru val = resources[rcswhich].func(lc, resources[rcswhich].cap, limits[rcswhich].rlim_max, limits[rcswhich].rlim_max); 35293142Sru limits[rcswhich].rlim_max = resources[rcswhich].func(lc, str, val, val); 35393142Sru } 35493142Sru } 35593142Sru 35693142Sru /* now, let's determine what we wish to do with all this */ 35793142Sru 35893142Sru argv += optind; 35993142Sru 36093142Sru /* If we're setting limits or doing an eval (ie. we're not just 361146520Sru * displaying), then check that hard limits are not lower than 36293142Sru * soft limits, and force rasing the hard limit if we need to if 36393142Sru * we are raising the soft limit, or lower the soft limit if we 364114477Sru * are lowering the hard limit. 36593142Sru */ 366146520Sru if ((*argv || doeval) && getuid() == 0) { 36793142Sru 368114477Sru for (rcswhich = 0; rcswhich < RLIM_NLIMITS; rcswhich++) { 369146520Sru if (limits[rcswhich].rlim_max != RLIM_INFINITY) { 37093142Sru if (limits[rcswhich].rlim_cur == RLIM_INFINITY) { 37193142Sru limits[rcswhich].rlim_max = RLIM_INFINITY; 372114477Sru which_limits[rcswhich] |= HARD; 37393142Sru } else if (limits[rcswhich].rlim_cur > limits[rcswhich].rlim_max) { 37493142Sru if (which_limits[rcswhich] == SOFT) { 37593142Sru limits[rcswhich].rlim_max = limits[rcswhich].rlim_cur; 376100516Sru which_limits[rcswhich] |= HARD; 377100516Sru } else if (which_limits[rcswhich] == HARD) { 378100516Sru limits[rcswhich].rlim_cur = limits[rcswhich].rlim_max; 379100516Sru which_limits[rcswhich] |= SOFT; 38093142Sru } else { 38193142Sru /* else.. if we're specifically setting both to 38293142Sru * silly values, then let it error out. 38393142Sru */ 38493142Sru } 38593142Sru } 386114477Sru } 38793142Sru } 38893142Sru } 38993142Sru 39093142Sru /* See if we've overridden anything specific on the command line */ 39193142Sru if (num_limits && todo == RCSSET) { 39293142Sru for (rcswhich = 0; rcswhich < RLIM_NLIMITS; rcswhich++) { 39393142Sru if (which_limits[rcswhich] & HARD) 39493142Sru limits[rcswhich].rlim_max = set_limits[rcswhich]; 39593142Sru if (which_limits[rcswhich] & SOFT) 39693142Sru limits[rcswhich].rlim_cur = set_limits[rcswhich]; 39793142Sru } 39893142Sru } 39993142Sru 40093142Sru /* If *argv is not NULL, then we are being asked to 401146520Sru * (perhaps) set environment variables and run a program 402114477Sru */ 403114477Sru if (*argv) { 404116530Sru if (doeval) { 405116530Sru warnx("-e cannot be used with `cmd' option"); 406116530Sru usage(); 407116530Sru } 408116530Sru 409146520Sru login_close(lc); 410146520Sru 411146520Sru /* set leading environment variables, like eval(1) */ 412146520Sru while (*argv && (p = strchr(*argv, '='))) { 413146520Sru *p = '\0'; 414146520Sru rtrn = setenv(*argv++, p + 1, 1); 415146520Sru *p = '='; 416116530Sru if (rtrn == -1) 41793142Sru err(EXIT_FAILURE, "setenv %s", *argv); 418116530Sru } 419116530Sru 420116530Sru /* Set limits */ 421116530Sru for (rcswhich = 0; rcswhich < RLIM_NLIMITS; rcswhich++) { 422116530Sru if (doall || num_limits == 0 || which_limits[rcswhich] != 0) 42393142Sru if (setrlimit(rcswhich, &limits[rcswhich]) == -1) 424100516Sru err(1, "setrlimit %s", resources[rcswhich].cap); 425114477Sru } 42693142Sru 427146520Sru if (*argv == NULL) 428146520Sru usage(); 429100516Sru 430100516Sru execvp(*argv, argv); 431100516Sru err(1, "%s", *argv); 432100516Sru } 433114477Sru 434146520Sru shelltype = doeval ? getshelltype() : SH_NONE; 435100516Sru 436100516Sru if (type == ANY) /* Default to soft limits */ 437100516Sru type = SOFT; 438100516Sru 439114477Sru /* Display limits */ 440146520Sru printf(shellparm[shelltype].cmd, 441146520Sru lc ? " for class " : " (current)", 44293142Sru lc ? lc->lc_class : ""); 44393142Sru 444114477Sru for (rcswhich = 0; rcswhich < RLIM_NLIMITS; rcswhich++) { 44593142Sru if (doall || num_limits == 0 || which_limits[rcswhich] != 0) { 44693142Sru if (which_limits[rcswhich] == ANY || which_limits[rcswhich]) 447100516Sru which_limits[rcswhich] = type; 448100516Sru if (shellparm[shelltype].lprm[rcswhich].pfx) { 449116530Sru if (shellparm[shelltype].both && limits[rcswhich].rlim_cur == limits[rcswhich].rlim_max) { 45093142Sru print_limit(limits[rcswhich].rlim_max, 45193142Sru shellparm[shelltype].lprm[rcswhich].divisor, 452114477Sru shellparm[shelltype].inf, 45356164Sru shellparm[shelltype].lprm[rcswhich].pfx, 45493142Sru shellparm[shelltype].lprm[rcswhich].sfx, 455100516Sru shellparm[shelltype].both); 456114477Sru } else { 457100516Sru if (which_limits[rcswhich] & HARD) { 458100516Sru print_limit(limits[rcswhich].rlim_max, 459100516Sru shellparm[shelltype].lprm[rcswhich].divisor, 460100516Sru shellparm[shelltype].inf, 46193142Sru shellparm[shelltype].lprm[rcswhich].pfx, 46293142Sru shellparm[shelltype].lprm[rcswhich].sfx, 463100516Sru shellparm[shelltype].hard); 46493142Sru } 465114477Sru if (which_limits[rcswhich] & SOFT) { 46656164Sru print_limit(limits[rcswhich].rlim_cur, 467100516Sru shellparm[shelltype].lprm[rcswhich].divisor, 468100516Sru shellparm[shelltype].inf, 469100516Sru shellparm[shelltype].lprm[rcswhich].pfx, 470114477Sru shellparm[shelltype].lprm[rcswhich].sfx, 471114477Sru shellparm[shelltype].soft); 47256164Sru } 47356164Sru } 47456164Sru } 47556164Sru } 47656164Sru } 47756164Sru 478116530Sru login_close(lc); 47993142Sru exit(EXIT_SUCCESS); 48093142Sru} 48156164Sru 48256164Sru 48356164Srustatic void 48456164Sruusage(void) 48556164Sru{ 48656164Sru (void)fprintf(stderr, 487146520Sru"usage: limits [-C class|-U user] [-eaSHBE] [-bcdflmnstuvp [val]] [[name=val ...] cmd]\n"); 48856164Sru exit(EXIT_FAILURE); 48956164Sru} 490100516Sru 49156164Srustatic void 492114477Sruprint_limit(rlim_t limit, unsigned divisor, const char * inf, const char * pfx, const char * sfx, const char * which) 49356164Sru{ 49456164Sru char numbr[64]; 495146520Sru 49656164Sru if (limit == RLIM_INFINITY) 49756164Sru strcpy(numbr, inf); 498100516Sru else 49956164Sru sprintf(numbr, "%jd", (intmax_t)((limit + divisor/2) / divisor)); 500114477Sru printf(pfx, which, numbr); 50156164Sru printf(sfx, which); 50256164Sru 50356164Sru} 50456164Sru 50556164Sru 50656164Srustatic rlim_t 50756164Sruresource_num(int which, int ch, const char *str) 50856164Sru{ 50956164Sru rlim_t res = RLIM_INFINITY; 510146520Sru 51156164Sru if (str != NULL && 512146520Sru !(strcasecmp(str, "inf") == 0 || 51356164Sru strcasecmp(str, "infinity") == 0 || 51493142Sru strcasecmp(str, "unlimit") == 0 || 51556164Sru strcasecmp(str, "unlimited") == 0)) { 51656164Sru const char * s = str; 51793142Sru char *e; 51856164Sru 51956164Sru switch (which) { 52056164Sru case RLIMIT_CPU: /* time values */ 521146520Sru errno = 0; 522146520Sru res = 0; 523146520Sru while (*s) { 524146520Sru rlim_t tim = strtoq(s, &e, 0); 525146520Sru if (e == NULL || e == s || errno) 526146520Sru break; 527146520Sru switch (*e++) { 528146520Sru case 0: /* end of string */ 529146520Sru e--; 530146520Sru default: 531146520Sru case 's': case 'S': /* seconds */ 532146520Sru break; 533146520Sru case 'm': case 'M': /* minutes */ 53421495Sjmacd tim *= 60L; 53521495Sjmacd break; 53621495Sjmacd case 'h': case 'H': /* hours */ 537146520Sru tim *= (60L * 60L); 53821495Sjmacd break; 53921495Sjmacd case 'd': case 'D': /* days */ 54021495Sjmacd tim *= (60L * 60L * 24L); 54121495Sjmacd break; 54242664Smarkm case 'w': case 'W': /* weeks */ 54342664Smarkm tim *= (60L * 60L * 24L * 7L); 54442664Smarkm case 'y': case 'Y': /* Years */ 54542664Smarkm tim *= (60L * 60L * 24L * 365L); 546146520Sru } 54742664Smarkm s = e; 548146520Sru res += tim; 54956164Sru } 55056164Sru break; 55142664Smarkm case RLIMIT_FSIZE: /* Size values */ 55242664Smarkm case RLIMIT_DATA: 553146520Sru case RLIMIT_STACK: 55442664Smarkm case RLIMIT_CORE: 55542664Smarkm case RLIMIT_RSS: 55642664Smarkm case RLIMIT_MEMLOCK: 557146520Sru case RLIMIT_SBSIZE: 55842664Smarkm case RLIMIT_VMEM: 559146520Sru errno = 0; 560146520Sru res = 0; 561146520Sru while (*s) { 562146520Sru rlim_t mult, tim = strtoq(s, &e, 0); 563146520Sru if (e == NULL || e == s || errno) 564146520Sru break; 565146520Sru switch (*e++) { 566146520Sru case 0: /* end of string */ 567146520Sru e--; 568146520Sru default: 569146520Sru mult = 1; 570146520Sru break; 571146520Sru case 'b': case 'B': /* 512-byte blocks */ 572146520Sru mult = 512; 573146520Sru break; 574146520Sru case 'k': case 'K': /* 1024-byte Kilobytes */ 575146520Sru mult = 1024; 576146520Sru break; 577146520Sru case 'm': case 'M': /* 1024-k kbytes */ 578146520Sru mult = 1024 * 1024; 579146520Sru break; 580146520Sru case 'g': case 'G': /* 1Gbyte */ 581146520Sru mult = 1024 * 1024 * 1024; 582146520Sru break; 583146520Sru case 't': case 'T': /* 1TBte */ 584146520Sru mult = 1024LL * 1024LL * 1024LL * 1024LL; 585146520Sru break; 586146520Sru } 587146520Sru s = e; 588146520Sru res += (tim * mult); 589146520Sru } 590146520Sru break; 591146520Sru case RLIMIT_NPROC: 592146520Sru case RLIMIT_NOFILE: 593146520Sru case RLIMIT_NPTS: 594146520Sru res = strtoq(s, &e, 0); 595146520Sru s = e; 596146520Sru break; 597146520Sru } 598146520Sru if (*s) { 599146520Sru warnx("invalid value -%c `%s'", ch, str); 600146520Sru usage(); 601146520Sru } 602146520Sru } 603146520Sru return res; 604146520Sru} 605146520Sru 606146520Sru 60721495Sjmacdstatic int 608146520Srugetshellbyname(const char * shell) 60942664Smarkm{ 61021495Sjmacd int i; 61121495Sjmacd const char * q; 61242664Smarkm const char * p = strrchr(shell, '/'); 61321495Sjmacd 61421495Sjmacd p = p ? p+1 : shell; 61542664Smarkm for (i = 0; (q = shellparm[i].name) != NULL; i++) { 616116530Sru while (*q) { 617116530Sru int j = strcspn(q, "|"); 618116530Sru 619116530Sru if (j == 0) 62042664Smarkm break; 62142664Smarkm if (strncmp(p, q, j) == 0) 62242664Smarkm return i; 623146520Sru if (*(q += j)) 624146520Sru ++q; 625146520Sru } 626146520Sru } 627146520Sru return SH_SH; 628146520Sru} 629146520Sru 630146520Sru 631146520Sru/* 632146520Sru * Determine the type of shell our parent process is 63342664Smarkm * This is quite tricky, not 100% reliable and probably 63421495Sjmacd * not nearly as thorough as it should be. Basically, this 63593142Sru * is a "best guess" only, but hopefully will work in 63693142Sru * most cases. 637114477Sru */ 638114477Sru 639146520Srustatic int 640146520Srugetshelltype(void) 64193142Sru{ 64293142Sru pid_t ppid = getppid(); 64356164Sru 64442664Smarkm if (ppid != 1) { 64542664Smarkm FILE * fp; 64642664Smarkm struct stat st; 64742664Smarkm char procdir[MAXPATHLEN], buf[128]; 648146520Sru int l = sprintf(procdir, "/proc/%ld/", (long)ppid); 64993142Sru char * shell = getenv("SHELL"); 65042664Smarkm 65142664Smarkm if (shell != NULL && stat(shell, &st) != -1) { 65221495Sjmacd struct stat st1; 65356164Sru 65442664Smarkm strcpy(procdir+l, "file"); 65542664Smarkm /* $SHELL is actual shell? */ 65642664Smarkm if (stat(procdir, &st1) != -1 && memcmp(&st, &st1, sizeof st) == 0) 65742664Smarkm return getshellbyname(shell); 65842664Smarkm } 65942664Smarkm strcpy(procdir+l, "status"); 660146520Sru if (stat(procdir, &st) == 0 && (fp = fopen(procdir, "r")) != NULL) { 661146520Sru char * p = fgets(buf, sizeof buf, fp)==NULL ? NULL : strtok(buf, " \t"); 66242664Smarkm fclose(fp); 66342664Smarkm if (p != NULL) 664146520Sru return getshellbyname(p); 665146520Sru } 666146520Sru } 66742664Smarkm return SH_SH; 66821495Sjmacd} 66956164Sru 67042664Smarkm