sync
[bitrig.git] / bin / ksh / c_ulimit.c
blobbf580772a9cd38a5643ef6627b9b978ef5e74221
1 /* $OpenBSD: c_ulimit.c,v 1.17 2008/03/21 12:51:19 millert 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 "sh.h"
22 #include <sys/resource.h>
24 #define SOFT 0x1
25 #define HARD 0x2
27 struct limits {
28 const char *name;
29 int resource; /* resource to get/set */
30 int factor; /* multiply by to get rlim_{cur,max} values */
31 char option; /* option character (-d, -f, ...) */
34 static void print_ulimit(const struct limits *, int);
35 static int set_ulimit(const struct limits *, const char *, int);
37 int
38 c_ulimit(char **wp)
40 static const struct limits limits[] = {
41 /* Do not use options -H, -S or -a or change the order. */
42 { "time(cpu-seconds)", RLIMIT_CPU, 1, 't' },
43 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
44 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
45 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
46 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
47 { "lockedmem(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
48 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
49 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
50 { "processes", RLIMIT_NPROC, 1, 'p' },
51 #ifdef RLIMIT_VMEM
52 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
53 #endif /* RLIMIT_VMEM */
54 { (char *) 0 }
56 static char options[4 + NELEM(limits) * 2];
57 int how = SOFT | HARD;
58 const struct limits *l;
59 int optc, all = 0;
61 if (!options[0]) {
62 /* build options string on first call - yuck */
63 char *p = options;
65 *p++ = 'H'; *p++ = 'S'; *p++ = 'a';
66 for (l = limits; l->name; l++) {
67 *p++ = l->option;
68 *p++ = '#';
70 *p = '\0';
72 /* First check for -a, -H and -S. */
73 while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
74 switch (optc) {
75 case 'H':
76 how = HARD;
77 break;
78 case 'S':
79 how = SOFT;
80 break;
81 case 'a':
82 all = 1;
83 break;
84 case '?':
85 return 1;
86 default:
87 break;
90 if (wp[builtin_opt.optind] != NULL) {
91 bi_errorf("usage: ulimit [-acdfHlmnpSst] [value]");
92 return 1;
95 /* Then parse and act on the actual limits, one at a time */
96 ksh_getopt_reset(&builtin_opt, GF_ERROR);
97 while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
98 switch (optc) {
99 case 'a':
100 case 'H':
101 case 'S':
102 break;
103 case '?':
104 return 1;
105 default:
106 for (l = limits; l->name && l->option != optc; l++)
108 if (!l->name) {
109 internal_errorf(0, "ulimit: %c", optc);
110 return 1;
112 if (builtin_opt.optarg) {
113 if (set_ulimit(l, builtin_opt.optarg, how))
114 return 1;
115 } else
116 print_ulimit(l, how);
117 break;
120 wp += builtin_opt.optind;
122 if (all) {
123 for (l = limits; l->name; l++) {
124 shprintf("%-20s ", l->name);
125 print_ulimit(l, how);
127 } else if (builtin_opt.optind == 1) {
128 /* No limit specified, use file size */
129 l = &limits[1];
130 if (wp[0] != NULL) {
131 if (set_ulimit(l, wp[0], how))
132 return 1;
133 wp++;
134 } else {
135 print_ulimit(l, how);
139 return 0;
142 static int
143 set_ulimit(const struct limits *l, const char *v, int how)
145 rlim_t val = 0;
146 struct rlimit limit;
148 if (strcmp(v, "unlimited") == 0)
149 val = RLIM_INFINITY;
150 else {
151 long rval;
153 if (!evaluate(v, &rval, KSH_RETURN_ERROR, false))
154 return 1;
156 * Avoid problems caused by typos that evaluate misses due
157 * to evaluating unset parameters to 0...
158 * If this causes problems, will have to add parameter to
159 * evaluate() to control if unset params are 0 or an error.
161 if (!rval && !digit(v[0])) {
162 bi_errorf("invalid limit: %s", v);
163 return 1;
165 val = (rlim_t)rval * l->factor;
168 getrlimit(l->resource, &limit);
169 if (how & SOFT)
170 limit.rlim_cur = val;
171 if (how & HARD)
172 limit.rlim_max = val;
173 if (setrlimit(l->resource, &limit) < 0) {
174 if (errno == EPERM)
175 bi_errorf("exceeds allowable limit");
176 else
177 bi_errorf("bad limit: %s", strerror(errno));
178 return 1;
180 return 0;
183 static void
184 print_ulimit(const struct limits *l, int how)
186 rlim_t val = 0;
187 struct rlimit limit;
189 getrlimit(l->resource, &limit);
190 if (how & SOFT)
191 val = limit.rlim_cur;
192 else if (how & HARD)
193 val = limit.rlim_max;
194 if (val == RLIM_INFINITY)
195 shprintf("unlimited\n");
196 else {
197 val /= l->factor;
198 shprintf("%ld\n", (long) val);