Merge commit 'db1c88f6dab43484b6c33636600ac4596ff4c354'
[unleashed.git] / bin / ksh / c_ulimit.c
blobd2956430be7c0cd7e5ab5f61f1439807d7902f61
1 /* $OpenBSD: c_ulimit.c,v 1.28 2018/04/09 17:53:36 tobias Exp $ */
3 /*
4 ulimit -- handle "ulimit" builtin
6 Reworked to use getrusage() and ulimit() at once (as needed on
7 some schizophrenic systems, eg, HP-UX 9.01), made argument parsing
8 conform to at&t ksh, added autoconf support. Michael Rendell, May, '94
10 Eric Gisin, September 1988
11 Adapted to PD KornShell. Removed AT&T code.
13 last edit: 06-Jun-1987 D A Gwyn
15 This started out as the BRL UNIX System V system call emulation
16 for 4.nBSD, and was later extended by Doug Kingston to handle
17 the extended 4.nBSD resource limits. It now includes the code
18 that was originally under case SYSULIMIT in source file "xec.c".
21 #include <sys/resource.h>
23 #include <ctype.h>
24 #include <errno.h>
25 #include <inttypes.h>
26 #include <string.h>
28 #include "sh.h"
30 #define SOFT 0x1
31 #define HARD 0x2
33 struct limits {
34 const char *name;
35 int resource; /* resource to get/set */
36 int factor; /* multiply by to get rlim_{cur,max} values */
37 char option; /* option character (-d, -f, ...) */
40 static void print_ulimit(const struct limits *, int);
41 static int set_ulimit(const struct limits *, const char *, int);
43 int
44 c_ulimit(char **wp)
46 static const struct limits limits[] = {
47 /* Do not use options -H, -S or -a or change the order. */
48 { "time(cpu-seconds)", RLIMIT_CPU, 1, 't' },
49 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
50 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
51 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
52 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
53 #ifdef RLIMIT_MEMLOCK
54 { "lockedmem(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
55 #endif
56 #ifdef RLIMIT_RSS
57 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
58 #endif
59 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
60 #ifdef RLIMIT_NPROC
61 { "processes", RLIMIT_NPROC, 1, 'p' },
62 #endif
63 { NULL }
65 const char *options = "HSat#f#c#d#s#l#m#n#p#";
66 int how = SOFT | HARD;
67 const struct limits *l;
68 int optc, all = 0;
70 /* First check for -a, -H and -S. */
71 while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
72 switch (optc) {
73 case 'H':
74 how = HARD;
75 break;
76 case 'S':
77 how = SOFT;
78 break;
79 case 'a':
80 all = 1;
81 break;
82 case '?':
83 return 1;
84 default:
85 break;
88 if (wp[builtin_opt.optind] != NULL) {
89 bi_errorf("usage: ulimit [-acdfHlmnpSst] [value]");
90 return 1;
93 /* Then parse and act on the actual limits, one at a time */
94 ksh_getopt_reset(&builtin_opt, GF_ERROR);
95 while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
96 switch (optc) {
97 case 'a':
98 case 'H':
99 case 'S':
100 break;
101 case '?':
102 return 1;
103 default:
104 for (l = limits; l->name && l->option != optc; l++)
106 if (!l->name) {
107 internal_warningf("%s: %c", __func__, optc);
108 return 1;
110 if (builtin_opt.optarg) {
111 if (set_ulimit(l, builtin_opt.optarg, how))
112 return 1;
113 } else
114 print_ulimit(l, how);
115 break;
118 wp += builtin_opt.optind;
120 if (all) {
121 for (l = limits; l->name; l++) {
122 shprintf("%-20s ", l->name);
123 print_ulimit(l, how);
125 } else if (builtin_opt.optind == 1) {
126 /* No limit specified, use file size */
127 l = &limits[1];
128 if (wp[0] != NULL) {
129 if (set_ulimit(l, wp[0], how))
130 return 1;
131 wp++;
132 } else {
133 print_ulimit(l, how);
137 return 0;
140 static int
141 set_ulimit(const struct limits *l, const char *v, int how)
143 rlim_t val = 0;
144 struct rlimit limit;
146 if (strcmp(v, "unlimited") == 0)
147 val = RLIM_INFINITY;
148 else {
149 int64_t rval;
151 if (!evaluate(v, &rval, KSH_RETURN_ERROR, false))
152 return 1;
154 * Avoid problems caused by typos that evaluate misses due
155 * to evaluating unset parameters to 0...
156 * If this causes problems, will have to add parameter to
157 * evaluate() to control if unset params are 0 or an error.
159 if (!rval && !digit(v[0])) {
160 bi_errorf("invalid limit: %s", v);
161 return 1;
163 val = (rlim_t)rval * l->factor;
166 getrlimit(l->resource, &limit);
167 if (how & SOFT)
168 limit.rlim_cur = val;
169 if (how & HARD)
170 limit.rlim_max = val;
171 if (setrlimit(l->resource, &limit) < 0) {
172 if (errno == EPERM)
173 bi_errorf("-%c exceeds allowable limit", l->option);
174 else
175 bi_errorf("bad -%c limit: %s", l->option,
176 strerror(errno));
177 return 1;
179 return 0;
182 static void
183 print_ulimit(const struct limits *l, int how)
185 rlim_t val = 0;
186 struct rlimit limit;
188 getrlimit(l->resource, &limit);
189 if (how & SOFT)
190 val = limit.rlim_cur;
191 else if (how & HARD)
192 val = limit.rlim_max;
193 if (val == RLIM_INFINITY)
194 shprintf("unlimited\n");
195 else {
196 val /= l->factor;
197 shprintf("%" PRIi64 "\n", (int64_t) val);