xref: /titanic_50/usr/src/cmd/plimit/plimit.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.5	*/
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #define	__EXTENSIONS__	/* For strtok_r */
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <stdio.h>
32*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
33*7c478bd9Sstevel@tonic-gate #include <unistd.h>
34*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
35*7c478bd9Sstevel@tonic-gate #include <ctype.h>
36*7c478bd9Sstevel@tonic-gate #include <string.h>
37*7c478bd9Sstevel@tonic-gate #include <signal.h>
38*7c478bd9Sstevel@tonic-gate #include <limits.h>
39*7c478bd9Sstevel@tonic-gate #include <errno.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/mman.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
44*7c478bd9Sstevel@tonic-gate #include <libproc.h>
45*7c478bd9Sstevel@tonic-gate #include <priv.h>
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate #define	TRUE	1
48*7c478bd9Sstevel@tonic-gate #define	FALSE	0
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate static	int	interrupt;
51*7c478bd9Sstevel@tonic-gate static	char	*command;
52*7c478bd9Sstevel@tonic-gate static	int	Fflag;
53*7c478bd9Sstevel@tonic-gate static	int	kbytes = FALSE;
54*7c478bd9Sstevel@tonic-gate static	int	mbytes = FALSE;
55*7c478bd9Sstevel@tonic-gate static	char	set_current[RLIM_NLIMITS];
56*7c478bd9Sstevel@tonic-gate static	char	set_maximum[RLIM_NLIMITS];
57*7c478bd9Sstevel@tonic-gate static	struct rlimit64 rlimit[RLIM_NLIMITS];
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate static	void	intr(int);
60*7c478bd9Sstevel@tonic-gate static	int	parse_limits(int, char *);
61*7c478bd9Sstevel@tonic-gate static	void	show_limits(struct ps_prochandle *);
62*7c478bd9Sstevel@tonic-gate static	int	set_limits(struct ps_prochandle *);
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate static void
usage()65*7c478bd9Sstevel@tonic-gate usage()
66*7c478bd9Sstevel@tonic-gate {
67*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
68*7c478bd9Sstevel@tonic-gate 		"usage:\n"
69*7c478bd9Sstevel@tonic-gate 		"    For each process, report all resource limits:\n"
70*7c478bd9Sstevel@tonic-gate 		"\t%s [-km] pid ...\n"
71*7c478bd9Sstevel@tonic-gate 		"\t-k\treport file sizes in kilobytes\n"
72*7c478bd9Sstevel@tonic-gate 		"\t-m\treport file/memory sizes in megabytes\n"
73*7c478bd9Sstevel@tonic-gate 		"    For each process, set specified resource limits:\n"
74*7c478bd9Sstevel@tonic-gate 		"\t%s -{cdfnstv} soft,hard ... pid ...\n"
75*7c478bd9Sstevel@tonic-gate 		"\t-c soft,hard\tset core file size limits\n"
76*7c478bd9Sstevel@tonic-gate 		"\t-d soft,hard\tset data segment (heap) size limits\n"
77*7c478bd9Sstevel@tonic-gate 		"\t-f soft,hard\tset file size limits\n"
78*7c478bd9Sstevel@tonic-gate 		"\t-n soft,hard\tset file descriptor limits\n"
79*7c478bd9Sstevel@tonic-gate 		"\t-s soft,hard\tset stack segment size limits\n"
80*7c478bd9Sstevel@tonic-gate 		"\t-t soft,hard\tset CPU time limits\n"
81*7c478bd9Sstevel@tonic-gate 		"\t-v soft,hard\tset virtual memory size limits\n"
82*7c478bd9Sstevel@tonic-gate 		"\t(default units are as shown by the output of '%s pid')\n",
83*7c478bd9Sstevel@tonic-gate 		command, command, command);
84*7c478bd9Sstevel@tonic-gate 	exit(2);
85*7c478bd9Sstevel@tonic-gate }
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)88*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
89*7c478bd9Sstevel@tonic-gate {
90*7c478bd9Sstevel@tonic-gate 	int retc = 0;
91*7c478bd9Sstevel@tonic-gate 	int opt;
92*7c478bd9Sstevel@tonic-gate 	int errflg = 0;
93*7c478bd9Sstevel@tonic-gate 	int set = FALSE;
94*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *Pr;
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	if ((command = strrchr(argv[0], '/')) != NULL)
97*7c478bd9Sstevel@tonic-gate 		command++;
98*7c478bd9Sstevel@tonic-gate 	else
99*7c478bd9Sstevel@tonic-gate 		command = argv[0];
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "Fkmc:d:f:n:s:t:v:")) != EOF) {
102*7c478bd9Sstevel@tonic-gate 		switch (opt) {
103*7c478bd9Sstevel@tonic-gate 		case 'F':		/* force grabbing (no O_EXCL) */
104*7c478bd9Sstevel@tonic-gate 			Fflag = PGRAB_FORCE;
105*7c478bd9Sstevel@tonic-gate 			break;
106*7c478bd9Sstevel@tonic-gate 		case 'k':
107*7c478bd9Sstevel@tonic-gate 			kbytes = TRUE;
108*7c478bd9Sstevel@tonic-gate 			mbytes = FALSE;
109*7c478bd9Sstevel@tonic-gate 			break;
110*7c478bd9Sstevel@tonic-gate 		case 'm':
111*7c478bd9Sstevel@tonic-gate 			kbytes = FALSE;
112*7c478bd9Sstevel@tonic-gate 			mbytes = TRUE;
113*7c478bd9Sstevel@tonic-gate 			break;
114*7c478bd9Sstevel@tonic-gate 		case 'c':	/* core file size */
115*7c478bd9Sstevel@tonic-gate 			set = TRUE;
116*7c478bd9Sstevel@tonic-gate 			errflg += parse_limits(RLIMIT_CORE, optarg);
117*7c478bd9Sstevel@tonic-gate 			break;
118*7c478bd9Sstevel@tonic-gate 		case 'd':	/* data segment size */
119*7c478bd9Sstevel@tonic-gate 			set = TRUE;
120*7c478bd9Sstevel@tonic-gate 			errflg += parse_limits(RLIMIT_DATA, optarg);
121*7c478bd9Sstevel@tonic-gate 			break;
122*7c478bd9Sstevel@tonic-gate 		case 'f':	/* file size */
123*7c478bd9Sstevel@tonic-gate 			set = TRUE;
124*7c478bd9Sstevel@tonic-gate 			errflg += parse_limits(RLIMIT_FSIZE, optarg);
125*7c478bd9Sstevel@tonic-gate 			break;
126*7c478bd9Sstevel@tonic-gate 		case 'n':	/* file descriptors */
127*7c478bd9Sstevel@tonic-gate 			set = TRUE;
128*7c478bd9Sstevel@tonic-gate 			errflg += parse_limits(RLIMIT_NOFILE, optarg);
129*7c478bd9Sstevel@tonic-gate 			break;
130*7c478bd9Sstevel@tonic-gate 		case 's':	/* stack segment size */
131*7c478bd9Sstevel@tonic-gate 			set = TRUE;
132*7c478bd9Sstevel@tonic-gate 			errflg += parse_limits(RLIMIT_STACK, optarg);
133*7c478bd9Sstevel@tonic-gate 			break;
134*7c478bd9Sstevel@tonic-gate 		case 't':	/* CPU time */
135*7c478bd9Sstevel@tonic-gate 			set = TRUE;
136*7c478bd9Sstevel@tonic-gate 			errflg += parse_limits(RLIMIT_CPU, optarg);
137*7c478bd9Sstevel@tonic-gate 			break;
138*7c478bd9Sstevel@tonic-gate 		case 'v':	/* virtual memory size */
139*7c478bd9Sstevel@tonic-gate 			set = TRUE;
140*7c478bd9Sstevel@tonic-gate 			errflg += parse_limits(RLIMIT_VMEM, optarg);
141*7c478bd9Sstevel@tonic-gate 			break;
142*7c478bd9Sstevel@tonic-gate 		default:
143*7c478bd9Sstevel@tonic-gate 			errflg = 1;
144*7c478bd9Sstevel@tonic-gate 			break;
145*7c478bd9Sstevel@tonic-gate 		}
146*7c478bd9Sstevel@tonic-gate 	}
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate 	argc -= optind;
149*7c478bd9Sstevel@tonic-gate 	argv += optind;
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate 	if (errflg || argc <= 0)
152*7c478bd9Sstevel@tonic-gate 		usage();
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 	/* catch signals from terminal */
155*7c478bd9Sstevel@tonic-gate 	if (sigset(SIGHUP, SIG_IGN) == SIG_DFL)
156*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGHUP, intr);
157*7c478bd9Sstevel@tonic-gate 	if (sigset(SIGINT, SIG_IGN) == SIG_DFL)
158*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGINT, intr);
159*7c478bd9Sstevel@tonic-gate 	if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL)
160*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGQUIT, intr);
161*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGPIPE, intr);
162*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGTERM, intr);
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 	while (--argc >= 0 && !interrupt) {
165*7c478bd9Sstevel@tonic-gate 		psinfo_t psinfo;
166*7c478bd9Sstevel@tonic-gate 		char *arg;
167*7c478bd9Sstevel@tonic-gate 		pid_t pid;
168*7c478bd9Sstevel@tonic-gate 		int gret;
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);	/* process-at-a-time */
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 		/* get the specified pid and the psinfo struct */
173*7c478bd9Sstevel@tonic-gate 		if ((pid = proc_arg_psinfo(arg = *argv++, PR_ARG_PIDS,
174*7c478bd9Sstevel@tonic-gate 		    &psinfo, &gret)) == -1) {
175*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: cannot examine %s: %s\n",
176*7c478bd9Sstevel@tonic-gate 				command, arg, Pgrab_error(gret));
177*7c478bd9Sstevel@tonic-gate 			retc = 1;
178*7c478bd9Sstevel@tonic-gate 		} else if ((Pr = Pgrab(pid, Fflag, &gret)) != NULL) {
179*7c478bd9Sstevel@tonic-gate 			if (Pcreate_agent(Pr) == 0) {
180*7c478bd9Sstevel@tonic-gate 				if (set) {
181*7c478bd9Sstevel@tonic-gate 					if (set_limits(Pr) != 0)
182*7c478bd9Sstevel@tonic-gate 						retc = 1;
183*7c478bd9Sstevel@tonic-gate 				} else {
184*7c478bd9Sstevel@tonic-gate 					proc_unctrl_psinfo(&psinfo);
185*7c478bd9Sstevel@tonic-gate 					(void) printf("%d:\t%.70s\n",
186*7c478bd9Sstevel@tonic-gate 						(int)pid, psinfo.pr_psargs);
187*7c478bd9Sstevel@tonic-gate 					show_limits(Pr);
188*7c478bd9Sstevel@tonic-gate 				}
189*7c478bd9Sstevel@tonic-gate 				Pdestroy_agent(Pr);
190*7c478bd9Sstevel@tonic-gate 			} else {
191*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
192*7c478bd9Sstevel@tonic-gate 					"%s: cannot control process %d\n",
193*7c478bd9Sstevel@tonic-gate 					command, (int)pid);
194*7c478bd9Sstevel@tonic-gate 				retc = 1;
195*7c478bd9Sstevel@tonic-gate 			}
196*7c478bd9Sstevel@tonic-gate 			Prelease(Pr, 0);
197*7c478bd9Sstevel@tonic-gate 		} else {
198*7c478bd9Sstevel@tonic-gate 			if ((gret == G_SYS || gret == G_SELF) && !set) {
199*7c478bd9Sstevel@tonic-gate 				proc_unctrl_psinfo(&psinfo);
200*7c478bd9Sstevel@tonic-gate 				(void) printf("%d:\t%.70s\n", (int)pid,
201*7c478bd9Sstevel@tonic-gate 					psinfo.pr_psargs);
202*7c478bd9Sstevel@tonic-gate 				if (gret == G_SYS)
203*7c478bd9Sstevel@tonic-gate 					(void) printf("  [system process]\n");
204*7c478bd9Sstevel@tonic-gate 				else
205*7c478bd9Sstevel@tonic-gate 					show_limits(NULL);
206*7c478bd9Sstevel@tonic-gate 			} else {
207*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
208*7c478bd9Sstevel@tonic-gate 					"%s: %s: %d\n",
209*7c478bd9Sstevel@tonic-gate 					command, Pgrab_error(gret), (int)pid);
210*7c478bd9Sstevel@tonic-gate 				retc = 1;
211*7c478bd9Sstevel@tonic-gate 			}
212*7c478bd9Sstevel@tonic-gate 		}
213*7c478bd9Sstevel@tonic-gate 	}
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 	if (interrupt)
216*7c478bd9Sstevel@tonic-gate 		retc = 1;
217*7c478bd9Sstevel@tonic-gate 	return (retc);
218*7c478bd9Sstevel@tonic-gate }
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate static void
intr(int sig)221*7c478bd9Sstevel@tonic-gate intr(int sig)
222*7c478bd9Sstevel@tonic-gate {
223*7c478bd9Sstevel@tonic-gate 	interrupt = sig;
224*7c478bd9Sstevel@tonic-gate }
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate /* ------ begin specific code ------ */
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate /*
229*7c478bd9Sstevel@tonic-gate  * Compute a limit, given a string:
230*7c478bd9Sstevel@tonic-gate  *	unlimited	unlimited
231*7c478bd9Sstevel@tonic-gate  *	nnn k		nnn kilobytes
232*7c478bd9Sstevel@tonic-gate  *	nnn m		nnn megabytes (minutes for CPU time)
233*7c478bd9Sstevel@tonic-gate  *	nnn h		nnn hours (for CPU time only)
234*7c478bd9Sstevel@tonic-gate  *	mm : ss		minutes and seconds (for CPU time only)
235*7c478bd9Sstevel@tonic-gate  */
236*7c478bd9Sstevel@tonic-gate static int
limit_value(int which,char * arg,rlim64_t * limit)237*7c478bd9Sstevel@tonic-gate limit_value(int which, char *arg, rlim64_t *limit)
238*7c478bd9Sstevel@tonic-gate {
239*7c478bd9Sstevel@tonic-gate 	rlim64_t value;
240*7c478bd9Sstevel@tonic-gate 	rlim64_t unit;
241*7c478bd9Sstevel@tonic-gate 	char *lastc;
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 	if (strcmp(arg, "unlimited") == 0) {
244*7c478bd9Sstevel@tonic-gate 		*limit = RLIM64_INFINITY;
245*7c478bd9Sstevel@tonic-gate 		return (0);
246*7c478bd9Sstevel@tonic-gate 	}
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 	if (which == RLIMIT_CPU && strchr(arg, ':') != NULL) {
249*7c478bd9Sstevel@tonic-gate 		char *minutes = strtok_r(arg, " \t:", &lastc);
250*7c478bd9Sstevel@tonic-gate 		char *seconds = strtok_r(NULL, " \t", &lastc);
251*7c478bd9Sstevel@tonic-gate 		rlim64_t sec;
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 		if (seconds != NULL && strtok_r(NULL, " \t", &lastc) != NULL)
254*7c478bd9Sstevel@tonic-gate 			return (1);
255*7c478bd9Sstevel@tonic-gate 		value = strtoull(minutes, &lastc, 10);
256*7c478bd9Sstevel@tonic-gate 		if (*lastc != '\0' || value > RLIM64_INFINITY / 60)
257*7c478bd9Sstevel@tonic-gate 			return (1);
258*7c478bd9Sstevel@tonic-gate 		if (seconds == NULL || *seconds == '\0')
259*7c478bd9Sstevel@tonic-gate 			sec = 0;
260*7c478bd9Sstevel@tonic-gate 		else {
261*7c478bd9Sstevel@tonic-gate 			sec = strtoull(seconds, &lastc, 10);
262*7c478bd9Sstevel@tonic-gate 			if (*lastc != '\0' || sec > 60)
263*7c478bd9Sstevel@tonic-gate 				return (1);
264*7c478bd9Sstevel@tonic-gate 		}
265*7c478bd9Sstevel@tonic-gate 		value = value * 60 + sec;
266*7c478bd9Sstevel@tonic-gate 		if (value > RLIM64_INFINITY)
267*7c478bd9Sstevel@tonic-gate 			value = RLIM64_INFINITY;
268*7c478bd9Sstevel@tonic-gate 		*limit = value;
269*7c478bd9Sstevel@tonic-gate 		return (0);
270*7c478bd9Sstevel@tonic-gate 	}
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate 	switch (*(lastc = arg + strlen(arg) - 1)) {
273*7c478bd9Sstevel@tonic-gate 	case 'k':
274*7c478bd9Sstevel@tonic-gate 		unit = 1024;
275*7c478bd9Sstevel@tonic-gate 		*lastc = '\0';
276*7c478bd9Sstevel@tonic-gate 		break;
277*7c478bd9Sstevel@tonic-gate 	case 'm':
278*7c478bd9Sstevel@tonic-gate 		if (which == RLIMIT_CPU)
279*7c478bd9Sstevel@tonic-gate 			unit = 60;
280*7c478bd9Sstevel@tonic-gate 		else
281*7c478bd9Sstevel@tonic-gate 			unit = 1024 * 1024;
282*7c478bd9Sstevel@tonic-gate 		*lastc = '\0';
283*7c478bd9Sstevel@tonic-gate 		break;
284*7c478bd9Sstevel@tonic-gate 	case 'h':
285*7c478bd9Sstevel@tonic-gate 		if (which == RLIMIT_CPU)
286*7c478bd9Sstevel@tonic-gate 			unit = 60 * 60;
287*7c478bd9Sstevel@tonic-gate 		else
288*7c478bd9Sstevel@tonic-gate 			return (1);
289*7c478bd9Sstevel@tonic-gate 		*lastc = '\0';
290*7c478bd9Sstevel@tonic-gate 		break;
291*7c478bd9Sstevel@tonic-gate 	default:
292*7c478bd9Sstevel@tonic-gate 		switch (which) {
293*7c478bd9Sstevel@tonic-gate 		case RLIMIT_CPU:	unit = 1;	break;
294*7c478bd9Sstevel@tonic-gate 		case RLIMIT_FSIZE:	unit = 512;	break;
295*7c478bd9Sstevel@tonic-gate 		case RLIMIT_DATA:	unit = 1024;	break;
296*7c478bd9Sstevel@tonic-gate 		case RLIMIT_STACK:	unit = 1024;	break;
297*7c478bd9Sstevel@tonic-gate 		case RLIMIT_CORE:	unit = 512;	break;
298*7c478bd9Sstevel@tonic-gate 		case RLIMIT_NOFILE:	unit = 1;	break;
299*7c478bd9Sstevel@tonic-gate 		case RLIMIT_VMEM:	unit = 1024;	break;
300*7c478bd9Sstevel@tonic-gate 		}
301*7c478bd9Sstevel@tonic-gate 		break;
302*7c478bd9Sstevel@tonic-gate 	}
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 	value = strtoull(arg, &lastc, 10);
305*7c478bd9Sstevel@tonic-gate 	if (*lastc != '\0' || value > RLIM64_INFINITY / unit)
306*7c478bd9Sstevel@tonic-gate 		return (1);
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	value *= unit;
309*7c478bd9Sstevel@tonic-gate 	if (value > RLIM64_INFINITY)
310*7c478bd9Sstevel@tonic-gate 		value = RLIM64_INFINITY;
311*7c478bd9Sstevel@tonic-gate 	*limit = value;
312*7c478bd9Sstevel@tonic-gate 	return (0);
313*7c478bd9Sstevel@tonic-gate }
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate static int
parse_limits(int which,char * arg)316*7c478bd9Sstevel@tonic-gate parse_limits(int which, char *arg)
317*7c478bd9Sstevel@tonic-gate {
318*7c478bd9Sstevel@tonic-gate 	char *lastc;
319*7c478bd9Sstevel@tonic-gate 	char *soft = strtok_r(arg, " \t,", &lastc);
320*7c478bd9Sstevel@tonic-gate 	char *hard = strtok_r(NULL, " \t", &lastc);
321*7c478bd9Sstevel@tonic-gate 	struct rlimit64 *rp = &rlimit[which];
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	if (hard != NULL && strtok_r(NULL, " \t", &lastc) != NULL)
324*7c478bd9Sstevel@tonic-gate 		return (1);
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 	if (soft == NULL || *soft == '\0') {
327*7c478bd9Sstevel@tonic-gate 		rp->rlim_cur = 0;
328*7c478bd9Sstevel@tonic-gate 		set_current[which] = FALSE;
329*7c478bd9Sstevel@tonic-gate 	} else {
330*7c478bd9Sstevel@tonic-gate 		if (limit_value(which, soft, &rp->rlim_cur) != 0)
331*7c478bd9Sstevel@tonic-gate 			return (1);
332*7c478bd9Sstevel@tonic-gate 		set_current[which] = TRUE;
333*7c478bd9Sstevel@tonic-gate 	}
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 	if (hard == NULL || *hard == '\0') {
336*7c478bd9Sstevel@tonic-gate 		rp->rlim_max = 0;
337*7c478bd9Sstevel@tonic-gate 		set_maximum[which] = FALSE;
338*7c478bd9Sstevel@tonic-gate 	} else {
339*7c478bd9Sstevel@tonic-gate 		if (limit_value(which, hard, &rp->rlim_max) != 0)
340*7c478bd9Sstevel@tonic-gate 			return (1);
341*7c478bd9Sstevel@tonic-gate 		set_maximum[which] = TRUE;
342*7c478bd9Sstevel@tonic-gate 	}
343*7c478bd9Sstevel@tonic-gate 	if (set_current[which] && set_maximum[which] &&
344*7c478bd9Sstevel@tonic-gate 	    rp->rlim_cur > rp->rlim_max)
345*7c478bd9Sstevel@tonic-gate 		return (1);
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 	return (0);
348*7c478bd9Sstevel@tonic-gate }
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate static void
limit_adjust(struct rlimit64 * rp,int units)351*7c478bd9Sstevel@tonic-gate limit_adjust(struct rlimit64 *rp, int units)
352*7c478bd9Sstevel@tonic-gate {
353*7c478bd9Sstevel@tonic-gate 	if (rp->rlim_cur != RLIM64_INFINITY)
354*7c478bd9Sstevel@tonic-gate 		rp->rlim_cur /= units;
355*7c478bd9Sstevel@tonic-gate 	if (rp->rlim_max != RLIM64_INFINITY)
356*7c478bd9Sstevel@tonic-gate 		rp->rlim_max /= units;
357*7c478bd9Sstevel@tonic-gate }
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate static char *
limit_values(struct rlimit64 * rp)360*7c478bd9Sstevel@tonic-gate limit_values(struct rlimit64 *rp)
361*7c478bd9Sstevel@tonic-gate {
362*7c478bd9Sstevel@tonic-gate 	static char buffer[64];
363*7c478bd9Sstevel@tonic-gate 	char buf1[32];
364*7c478bd9Sstevel@tonic-gate 	char buf2[32];
365*7c478bd9Sstevel@tonic-gate 	char *s1;
366*7c478bd9Sstevel@tonic-gate 	char *s2;
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 	if (rp->rlim_cur == RLIM64_INFINITY)
369*7c478bd9Sstevel@tonic-gate 		s1 = "unlimited";
370*7c478bd9Sstevel@tonic-gate 	else {
371*7c478bd9Sstevel@tonic-gate 		(void) sprintf(s1 = buf1, "%lld", rp->rlim_cur);
372*7c478bd9Sstevel@tonic-gate 		if (strlen(s1) < 8)
373*7c478bd9Sstevel@tonic-gate 			(void) strcat(s1, "\t");
374*7c478bd9Sstevel@tonic-gate 	}
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate 	if (rp->rlim_max == RLIM64_INFINITY)
377*7c478bd9Sstevel@tonic-gate 		s2 = "unlimited";
378*7c478bd9Sstevel@tonic-gate 	else {
379*7c478bd9Sstevel@tonic-gate 		(void) sprintf(s2 = buf2, "%lld", rp->rlim_max);
380*7c478bd9Sstevel@tonic-gate 	}
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate 	(void) sprintf(buffer, "%s\t%s", s1, s2);
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	return (buffer);
385*7c478bd9Sstevel@tonic-gate }
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate static void
show_limits(struct ps_prochandle * Pr)388*7c478bd9Sstevel@tonic-gate show_limits(struct ps_prochandle *Pr)
389*7c478bd9Sstevel@tonic-gate {
390*7c478bd9Sstevel@tonic-gate 	struct rlimit64 rlim;
391*7c478bd9Sstevel@tonic-gate 	int resource;
392*7c478bd9Sstevel@tonic-gate 	char buf[32];
393*7c478bd9Sstevel@tonic-gate 	char *s;
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 	(void) printf("   resource\t\t current\t maximum\n");
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 	for (resource = 0; resource < RLIM_NLIMITS; resource++) {
398*7c478bd9Sstevel@tonic-gate 		if (pr_getrlimit64(Pr, resource, &rlim) != 0)
399*7c478bd9Sstevel@tonic-gate 			continue;
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 		switch (resource) {
402*7c478bd9Sstevel@tonic-gate 		case RLIMIT_CPU:
403*7c478bd9Sstevel@tonic-gate 			s = "  time(seconds)\t\t";
404*7c478bd9Sstevel@tonic-gate 			break;
405*7c478bd9Sstevel@tonic-gate 		case RLIMIT_FSIZE:
406*7c478bd9Sstevel@tonic-gate 			if (kbytes) {
407*7c478bd9Sstevel@tonic-gate 				s = "  file(kbytes)\t\t";
408*7c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024);
409*7c478bd9Sstevel@tonic-gate 			} else if (mbytes) {
410*7c478bd9Sstevel@tonic-gate 				s = "  file(mbytes)\t\t";
411*7c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024 * 1024);
412*7c478bd9Sstevel@tonic-gate 			} else {
413*7c478bd9Sstevel@tonic-gate 				s = "  file(blocks)\t\t";
414*7c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 512);
415*7c478bd9Sstevel@tonic-gate 			}
416*7c478bd9Sstevel@tonic-gate 			break;
417*7c478bd9Sstevel@tonic-gate 		case RLIMIT_DATA:
418*7c478bd9Sstevel@tonic-gate 			if (mbytes) {
419*7c478bd9Sstevel@tonic-gate 				s = "  data(mbytes)\t\t";
420*7c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024 * 1024);
421*7c478bd9Sstevel@tonic-gate 			} else {
422*7c478bd9Sstevel@tonic-gate 				s = "  data(kbytes)\t\t";
423*7c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024);
424*7c478bd9Sstevel@tonic-gate 			}
425*7c478bd9Sstevel@tonic-gate 			break;
426*7c478bd9Sstevel@tonic-gate 		case RLIMIT_STACK:
427*7c478bd9Sstevel@tonic-gate 			if (mbytes) {
428*7c478bd9Sstevel@tonic-gate 				s = "  stack(mbytes)\t\t";
429*7c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024 * 1024);
430*7c478bd9Sstevel@tonic-gate 			} else {
431*7c478bd9Sstevel@tonic-gate 				s = "  stack(kbytes)\t\t";
432*7c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024);
433*7c478bd9Sstevel@tonic-gate 			}
434*7c478bd9Sstevel@tonic-gate 			break;
435*7c478bd9Sstevel@tonic-gate 		case RLIMIT_CORE:
436*7c478bd9Sstevel@tonic-gate 			if (kbytes) {
437*7c478bd9Sstevel@tonic-gate 				s = "  coredump(kbytes)\t";
438*7c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024);
439*7c478bd9Sstevel@tonic-gate 			} else if (mbytes) {
440*7c478bd9Sstevel@tonic-gate 				s = "  coredump(mbytes)\t";
441*7c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024 * 1024);
442*7c478bd9Sstevel@tonic-gate 			} else {
443*7c478bd9Sstevel@tonic-gate 				s = "  coredump(blocks)\t";
444*7c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 512);
445*7c478bd9Sstevel@tonic-gate 			}
446*7c478bd9Sstevel@tonic-gate 			break;
447*7c478bd9Sstevel@tonic-gate 		case RLIMIT_NOFILE:
448*7c478bd9Sstevel@tonic-gate 			s = "  nofiles(descriptors)\t";
449*7c478bd9Sstevel@tonic-gate 			break;
450*7c478bd9Sstevel@tonic-gate 		case RLIMIT_VMEM:
451*7c478bd9Sstevel@tonic-gate 			if (mbytes) {
452*7c478bd9Sstevel@tonic-gate 				s = "  vmemory(mbytes)\t";
453*7c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024 * 1024);
454*7c478bd9Sstevel@tonic-gate 			} else {
455*7c478bd9Sstevel@tonic-gate 				s = "  vmemory(kbytes)\t";
456*7c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024);
457*7c478bd9Sstevel@tonic-gate 			}
458*7c478bd9Sstevel@tonic-gate 			break;
459*7c478bd9Sstevel@tonic-gate 		default:
460*7c478bd9Sstevel@tonic-gate 			(void) sprintf(buf, "  rlimit #%d\t", resource);
461*7c478bd9Sstevel@tonic-gate 			s = buf;
462*7c478bd9Sstevel@tonic-gate 			break;
463*7c478bd9Sstevel@tonic-gate 		}
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 		(void) printf("%s%s\n", s, limit_values(&rlim));
466*7c478bd9Sstevel@tonic-gate 	}
467*7c478bd9Sstevel@tonic-gate }
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate static int
set_one_limit(struct ps_prochandle * Pr,int which,rlim64_t cur,rlim64_t max)470*7c478bd9Sstevel@tonic-gate set_one_limit(struct ps_prochandle *Pr, int which, rlim64_t cur, rlim64_t max)
471*7c478bd9Sstevel@tonic-gate {
472*7c478bd9Sstevel@tonic-gate 	struct rlimit64 rlim;
473*7c478bd9Sstevel@tonic-gate 	int be_su = 0;
474*7c478bd9Sstevel@tonic-gate 	prpriv_t *old_prpriv = NULL, *new_prpriv = NULL;
475*7c478bd9Sstevel@tonic-gate 	priv_set_t *eset, *pset;
476*7c478bd9Sstevel@tonic-gate 	int ret = 0;
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 	if (pr_getrlimit64(Pr, which, &rlim) != 0) {
479*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
480*7c478bd9Sstevel@tonic-gate 		    "%s: unable to get process limit for pid %d: %s\n",
481*7c478bd9Sstevel@tonic-gate 		    command, Pstatus(Pr)->pr_pid, strerror(errno));
482*7c478bd9Sstevel@tonic-gate 		return (1);
483*7c478bd9Sstevel@tonic-gate 	}
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 	if (!set_current[which])
486*7c478bd9Sstevel@tonic-gate 		cur = rlim.rlim_cur;
487*7c478bd9Sstevel@tonic-gate 	if (!set_maximum[which])
488*7c478bd9Sstevel@tonic-gate 		max = rlim.rlim_max;
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 	if (max < cur)
491*7c478bd9Sstevel@tonic-gate 		max = cur;
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 	if (max > rlim.rlim_max && Pr != NULL)
494*7c478bd9Sstevel@tonic-gate 		be_su = 1;
495*7c478bd9Sstevel@tonic-gate 	rlim.rlim_cur = cur;
496*7c478bd9Sstevel@tonic-gate 	rlim.rlim_max = max;
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 	if (be_su) {
499*7c478bd9Sstevel@tonic-gate 		new_prpriv = proc_get_priv(Pstatus(Pr)->pr_pid);
500*7c478bd9Sstevel@tonic-gate 		if (new_prpriv == NULL) {
501*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
502*7c478bd9Sstevel@tonic-gate 			    "%s: unable to get process privileges for pid"
503*7c478bd9Sstevel@tonic-gate 			    " %d: %s\n", command, Pstatus(Pr)->pr_pid,
504*7c478bd9Sstevel@tonic-gate 			    strerror(errno));
505*7c478bd9Sstevel@tonic-gate 			return (1);
506*7c478bd9Sstevel@tonic-gate 		}
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 		/*
509*7c478bd9Sstevel@tonic-gate 		 * We only have to change the process privileges if it doesn't
510*7c478bd9Sstevel@tonic-gate 		 * already have PRIV_SYS_RESOURCE.  In addition, we want to make
511*7c478bd9Sstevel@tonic-gate 		 * sure that we don't leave a process with elevated privileges,
512*7c478bd9Sstevel@tonic-gate 		 * so we make sure the process dies if we exit unexpectedly.
513*7c478bd9Sstevel@tonic-gate 		 */
514*7c478bd9Sstevel@tonic-gate 		eset = (priv_set_t *)
515*7c478bd9Sstevel@tonic-gate 		    &new_prpriv->pr_sets[new_prpriv->pr_setsize *
516*7c478bd9Sstevel@tonic-gate 		    priv_getsetbyname(PRIV_EFFECTIVE)];
517*7c478bd9Sstevel@tonic-gate 		pset = (priv_set_t *)
518*7c478bd9Sstevel@tonic-gate 		    &new_prpriv->pr_sets[new_prpriv->pr_setsize *
519*7c478bd9Sstevel@tonic-gate 		    priv_getsetbyname(PRIV_PERMITTED)];
520*7c478bd9Sstevel@tonic-gate 		if (!priv_ismember(eset, PRIV_SYS_RESOURCE)) {
521*7c478bd9Sstevel@tonic-gate 			/* Keep track of original privileges */
522*7c478bd9Sstevel@tonic-gate 			old_prpriv = proc_get_priv(Pstatus(Pr)->pr_pid);
523*7c478bd9Sstevel@tonic-gate 			if (old_prpriv == NULL) {
524*7c478bd9Sstevel@tonic-gate 				free(new_prpriv);
525*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
526*7c478bd9Sstevel@tonic-gate 				    "%s: unable to get process privileges "
527*7c478bd9Sstevel@tonic-gate 				    "for pid %d: %s\n", command,
528*7c478bd9Sstevel@tonic-gate 				    Pstatus(Pr)->pr_pid, strerror(errno));
529*7c478bd9Sstevel@tonic-gate 				return (1);
530*7c478bd9Sstevel@tonic-gate 			}
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 			(void) priv_addset(eset, PRIV_SYS_RESOURCE);
533*7c478bd9Sstevel@tonic-gate 			(void) priv_addset(pset, PRIV_SYS_RESOURCE);
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 			if (Psetflags(Pr, PR_KLC) != 0 ||
536*7c478bd9Sstevel@tonic-gate 			    Psetpriv(Pr, new_prpriv) != 0) {
537*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
538*7c478bd9Sstevel@tonic-gate 				    "%s: unable to set process privileges for"
539*7c478bd9Sstevel@tonic-gate 				    " pid %d: %s\n", command,
540*7c478bd9Sstevel@tonic-gate 				    Pstatus(Pr)->pr_pid, strerror(errno));
541*7c478bd9Sstevel@tonic-gate 				(void) Punsetflags(Pr, PR_KLC);
542*7c478bd9Sstevel@tonic-gate 				free(new_prpriv);
543*7c478bd9Sstevel@tonic-gate 				free(old_prpriv);
544*7c478bd9Sstevel@tonic-gate 				return (1);
545*7c478bd9Sstevel@tonic-gate 			}
546*7c478bd9Sstevel@tonic-gate 		}
547*7c478bd9Sstevel@tonic-gate 	}
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate 	if (pr_setrlimit64(Pr, which, &rlim) != 0) {
550*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
551*7c478bd9Sstevel@tonic-gate 		    "%s: cannot set resource limit for pid %d: %s\n",
552*7c478bd9Sstevel@tonic-gate 		    command, Pstatus(Pr)->pr_pid, strerror(errno));
553*7c478bd9Sstevel@tonic-gate 		ret = 1;
554*7c478bd9Sstevel@tonic-gate 	}
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate 	if (old_prpriv != NULL) {
557*7c478bd9Sstevel@tonic-gate 		if (Psetpriv(Pr, old_prpriv) != 0) {
558*7c478bd9Sstevel@tonic-gate 			/*
559*7c478bd9Sstevel@tonic-gate 			 * If this fails, we can't leave a process hanging
560*7c478bd9Sstevel@tonic-gate 			 * around with elevated privileges, so we'll have to
561*7c478bd9Sstevel@tonic-gate 			 * release the process from libproc, knowing that it
562*7c478bd9Sstevel@tonic-gate 			 * will be killed (since we set PR_KLC).
563*7c478bd9Sstevel@tonic-gate 			 */
564*7c478bd9Sstevel@tonic-gate 			Pdestroy_agent(Pr);
565*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
566*7c478bd9Sstevel@tonic-gate 			    "%s: cannot relinquish privileges for pid %d."
567*7c478bd9Sstevel@tonic-gate 			    " The process was killed.",
568*7c478bd9Sstevel@tonic-gate 			    command, Pstatus(Pr)->pr_pid);
569*7c478bd9Sstevel@tonic-gate 			ret = 1;
570*7c478bd9Sstevel@tonic-gate 		}
571*7c478bd9Sstevel@tonic-gate 		if (Punsetflags(Pr, PR_KLC) != 0) {
572*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
573*7c478bd9Sstevel@tonic-gate 			    "%s: cannot relinquish privileges for pid %d."
574*7c478bd9Sstevel@tonic-gate 			    " The process was killed.",
575*7c478bd9Sstevel@tonic-gate 			    command, Pstatus(Pr)->pr_pid);
576*7c478bd9Sstevel@tonic-gate 			ret = 1;
577*7c478bd9Sstevel@tonic-gate 		}
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate 		free(old_prpriv);
580*7c478bd9Sstevel@tonic-gate 	}
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 	if (new_prpriv != NULL)
583*7c478bd9Sstevel@tonic-gate 		free(new_prpriv);
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate 	return (ret);
586*7c478bd9Sstevel@tonic-gate }
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate static int
set_limits(struct ps_prochandle * Pr)589*7c478bd9Sstevel@tonic-gate set_limits(struct ps_prochandle *Pr)
590*7c478bd9Sstevel@tonic-gate {
591*7c478bd9Sstevel@tonic-gate 	int which;
592*7c478bd9Sstevel@tonic-gate 	int retc = 0;
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 	for (which = 0; which < RLIM_NLIMITS; which++) {
595*7c478bd9Sstevel@tonic-gate 		if (set_current[which] || set_maximum[which]) {
596*7c478bd9Sstevel@tonic-gate 			if (set_one_limit(Pr, which, rlimit[which].rlim_cur,
597*7c478bd9Sstevel@tonic-gate 			    rlimit[which].rlim_max) != 0)
598*7c478bd9Sstevel@tonic-gate 				retc = 1;
599*7c478bd9Sstevel@tonic-gate 		}
600*7c478bd9Sstevel@tonic-gate 	}
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 	return (retc);
603*7c478bd9Sstevel@tonic-gate }
604