blob: b57c627ef4257b83fcb97b9c1dc957ad2bd819c1 [file] [log] [blame]
Dan Pasanenc6e37862014-10-02 14:08:59 -05001/* ulimit.c, created from ulimit.def. */
2#line 22 "./ulimit.def"
3
4#line 70 "./ulimit.def"
5
6#if !defined (_MINIX)
7
8#include <config.h>
9
10#include "../bashtypes.h"
11#if defined (HAVE_SYS_PARAM_H)
12# include <sys/param.h>
13#endif
14
15#if defined (HAVE_UNISTD_H)
16# include <unistd.h>
17#endif
18
19#include <stdio.h>
20#include <errno.h>
21
22#include "../bashintl.h"
23
24#include "../shell.h"
25#include "common.h"
26#include "bashgetopt.h"
27#include "pipesize.h"
28
29#if !defined (errno)
Ricardo Cerqueiraa02fbff2013-07-25 22:35:34 +010030#include <errno.h>
Dan Pasanenc6e37862014-10-02 14:08:59 -050031#endif
32
33/* For some reason, HPUX chose to make these definitions visible only if
34 _KERNEL is defined, so we define _KERNEL before including <sys/resource.h>
35 and #undef it afterward. */
36#if defined (HAVE_RESOURCE)
37# include <sys/time.h>
38# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
39# define _KERNEL
40# endif
41# include <sys/resource.h>
42# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
43# undef _KERNEL
44# endif
45#elif defined (HAVE_SYS_TIMES_H)
46# include <sys/times.h>
47#endif
48
49#if defined (HAVE_LIMITS_H)
50# include <limits.h>
51#endif
52
53/* Check for the most basic symbols. If they aren't present, this
54 system's <sys/resource.h> isn't very useful to us. */
55#if !defined (RLIMIT_FSIZE) || !defined (HAVE_GETRLIMIT)
56# undef HAVE_RESOURCE
57#endif
58
59#if !defined (HAVE_RESOURCE) && defined (HAVE_ULIMIT_H)
60# include <ulimit.h>
61#endif
62
63#if !defined (RLIMTYPE)
64# define RLIMTYPE long
65# define string_to_rlimtype(s) strtol(s, (char **)NULL, 10)
66# define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "")
67#endif
68
69/* Some systems use RLIMIT_NOFILE, others use RLIMIT_OFILE */
70#if defined (HAVE_RESOURCE) && defined (RLIMIT_OFILE) && !defined (RLIMIT_NOFILE)
71# define RLIMIT_NOFILE RLIMIT_OFILE
72#endif /* HAVE_RESOURCE && RLIMIT_OFILE && !RLIMIT_NOFILE */
73
74/* Some systems have these, some do not. */
75#ifdef RLIMIT_FSIZE
76# define RLIMIT_FILESIZE RLIMIT_FSIZE
77#else
78# define RLIMIT_FILESIZE 256
79#endif
80
81#define RLIMIT_PIPESIZE 257
82
83#ifdef RLIMIT_NOFILE
84# define RLIMIT_OPENFILES RLIMIT_NOFILE
85#else
86# define RLIMIT_OPENFILES 258
87#endif
88
89#ifdef RLIMIT_VMEM
90# define RLIMIT_VIRTMEM RLIMIT_VMEM
91# define RLIMIT_VMBLKSZ 1024
92#else
93# ifdef RLIMIT_AS
94# define RLIMIT_VIRTMEM RLIMIT_AS
95# define RLIMIT_VMBLKSZ 1024
96# else
97# define RLIMIT_VIRTMEM 259
98# define RLIMIT_VMBLKSZ 1
99# endif
100#endif
101
102#ifdef RLIMIT_NPROC
103# define RLIMIT_MAXUPROC RLIMIT_NPROC
104#else
105# define RLIMIT_MAXUPROC 260
106#endif
107
108#if !defined (RLIMIT_PTHREAD) && defined (RLIMIT_NTHR)
109# define RLIMIT_PTHREAD RLIMIT_NTHR
110#endif
111
112#if !defined (RLIM_INFINITY)
113# define RLIM_INFINITY 0x7fffffff
114#endif
115
116#if !defined (RLIM_SAVED_CUR)
117# define RLIM_SAVED_CUR RLIM_INFINITY
118#endif
119
120#if !defined (RLIM_SAVED_MAX)
121# define RLIM_SAVED_MAX RLIM_INFINITY
122#endif
123
124#define LIMIT_HARD 0x01
125#define LIMIT_SOFT 0x02
126
127/* "Blocks" are defined as 512 bytes when in Posix mode and 1024 bytes
128 otherwise. */
129#define POSIXBLK -2
130
131#define BLOCKSIZE(x) (((x) == POSIXBLK) ? (posixly_correct ? 512 : 1024) : (x))
132
133extern int posixly_correct;
134
135static int _findlim __P((int));
136
137static int ulimit_internal __P((int, char *, int, int));
138
139static int get_limit __P((int, RLIMTYPE *, RLIMTYPE *));
140static int set_limit __P((int, RLIMTYPE, int));
141
142static void printone __P((int, RLIMTYPE, int));
143static void print_all_limits __P((int));
144
145static int set_all_limits __P((int, RLIMTYPE));
146
147static int filesize __P((RLIMTYPE *));
148static int pipesize __P((RLIMTYPE *));
149static int getmaxuprc __P((RLIMTYPE *));
150static int getmaxvm __P((RLIMTYPE *, RLIMTYPE *));
151
152typedef struct {
153 int option; /* The ulimit option for this limit. */
154 int parameter; /* Parameter to pass to get_limit (). */
155 int block_factor; /* Blocking factor for specific limit. */
156 const char * const description; /* Descriptive string to output. */
157 const char * const units; /* scale */
158} RESOURCE_LIMITS;
159
160static RESOURCE_LIMITS limits[] = {
161#ifdef RLIMIT_PTHREAD
162 { 'T', RLIMIT_PTHREAD, 1, "number of threads", (char *)NULL },
163#endif
164#ifdef RLIMIT_SBSIZE
165 { 'b', RLIMIT_SBSIZE, 1, "socket buffer size", "bytes" },
166#endif
167#ifdef RLIMIT_CORE
168 { 'c', RLIMIT_CORE, POSIXBLK, "core file size", "blocks" },
169#endif
170#ifdef RLIMIT_DATA
171 { 'd', RLIMIT_DATA, 1024, "data seg size", "kbytes" },
172#endif
173#ifdef RLIMIT_NICE
174 { 'e', RLIMIT_NICE, 1, "scheduling priority", (char *)NULL },
175#endif
176 { 'f', RLIMIT_FILESIZE, POSIXBLK, "file size", "blocks" },
177#ifdef RLIMIT_SIGPENDING
178 { 'i', RLIMIT_SIGPENDING, 1, "pending signals", (char *)NULL },
179#endif
180#ifdef RLIMIT_MEMLOCK
181 { 'l', RLIMIT_MEMLOCK, 1024, "max locked memory", "kbytes" },
182#endif
183#ifdef RLIMIT_RSS
184 { 'm', RLIMIT_RSS, 1024, "max memory size", "kbytes" },
185#endif /* RLIMIT_RSS */
186 { 'n', RLIMIT_OPENFILES, 1, "open files", (char *)NULL},
187 { 'p', RLIMIT_PIPESIZE, 512, "pipe size", "512 bytes" },
188#ifdef RLIMIT_MSGQUEUE
189 { 'q', RLIMIT_MSGQUEUE, 1, "POSIX message queues", "bytes" },
190#endif
191#ifdef RLIMIT_RTPRIO
192 { 'r', RLIMIT_RTPRIO, 1, "real-time priority", (char *)NULL },
193#endif
194#ifdef RLIMIT_STACK
195 { 's', RLIMIT_STACK, 1024, "stack size", "kbytes" },
196#endif
197#ifdef RLIMIT_CPU
198 { 't', RLIMIT_CPU, 1, "cpu time", "seconds" },
199#endif /* RLIMIT_CPU */
200 { 'u', RLIMIT_MAXUPROC, 1, "max user processes", (char *)NULL },
201#if defined (HAVE_RESOURCE)
202 { 'v', RLIMIT_VIRTMEM, RLIMIT_VMBLKSZ, "virtual memory", "kbytes" },
203#endif
204#ifdef RLIMIT_SWAP
205 { 'w', RLIMIT_SWAP, 1024, "swap size", "kbytes" },
206#endif
207#ifdef RLIMIT_LOCKS
208 { 'x', RLIMIT_LOCKS, 1, "file locks", (char *)NULL },
209#endif
210 { -1, -1, -1, (char *)NULL, (char *)NULL }
211};
212#define NCMDS (sizeof(limits) / sizeof(limits[0]))
213
214typedef struct _cmd {
215 int cmd;
216 char *arg;
217} ULCMD;
218
219static ULCMD *cmdlist;
220static int ncmd;
221static int cmdlistsz;
222
223#if !defined (HAVE_RESOURCE) && !defined (HAVE_ULIMIT)
224long
225ulimit (cmd, newlim)
226 int cmd;
227 long newlim;
228{
229 errno = EINVAL;
230 return -1;
231}
232#endif /* !HAVE_RESOURCE && !HAVE_ULIMIT */
233
234static int
235_findlim (opt)
236 int opt;
237{
238 register int i;
239
240 for (i = 0; limits[i].option > 0; i++)
241 if (limits[i].option == opt)
242 return i;
243 return -1;
244}
245
246static char optstring[4 + 2 * NCMDS];
247
248/* Report or set limits associated with certain per-process resources.
249 See the help documentation in builtins.c for a full description. */
250int
251ulimit_builtin (list)
252 register WORD_LIST *list;
253{
254 register char *s;
255 int c, limind, mode, opt, all_limits;
256
257 mode = 0;
258
259 all_limits = 0;
260
261 /* Idea stolen from pdksh -- build option string the first time called. */
262 if (optstring[0] == 0)
263 {
264 s = optstring;
265 *s++ = 'a'; *s++ = 'S'; *s++ = 'H';
266 for (c = 0; limits[c].option > 0; c++)
267 {
268 *s++ = limits[c].option;
269 *s++ = ';';
270 }
271 *s = '\0';
272 }
273
274 /* Initialize the command list. */
275 if (cmdlistsz == 0)
276 cmdlist = (ULCMD *)xmalloc ((cmdlistsz = 16) * sizeof (ULCMD));
277 ncmd = 0;
278
279 reset_internal_getopt ();
280 while ((opt = internal_getopt (list, optstring)) != -1)
281 {
282 switch (opt)
283 {
284 case 'a':
285 all_limits++;
286 break;
287
288 /* -S and -H are modifiers, not real options. */
289 case 'S':
290 mode |= LIMIT_SOFT;
291 break;
292
293 case 'H':
294 mode |= LIMIT_HARD;
295 break;
296
297 case '?':
298 builtin_usage ();
299 return (EX_USAGE);
300
301 default:
302 if (ncmd >= cmdlistsz)
303 cmdlist = (ULCMD *)xrealloc (cmdlist, (cmdlistsz *= 2) * sizeof (ULCMD));
304 cmdlist[ncmd].cmd = opt;
305 cmdlist[ncmd++].arg = list_optarg;
306 break;
307 }
308 }
309 list = loptend;
310
311 if (all_limits)
312 {
313#ifdef NOTYET
314 if (list) /* setting */
315 {
316 if (STREQ (list->word->word, "unlimited") == 0)
317 {
318 builtin_error (_("%s: invalid limit argument"), list->word->word);
319 return (EXECUTION_FAILURE);
320 }
321 return (set_all_limits (mode == 0 ? LIMIT_SOFT|LIMIT_HARD : mode, RLIM_INFINITY));
322 }
323#endif
324 print_all_limits (mode == 0 ? LIMIT_SOFT : mode);
325 return (sh_chkwrite (EXECUTION_SUCCESS));
326 }
327
328 /* default is `ulimit -f' */
329 if (ncmd == 0)
330 {
331 cmdlist[ncmd].cmd = 'f';
332 /* `ulimit something' is same as `ulimit -f something' */
333 cmdlist[ncmd++].arg = list ? list->word->word : (char *)NULL;
334 if (list)
335 list = list->next;
336 }
337
338 /* verify each command in the list. */
339 for (c = 0; c < ncmd; c++)
340 {
341 limind = _findlim (cmdlist[c].cmd);
342 if (limind == -1)
343 {
344 builtin_error (_("`%c': bad command"), cmdlist[c].cmd);
345 return (EX_USAGE);
346 }
347 }
348
349 for (c = 0; c < ncmd; c++)
350 if (ulimit_internal (cmdlist[c].cmd, cmdlist[c].arg, mode, ncmd > 1) == EXECUTION_FAILURE)
351 return (EXECUTION_FAILURE);
352
353 return (EXECUTION_SUCCESS);
354}
355
356static int
357ulimit_internal (cmd, cmdarg, mode, multiple)
358 int cmd;
359 char *cmdarg;
360 int mode, multiple;
361{
362 int opt, limind, setting;
363 int block_factor;
364 RLIMTYPE soft_limit, hard_limit, real_limit, limit;
365
366 setting = cmdarg != 0;
367 limind = _findlim (cmd);
368 if (mode == 0)
369 mode = setting ? (LIMIT_HARD|LIMIT_SOFT) : LIMIT_SOFT;
370 opt = get_limit (limind, &soft_limit, &hard_limit);
371 if (opt < 0)
372 {
373 builtin_error (_("%s: cannot get limit: %s"), limits[limind].description,
374 strerror (errno));
375 return (EXECUTION_FAILURE);
376 }
377
378 if (setting == 0) /* print the value of the specified limit */
379 {
380 printone (limind, (mode & LIMIT_SOFT) ? soft_limit : hard_limit, multiple);
381 return (EXECUTION_SUCCESS);
382 }
383
384 /* Setting the limit. */
385 if (STREQ (cmdarg, "hard"))
386 real_limit = hard_limit;
387 else if (STREQ (cmdarg, "soft"))
388 real_limit = soft_limit;
389 else if (STREQ (cmdarg, "unlimited"))
390 real_limit = RLIM_INFINITY;
391 else if (all_digits (cmdarg))
392 {
393 limit = string_to_rlimtype (cmdarg);
394 block_factor = BLOCKSIZE(limits[limind].block_factor);
395 real_limit = limit * block_factor;
396
397 if ((real_limit / block_factor) != limit)
398 {
399 sh_erange (cmdarg, _("limit"));
400 return (EXECUTION_FAILURE);
401 }
402 }
403 else
404 {
405 sh_invalidnum (cmdarg);
406 return (EXECUTION_FAILURE);
407 }
408
409 if (set_limit (limind, real_limit, mode) < 0)
410 {
411 builtin_error (_("%s: cannot modify limit: %s"), limits[limind].description,
412 strerror (errno));
413 return (EXECUTION_FAILURE);
414 }
415
416 return (EXECUTION_SUCCESS);
417}
418
419static int
420get_limit (ind, softlim, hardlim)
421 int ind;
422 RLIMTYPE *softlim, *hardlim;
423{
424 RLIMTYPE value;
425#if defined (HAVE_RESOURCE)
426 struct rlimit limit;
427#endif
428
429 if (limits[ind].parameter >= 256)
430 {
431 switch (limits[ind].parameter)
432 {
433 case RLIMIT_FILESIZE:
434 if (filesize (&value) < 0)
435 return -1;
436 break;
437 case RLIMIT_PIPESIZE:
438 if (pipesize (&value) < 0)
439 return -1;
440 break;
441 case RLIMIT_OPENFILES:
442 value = (RLIMTYPE)getdtablesize ();
443 break;
444 case RLIMIT_VIRTMEM:
445 return (getmaxvm (softlim, hardlim));
446 case RLIMIT_MAXUPROC:
447 if (getmaxuprc (&value) < 0)
448 return -1;
449 break;
450 default:
451 errno = EINVAL;
452 return -1;
453 }
454 *softlim = *hardlim = value;
455 return (0);
456 }
457 else
458 {
459#if defined (HAVE_RESOURCE)
460 if (getrlimit (limits[ind].parameter, &limit) < 0)
461 return -1;
462 *softlim = limit.rlim_cur;
463 *hardlim = limit.rlim_max;
464# if defined (HPUX9)
465 if (limits[ind].parameter == RLIMIT_FILESIZE)
466 {
467 *softlim *= 512;
468 *hardlim *= 512; /* Ugh. */
469 }
470 else
471# endif /* HPUX9 */
472 return 0;
473#else
474 errno = EINVAL;
475 return -1;
476#endif
477 }
478}
479
480static int
481set_limit (ind, newlim, mode)
482 int ind;
483 RLIMTYPE newlim;
484 int mode;
485{
486#if defined (HAVE_RESOURCE)
487 struct rlimit limit;
488 RLIMTYPE val;
489#endif
490
491 if (limits[ind].parameter >= 256)
492 switch (limits[ind].parameter)
493 {
494 case RLIMIT_FILESIZE:
495#if !defined (HAVE_RESOURCE)
496 return (ulimit (2, newlim / 512L));
497#else
498 errno = EINVAL;
499 return -1;
500#endif
501
502 case RLIMIT_OPENFILES:
503#if defined (HAVE_SETDTABLESIZE)
504# if defined (__CYGWIN__)
505 /* Grrr... Cygwin declares setdtablesize as void. */
506 setdtablesize (newlim);
507 return 0;
508# else
509 return (setdtablesize (newlim));
510# endif
511#endif
512 case RLIMIT_PIPESIZE:
513 case RLIMIT_VIRTMEM:
514 case RLIMIT_MAXUPROC:
515 default:
516 errno = EINVAL;
517 return -1;
518 }
519 else
520 {
521#if defined (HAVE_RESOURCE)
522 if (getrlimit (limits[ind].parameter, &limit) < 0)
523 return -1;
524# if defined (HPUX9)
525 if (limits[ind].parameter == RLIMIT_FILESIZE)
526 newlim /= 512; /* Ugh. */
527# endif /* HPUX9 */
528 val = (current_user.euid != 0 && newlim == RLIM_INFINITY &&
529 (mode & LIMIT_HARD) == 0 && /* XXX -- test */
530 (limit.rlim_cur <= limit.rlim_max))
531 ? limit.rlim_max : newlim;
532 if (mode & LIMIT_SOFT)
533 limit.rlim_cur = val;
534 if (mode & LIMIT_HARD)
535 limit.rlim_max = val;
536
537 return (setrlimit (limits[ind].parameter, &limit));
538#else
539 errno = EINVAL;
540 return -1;
541#endif
542 }
543}
544
545static int
546getmaxvm (softlim, hardlim)
547 RLIMTYPE *softlim, *hardlim;
548{
549#if defined (HAVE_RESOURCE)
550 struct rlimit datalim, stacklim;
551
552 if (getrlimit (RLIMIT_DATA, &datalim) < 0)
553 return -1;
554
555 if (getrlimit (RLIMIT_STACK, &stacklim) < 0)
556 return -1;
557
558 /* Protect against overflow. */
559 *softlim = (datalim.rlim_cur / 1024L) + (stacklim.rlim_cur / 1024L);
560 *hardlim = (datalim.rlim_max / 1024L) + (stacklim.rlim_max / 1024L);
561 return 0;
562#else
563 errno = EINVAL;
564 return -1;
565#endif /* HAVE_RESOURCE */
566}
567
568static int
569filesize(valuep)
570 RLIMTYPE *valuep;
571{
572#if !defined (HAVE_RESOURCE)
573 long result;
574 if ((result = ulimit (1, 0L)) < 0)
575 return -1;
576 else
577 *valuep = (RLIMTYPE) result * 512;
578 return 0;
579#else
580 errno = EINVAL;
581 return -1;
582#endif
583}
584
585static int
586pipesize (valuep)
587 RLIMTYPE *valuep;
588{
589#if defined (PIPE_BUF)
590 /* This is defined on Posix systems. */
591 *valuep = (RLIMTYPE) PIPE_BUF;
592 return 0;
593#else
594# if defined (_POSIX_PIPE_BUF)
595 *valuep = (RLIMTYPE) _POSIX_PIPE_BUF;
596 return 0;
597# else
598# if defined (PIPESIZE)
599 /* This is defined by running a program from the Makefile. */
600 *valuep = (RLIMTYPE) PIPESIZE;
601 return 0;
602# else
603 errno = EINVAL;
604 return -1;
605# endif /* PIPESIZE */
606# endif /* _POSIX_PIPE_BUF */
607#endif /* PIPE_BUF */
608}
609
610static int
611getmaxuprc (valuep)
612 RLIMTYPE *valuep;
613{
614 long maxchild;
615
616 maxchild = getmaxchild ();
617 if (maxchild < 0)
618 {
619 errno = EINVAL;
620 return -1;
621 }
622 else
623 {
624 *valuep = (RLIMTYPE) maxchild;
625 return 0;
626 }
627}
628
629static void
630print_all_limits (mode)
631 int mode;
632{
633 register int i;
634 RLIMTYPE softlim, hardlim;
635
636 if (mode == 0)
637 mode |= LIMIT_SOFT;
638
639 for (i = 0; limits[i].option > 0; i++)
640 {
641 if (get_limit (i, &softlim, &hardlim) == 0)
642 printone (i, (mode & LIMIT_SOFT) ? softlim : hardlim, 1);
643 else if (errno != EINVAL)
644 builtin_error ("%s: cannot get limit: %s", limits[i].description,
645 strerror (errno));
646 }
647}
648
649static void
650printone (limind, curlim, pdesc)
651 int limind;
652 RLIMTYPE curlim;
653 int pdesc;
654{
655 char unitstr[64];
656 int factor;
657
658 factor = BLOCKSIZE(limits[limind].block_factor);
659 if (pdesc)
660 {
661 if (limits[limind].units)
662 sprintf (unitstr, "(%s, -%c) ", limits[limind].units, limits[limind].option);
663 else
664 sprintf (unitstr, "(-%c) ", limits[limind].option);
665
666 printf ("%-20s %16s", limits[limind].description, unitstr);
667 }
668 if (curlim == RLIM_INFINITY)
669 puts ("unlimited");
670 else if (curlim == RLIM_SAVED_MAX)
671 puts ("hard");
672 else if (curlim == RLIM_SAVED_CUR)
673 puts ("soft");
674 else
675 print_rlimtype ((curlim / factor), 1);
676}
677
678/* Set all limits to NEWLIM. NEWLIM currently must be RLIM_INFINITY, which
679 causes all limits to be set as high as possible depending on mode (like
680 csh `unlimit'). Returns -1 if NEWLIM is invalid, 0 if all limits
681 were set successfully, and 1 if at least one limit could not be set.
682
683 To raise all soft limits to their corresponding hard limits, use
684 ulimit -S -a unlimited
685 To attempt to raise all hard limits to infinity (superuser-only), use
686 ulimit -H -a unlimited
687 To attempt to raise all soft and hard limits to infinity, use
688 ulimit -a unlimited
689*/
690
691static int
692set_all_limits (mode, newlim)
693 int mode;
694 RLIMTYPE newlim;
695{
696 register int i;
697 int retval = 0;
698
699 if (newlim != RLIM_INFINITY)
700 {
701 errno = EINVAL;
702 return -1;
703 }
704
705 if (mode == 0)
706 mode = LIMIT_SOFT|LIMIT_HARD;
707
708 for (retval = i = 0; limits[i].option > 0; i++)
709 if (set_limit (i, newlim, mode) < 0)
710 {
711 builtin_error (_("%s: cannot modify limit: %s"), limits[i].description,
712 strerror (errno));
713 retval = 1;
714 }
715 return retval;
716}
717
718#endif /* !_MINIX */