1 /* $OpenBSD: c_ulimit.c,v 1.29 2019/06/28 13:34:59 deraadt Exp $ */
2
3 /*
4 ulimit -- handle "ulimit" builtin
5
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
9
10 Eric Gisin, September 1988
11 Adapted to PD KornShell. Removed AT&T code.
12
13 last edit: 06-Jun-1987 D A Gwyn
14
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".
19 */
20
21 #include <sys/resource.h>
22
23 #include <ctype.h>
24 #include <errno.h>
25 #include <inttypes.h>
26 #include <string.h>
27
28 #include "sh.h"
29
30 #define SOFT 0x1
31 #define HARD 0x2
32
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, ...) */
38 };
39
40 static void print_ulimit(const struct limits *, int);
41 static int set_ulimit(const struct limits *, const char *, int);
42
43 int
c_ulimit(char ** wp)44 c_ulimit(char **wp)
45 {
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 { "lockedmem(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
54 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
55 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
56 { "processes", RLIMIT_NPROC, 1, 'p' },
57 { NULL }
58 };
59 const char *options = "HSat#f#c#d#s#l#m#n#p#";
60 int how = SOFT | HARD;
61 const struct limits *l;
62 int optc, all = 0;
63
64 /* First check for -a, -H and -S. */
65 while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
66 switch (optc) {
67 case 'H':
68 how = HARD;
69 break;
70 case 'S':
71 how = SOFT;
72 break;
73 case 'a':
74 all = 1;
75 break;
76 case '?':
77 return 1;
78 default:
79 break;
80 }
81
82 if (wp[builtin_opt.optind] != NULL) {
83 bi_errorf("usage: ulimit [-acdfHlmnpSst] [value]");
84 return 1;
85 }
86
87 /* Then parse and act on the actual limits, one at a time */
88 ksh_getopt_reset(&builtin_opt, GF_ERROR);
89 while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
90 switch (optc) {
91 case 'a':
92 case 'H':
93 case 'S':
94 break;
95 case '?':
96 return 1;
97 default:
98 for (l = limits; l->name && l->option != optc; l++)
99 ;
100 if (!l->name) {
101 internal_warningf("%s: %c", __func__, optc);
102 return 1;
103 }
104 if (builtin_opt.optarg) {
105 if (set_ulimit(l, builtin_opt.optarg, how))
106 return 1;
107 } else
108 print_ulimit(l, how);
109 break;
110 }
111
112 wp += builtin_opt.optind;
113
114 if (all) {
115 for (l = limits; l->name; l++) {
116 shprintf("%-20s ", l->name);
117 print_ulimit(l, how);
118 }
119 } else if (builtin_opt.optind == 1) {
120 /* No limit specified, use file size */
121 l = &limits[1];
122 if (wp[0] != NULL) {
123 if (set_ulimit(l, wp[0], how))
124 return 1;
125 wp++;
126 } else {
127 print_ulimit(l, how);
128 }
129 }
130
131 return 0;
132 }
133
134 static int
set_ulimit(const struct limits * l,const char * v,int how)135 set_ulimit(const struct limits *l, const char *v, int how)
136 {
137 rlim_t val = 0;
138 struct rlimit limit;
139
140 if (strcmp(v, "unlimited") == 0)
141 val = RLIM_INFINITY;
142 else {
143 int64_t rval;
144
145 if (!evaluate(v, &rval, KSH_RETURN_ERROR, false))
146 return 1;
147 /*
148 * Avoid problems caused by typos that evaluate misses due
149 * to evaluating unset parameters to 0...
150 * If this causes problems, will have to add parameter to
151 * evaluate() to control if unset params are 0 or an error.
152 */
153 if (!rval && !digit(v[0])) {
154 bi_errorf("invalid limit: %s", v);
155 return 1;
156 }
157 val = (rlim_t)rval * l->factor;
158 }
159
160 getrlimit(l->resource, &limit);
161 if (how & SOFT)
162 limit.rlim_cur = val;
163 if (how & HARD)
164 limit.rlim_max = val;
165 if (setrlimit(l->resource, &limit) == -1) {
166 if (errno == EPERM)
167 bi_errorf("-%c exceeds allowable limit", l->option);
168 else
169 bi_errorf("bad -%c limit: %s", l->option,
170 strerror(errno));
171 return 1;
172 }
173 return 0;
174 }
175
176 static void
print_ulimit(const struct limits * l,int how)177 print_ulimit(const struct limits *l, int how)
178 {
179 rlim_t val = 0;
180 struct rlimit limit;
181
182 getrlimit(l->resource, &limit);
183 if (how & SOFT)
184 val = limit.rlim_cur;
185 else if (how & HARD)
186 val = limit.rlim_max;
187 if (val == RLIM_INFINITY)
188 shprintf("unlimited\n");
189 else {
190 val /= l->factor;
191 shprintf("%" PRIi64 "\n", (int64_t) val);
192 }
193 }
194