2 * prlimit - get/set process resource limits.
4 * Copyright (C) 2011 Davidlohr Bueso <dave@gnu.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include <sys/resource.h>
37 # define RLIMIT_RTTIME 15
66 static struct prlimit_desc prlimit_desc
[] =
68 [AS
] = { "AS", N_("address space limit"), N_("bytes"), RLIMIT_AS
},
69 [CORE
] = { "CORE", N_("max core file size"), N_("blocks"), RLIMIT_CORE
},
70 [CPU
] = { "CPU", N_("CPU time"), N_("seconds"), RLIMIT_CPU
},
71 [DATA
] = { "DATA", N_("max data size"), N_("bytes"), RLIMIT_DATA
},
72 [FSIZE
] = { "FSIZE", N_("max file size"), N_("blocks"), RLIMIT_FSIZE
},
73 [LOCKS
] = { "LOCKS", N_("max amount of file locks held"), NULL
, RLIMIT_LOCKS
},
74 [MEMLOCK
] = { "MEMLOCK", N_("max locked-in-memory address space"), N_("bytes"), RLIMIT_MEMLOCK
},
75 [MSGQUEUE
] = { "MSGQUEUE", N_("max bytes in POSIX mqueues"), N_("bytes"), RLIMIT_MSGQUEUE
},
76 [NICE
] = { "NICE", N_("max nice prio allowed to raise"), NULL
, RLIMIT_NICE
},
77 [NOFILE
] = { "NOFILE", N_("max amount of open files"), NULL
, RLIMIT_NOFILE
},
78 [NPROC
] = { "NPROC", N_("max number of processes"), NULL
, RLIMIT_NPROC
},
79 [RSS
] = { "RSS", N_("max resident set size"), N_("pages"), RLIMIT_RSS
},
80 [RTPRIO
] = { "RTPRIO", N_("max real-time priority"), NULL
, RLIMIT_RTPRIO
},
81 [RTTIME
] = { "RTTIME", N_("timeout for real-time tasks"), N_("microsecs"), RLIMIT_RTTIME
},
82 [SIGPENDING
] = { "SIGPENDING", N_("max amount of pending signals"), NULL
, RLIMIT_SIGPENDING
},
83 [STACK
] = { "STACK", N_("max stack size"), N_("bytes"), RLIMIT_STACK
}
88 struct prlimit_desc
*desc
;
92 #define PRLIMIT_EMPTY_LIMIT {{ 0, 0, }, NULL, 0 }
104 const char *name
; /* header */
105 double whint
; /* width hint (N < 1 is in percent of termwidth) */
106 int flags
; /* TT_FL_* */
110 /* columns descriptions */
111 struct colinfo infos
[] = {
112 [COL_RES
] = { "RESOURCE", 0.25, TT_FL_TRUNC
, N_("resource name") },
113 [COL_HELP
] = { "DESCRIPTION", 0.1, TT_FL_TRUNC
, N_("resource description")},
114 [COL_SOFT
] = { "SOFT", 0.1, TT_FL_RIGHT
, N_("soft limit")},
115 [COL_HARD
] = { "HARD", 1, TT_FL_RIGHT
, N_("hard limit (ceiling)")},
116 [COL_UNITS
] = { "UNITS", 0.1, TT_FL_TRUNC
, N_("units")},
119 #define NCOLS ARRAY_SIZE(infos)
120 #define MAX_RESOURCES ARRAY_SIZE(prlimit_desc)
122 #define INFINITY_STR "unlimited"
123 #define INFINITY_STRLEN (sizeof(INFINITY_STR) - 1)
125 #define PRLIMIT_SOFT (1 << 1)
126 #define PRLIMIT_HARD (1 << 2)
128 /* array with IDs of enabled columns */
129 static int columns
[NCOLS
], ncolumns
;
130 static pid_t pid
; /* calling process (default) */
134 # include <sys/syscall.h>
135 static int prlimit(pid_t p
, int resource
,
136 const struct rlimit
*new_limit
,
137 struct rlimit
*old_limit
)
139 return syscall(SYS_prlimit
, p
, resource
, new_limit
, old_limit
);
143 static void __attribute__ ((__noreturn__
)) usage(FILE * out
)
147 fputs(USAGE_HEADER
, out
);
150 _(" %s [options]\n"), program_invocation_short_name
);
152 fputs(_("\nGeneral Options:\n"), out
);
153 fputs(_(" -p, --pid <pid> process id\n"
154 " -o, --output <list> define which output columns to use\n"
155 " --noheadings don't print headings\n"
156 " --raw use the raw output format\n"
157 " --verbose verbose output\n"
158 " -h, --help display this help and exit\n"
159 " -V, --version output version information and exit\n"), out
);
161 fputs(_("\nResources Options:\n"), out
);
162 fputs(_(" -c, --core maximum size of core files created\n"
163 " -d, --data maximum size of a process's data segment\n"
164 " -e, --nice maximum nice priority allowed to raise\n"
165 " -f, --fsize maximum size of files written by the process\n"
166 " -i, --sigpending maximum amount of pending signals\n"
167 " -l, --memlock maximum size a process may lock into memory\n"
168 " -m, --rss maximum resident set size\n"
169 " -n, --nofile maximum amount of open files\n"
170 " -q, --msgqueue maximum bytes in POSIX message queues\n"
171 " -r, --rtprio maximum real-time scheduling priority\n"
172 " -s, --stack maximum stack size\n"
173 " -t, --cpu maximum amount of CPU time in seconds\n"
174 " -u, --nproc maximum number of user processes\n"
175 " -v, --as size of virtual memory\n"
176 " -x, --locks maximum number of file locks\n"
177 " -y, --rttime CPU time in microseconds a process scheduled\n"
178 " under real-time scheduling\n"), out
);
180 fputs(_("\nAvailable columns (for --output):\n"), out
);
182 for (i
= 0; i
< NCOLS
; i
++)
183 fprintf(out
, " %11s %s\n", infos
[i
].name
, _(infos
[i
].help
));
185 fprintf(out
, USAGE_MAN_TAIL("prlimit(1)"));
187 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
190 static inline int get_column_id(int num
)
192 assert(ARRAY_SIZE(columns
) == NCOLS
);
193 assert(num
< ncolumns
);
194 assert(columns
[num
] < (int) NCOLS
);
199 static inline struct colinfo
*get_column_info(unsigned num
)
201 return &infos
[ get_column_id(num
) ];
204 static void add_tt_line(struct tt
*tt
, struct prlimit
*l
)
207 struct tt_line
*line
;
212 line
= tt_add_line(tt
, NULL
);
214 warn(_("failed to add line to output"));
218 for (i
= 0; i
< ncolumns
; i
++) {
222 switch (get_column_id(i
)) {
224 rc
= asprintf(&str
, "%s", l
->desc
->name
);
227 rc
= asprintf(&str
, "%s", l
->desc
->help
);
230 rc
= l
->rlim
.rlim_cur
== RLIM_INFINITY
?
231 asprintf(&str
, "%s", "unlimited") :
232 asprintf(&str
, "%llu", (unsigned long long) l
->rlim
.rlim_cur
);
235 rc
= l
->rlim
.rlim_max
== RLIM_INFINITY
?
236 asprintf(&str
, "%s", "unlimited") :
237 asprintf(&str
, "%llu", (unsigned long long) l
->rlim
.rlim_max
);
240 str
= l
->desc
->unit
? xstrdup(_(l
->desc
->unit
)) : NULL
;
247 tt_line_set_data(line
, i
, str
);
251 static int column_name_to_id(const char *name
, size_t namesz
)
257 for (i
= 0; i
< NCOLS
; i
++) {
258 const char *cn
= infos
[i
].name
;
260 if (!strncasecmp(name
, cn
, namesz
) && !*(cn
+ namesz
))
263 warnx(_("unknown column: %s"), name
);
267 static int show_limits(struct prlimit lims
[], size_t n
, int tt_flags
)
272 tt
= tt_new_table(tt_flags
);
274 warn(_("failed to initialize output table"));
278 for (i
= 0; i
< ncolumns
; i
++) {
279 struct colinfo
*col
= get_column_info(i
);
281 if (!tt_define_column(tt
, col
->name
, col
->whint
, col
->flags
)) {
282 warnx(_("failed to initialize output column"));
287 for (i
= 0; (size_t) i
< n
; i
++)
288 if (!lims
[i
].modify
) /* only display old limits */
289 add_tt_line(tt
, &lims
[i
]);
298 static void do_prlimit(struct prlimit lims
[], size_t n
, int tt_flags
)
300 size_t i
, nshows
= 0;
302 for (i
= 0; i
< n
; i
++) {
303 struct rlimit
*new = NULL
;
310 if (verbose
&& new) {
311 printf(_("New %s limit: "), lims
[i
].desc
->name
);
312 if (new->rlim_cur
== RLIM_INFINITY
)
313 printf("<%s", _("unlimited"));
315 printf("<%ju", new->rlim_cur
);
317 if (new->rlim_max
== RLIM_INFINITY
)
318 printf(":%s>\n", _("unlimited"));
320 printf(":%ju>\n", new->rlim_max
);
323 if (prlimit(pid
, lims
[i
].desc
->resource
, new, &lims
[i
].rlim
) == -1)
324 err(EXIT_FAILURE
, _("failed to get resource limits for PID %d"), pid
);
328 show_limits(lims
, n
, tt_flags
);
333 static int get_range(char *str
, rlim_t
*soft
, rlim_t
*hard
, int *found
)
341 *soft
= *hard
= RLIM_INFINITY
;
343 if (!strcmp(str
, INFINITY_STR
)) { /* <unlimited> */
344 *found
|= PRLIMIT_SOFT
| PRLIMIT_HARD
;
347 } else if (*str
== ':') { /* <:hard> */
350 if (strcmp(str
, INFINITY_STR
) != 0) {
351 *hard
= strtoull(str
, &end
, 10);
353 if (errno
|| !end
|| *end
|| end
== str
)
356 *found
|= PRLIMIT_HARD
;
361 if (strncmp(str
, INFINITY_STR
, INFINITY_STRLEN
) == 0) {
362 /* <unlimited> or <unlimited:> */
363 end
= str
+ INFINITY_STRLEN
;
365 /* <value> or <soft:> */
366 *hard
= *soft
= strtoull(str
, &end
, 10);
367 if (errno
|| !end
|| end
== str
)
371 if (*end
== ':' && !*(end
+ 1)) /* <soft:> */
372 *found
|= PRLIMIT_SOFT
;
374 else if (*end
== ':') { /* <soft:hard> */
377 if (!strcmp(str
, INFINITY_STR
))
378 *hard
= RLIM_INFINITY
;
382 *hard
= strtoull(str
, &end
, 10);
384 if (errno
|| !end
|| *end
|| end
== str
)
387 *found
|= PRLIMIT_SOFT
| PRLIMIT_HARD
;
390 *found
|= PRLIMIT_SOFT
| PRLIMIT_HARD
;
396 static int parse_prlim(struct rlimit
*lim
, char *ops
, size_t id
)
401 if (get_range(ops
, &soft
, &hard
, &found
))
402 errx(EXIT_FAILURE
, _("failed to parse %s limit"),
403 prlimit_desc
[id
].name
);
406 * If one of the limits is unknown (default value for not being passed), we need
407 * to get the current limit and use it.
408 * I see no other way other than using prlimit(2).
410 if (found
!= (PRLIMIT_HARD
| PRLIMIT_SOFT
)) {
413 if (prlimit(pid
, prlimit_desc
[id
].resource
, NULL
, &old
) == -1)
414 errx(EXIT_FAILURE
, _("failed to get old %s limit"),
415 prlimit_desc
[id
].name
);
417 if (!(found
& PRLIMIT_SOFT
))
419 else if (!(found
& PRLIMIT_HARD
))
423 if (soft
> hard
&& (soft
!= RLIM_INFINITY
|| hard
!= RLIM_INFINITY
))
424 errx(EXIT_FAILURE
, _("the soft limit cannot exceed the ceiling value"));
426 lim
->rlim_cur
= soft
;
427 lim
->rlim_max
= hard
;
433 * Add a resource limit to the limits array
435 static int add_prlim(char *ops
, struct prlimit
*lim
, size_t id
)
437 lim
->desc
= &prlimit_desc
[id
];
439 if (ops
) { /* planning on modifying a limit? */
441 parse_prlim(&lim
->rlim
, ops
, id
);
447 int main(int argc
, char **argv
)
449 int opt
, tt_flags
= 0;
451 struct prlimit lims
[MAX_RESOURCES
] = { PRLIMIT_EMPTY_LIMIT
};
454 VERBOSE_OPTION
= CHAR_MAX
+ 1,
459 static const struct option longopts
[] = {
460 { "pid", required_argument
, NULL
, 'p' },
461 { "output", required_argument
, NULL
, 'o' },
462 { "as", optional_argument
, NULL
, 'v' },
463 { "core", optional_argument
, NULL
, 'c' },
464 { "cpu", optional_argument
, NULL
, 't' },
465 { "data", optional_argument
, NULL
, 'd' },
466 { "fsize", optional_argument
, NULL
, 'f' },
467 { "locks", optional_argument
, NULL
, 'x' },
468 { "memlock", optional_argument
, NULL
, 'l' },
469 { "msgqueue", optional_argument
, NULL
, 'q' },
470 { "nice", optional_argument
, NULL
, 'e' },
471 { "nofile", optional_argument
, NULL
, 'n' },
472 { "nproc", optional_argument
, NULL
, 'u' },
473 { "rss", optional_argument
, NULL
, 'm' },
474 { "rtprio", optional_argument
, NULL
, 'r' },
475 { "rttime", optional_argument
, NULL
, 'y' },
476 { "sigpending", optional_argument
, NULL
, 'i' },
477 { "stack", optional_argument
, NULL
, 's' },
478 { "version", no_argument
, NULL
, 'V' },
479 { "help", no_argument
, NULL
, 'h' },
480 { "noheadings", no_argument
, NULL
, NOHEADINGS_OPTION
},
481 { "raw", no_argument
, NULL
, RAW_OPTION
},
482 { "verbose", no_argument
, NULL
, VERBOSE_OPTION
},
486 setlocale(LC_ALL
, "");
487 bindtextdomain(PACKAGE
, LOCALEDIR
);
491 * Something is very wrong if this doesn't succeed,
492 * assuming STACK is the last resource, of course.
494 assert(MAX_RESOURCES
== STACK
+ 1);
496 while((opt
= getopt_long(argc
, argv
,
497 "c::d::e::f::i::l::m::n::q::r::s::t::u::v::x::y::p:o:vVh",
498 longopts
, NULL
)) != -1) {
501 add_prlim(optarg
, &lims
[n
++], CORE
);
504 add_prlim(optarg
, &lims
[n
++], DATA
);
507 add_prlim(optarg
, &lims
[n
++], NICE
);
510 add_prlim(optarg
, &lims
[n
++], FSIZE
);
513 add_prlim(optarg
, &lims
[n
++], SIGPENDING
);
516 add_prlim(optarg
, &lims
[n
++], MEMLOCK
);
519 add_prlim(optarg
, &lims
[n
++], RSS
);
522 add_prlim(optarg
, &lims
[n
++], NOFILE
);
525 add_prlim(optarg
, &lims
[n
++], MSGQUEUE
);
528 add_prlim(optarg
, &lims
[n
++], RTPRIO
);
531 add_prlim(optarg
, &lims
[n
++], STACK
);
534 add_prlim(optarg
, &lims
[n
++], CPU
);
537 add_prlim(optarg
, &lims
[n
++], NPROC
);
540 add_prlim(optarg
, &lims
[n
++], AS
);
543 add_prlim(optarg
, &lims
[n
++], LOCKS
);
546 add_prlim(optarg
, &lims
[n
++], RTTIME
);
550 if (pid
) /* we only work one pid at a time */
551 errx(EXIT_FAILURE
, _("only use one PID at a time"));
553 pid
= strtol_or_err(optarg
, _("cannot parse PID"));
559 ncolumns
= string_to_idarray(optarg
,
560 columns
, ARRAY_SIZE(columns
),
566 printf(UTIL_LINUX_VERSION
);
569 case NOHEADINGS_OPTION
:
570 tt_flags
|= TT_FL_NOHEADINGS
;
576 tt_flags
|= TT_FL_RAW
;
589 /* default columns */
590 columns
[ncolumns
++] = COL_RES
;
591 columns
[ncolumns
++] = COL_HELP
;
592 columns
[ncolumns
++] = COL_SOFT
;
593 columns
[ncolumns
++] = COL_HARD
;
594 columns
[ncolumns
++] = COL_UNITS
;
598 /* default is to print all resources */
599 for (; n
< MAX_RESOURCES
; n
++)
600 add_prlim(NULL
, &lims
[n
], n
);
603 do_prlimit(lims
, n
, tt_flags
);