aboutsummaryrefslogtreecommitdiffstats
path: root/res/res_limit.c
blob: 045f8db69d49bc63f59a32007f75a5ce17decb22 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/*
 * Asterisk -- A telephony toolkit for Linux.
 *
 * Resource limits
 * 
 * Copyright (c) 2006 Tilghman Lesher.  All rights reserved.
 *
 * Tilghman Lesher <res_limit_200607@the-tilghman.com>
 *
 * This code is released by the author with no restrictions on usage.
 *
 */

/*! \file
 *
 * \brief Resource limits
 *
 * \author Tilghman Lesher <res_limit_200607@the-tilghman.com>
 */


#include "asterisk.h"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define _XOPEN_SOURCE 600
#include <string.h>
#include <ctype.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <errno.h>
#include "asterisk/module.h"
#include "asterisk/cli.h"

/* Find proper rlimit for virtual memory */
#ifdef RLIMIT_AS
#define VMEM_DEF RLIMIT_AS
#else
#ifdef RLIMIT_VMEM
#define VMEM_DEF RLIMIT_VMEM
#endif
#endif

static struct limits {
	int resource;
	char limit[3];
	char desc[40];
} limits[] = {
	{ RLIMIT_CPU, "-t", "cpu time" },
	{ RLIMIT_FSIZE, "-f", "file size" },
	{ RLIMIT_DATA, "-d", "program data segment" },
	{ RLIMIT_STACK, "-s", "program stack size" },
	{ RLIMIT_CORE, "-c", "core file size" },
#ifdef RLIMIT_RSS
	{ RLIMIT_RSS, "-m", "resident memory" },
	{ RLIMIT_NPROC, "-u", "number of processes" },
	{ RLIMIT_MEMLOCK, "-l", "amount of memory locked into RAM" },
#endif
	{ RLIMIT_NOFILE, "-n", "number of file descriptors" },
#ifdef VMEM_DEF
	{ VMEM_DEF, "-v", "virtual memory" },
#endif
};

static int str2limit(const char *string)
{
	size_t i;
	for (i = 0; i < sizeof(limits) / sizeof(limits[0]); i++) {
		if (!strcasecmp(string, limits[i].limit))
			return limits[i].resource;
	}
	return -1;
}

static const char *str2desc(const char *string)
{
	size_t i;
	for (i = 0; i < sizeof(limits) / sizeof(limits[0]); i++) {
		if (!strcmp(string, limits[i].limit))
			return limits[i].desc;
	}
	return "<unknown>";
}

static int my_ulimit(int fd, int argc, char **argv)
{
	int resource;
	struct rlimit rlimit = { 0, 0 };
	if (argc > 3)
		return RESULT_SHOWUSAGE;

	if (argc == 1) {
		char arg2[3];
		char *newargv[2] = { "ulimit", arg2 };
		for (resource = 0; resource < sizeof(limits) / sizeof(limits[0]); resource++) {
			ast_copy_string(arg2, limits[resource].limit, sizeof(arg2));
			my_ulimit(fd, 2, newargv);
		}
		return RESULT_SUCCESS;
	} else {
		resource = str2limit(argv[1]);
		if (resource == -1) {
			ast_cli(fd, "Unknown resource\n");
			return RESULT_FAILURE;
		}

		if (argc == 3) {
			int x;
			if (resource != RLIMIT_NOFILE && resource != RLIMIT_CORE && resource != RLIMIT_NPROC && resource != RLIMIT_FSIZE) {
				ast_cli(fd, "Resource not permitted to be set\n");
				return RESULT_FAILURE;
			}

			sscanf(argv[2], "%d", &x);
			rlimit.rlim_max = rlimit.rlim_cur = x;
			setrlimit(resource, &rlimit);
			return RESULT_SUCCESS;
		} else {
			if (!getrlimit(resource, &rlimit)) {
				char printlimit[32];
				const char *desc;
				if (rlimit.rlim_max == RLIM_INFINITY)
					ast_copy_string(printlimit, "effectively unlimited", sizeof(printlimit));
				else
					snprintf(printlimit, sizeof(printlimit), "limited to %d", (int)rlimit.rlim_cur);
				desc = str2desc(argv[1]);
				ast_cli(fd, "%c%s (%s) is %s.\n", toupper(desc[0]), desc + 1, argv[1], printlimit);
			} else
				ast_cli(fd, "Could not retrieve resource limits for %s: %s\n", str2desc(argv[1]), strerror(errno));
			return RESULT_SUCCESS;
		}
	}
}

static char *complete_ulimit(const char *line, const char *word, int pos, int state)
{
	int which = 0, i;
	int wordlen = strlen(word);

	if (pos > 2)
		return NULL;
	for (i = 0; i < sizeof(limits) / sizeof(limits[0]); i++) {
		if (!strncasecmp(limits[i].limit, word, wordlen)) {
			if (++which > state)
				return ast_strdup(limits[i].limit);
		}
	}
	return NULL;
}

static const char ulimit_usage[] =
"Usage: ulimit {-d|-l|-f|-m|-s|-t|-u|-v|-c|-n} [<num>]\n"
"       Shows or sets the corresponding resource limit.\n"
"         -d  Process data segment [readonly]\n"
"         -l  Memory lock size [readonly]\n"
"         -f  File size\n"
"         -m  Process resident memory [readonly]\n"
"         -s  Process stack size [readonly]\n"
"         -t  CPU usage [readonly]\n"
"         -u  Child processes\n"
#ifdef VMEM_DEF
"         -v  Process virtual memory [readonly]\n"
#endif
"         -c  Core dump file size\n"
"         -n  Number of file descriptors\n";

static struct ast_cli_entry cli_ulimit = {
	{ "ulimit", NULL }, my_ulimit,
	"Set or show process resource limits", ulimit_usage, complete_ulimit };

static int unload_module(void)
{
	return ast_cli_unregister(&cli_ulimit);
}

static int load_module(void)
{
	return ast_cli_register(&cli_ulimit)? AST_MODULE_LOAD_FAILURE: AST_MODULE_LOAD_SUCCESS;
}

AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Resource limits");