xref: /illumos-gate/usr/src/cmd/plimit/plimit.c (revision 43051d2742bbe5911de73322064cb573b6aff975)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
26*43051d27SRobert Mustacchi /*
27*43051d27SRobert Mustacchi  * Copyright 2015, Joyent, Inc.
28*43051d27SRobert Mustacchi  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #define	__EXTENSIONS__	/* For strtok_r */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <stdio.h>
337c478bd9Sstevel@tonic-gate #include <stdlib.h>
347c478bd9Sstevel@tonic-gate #include <unistd.h>
357c478bd9Sstevel@tonic-gate #include <fcntl.h>
367c478bd9Sstevel@tonic-gate #include <ctype.h>
377c478bd9Sstevel@tonic-gate #include <string.h>
387c478bd9Sstevel@tonic-gate #include <signal.h>
397c478bd9Sstevel@tonic-gate #include <limits.h>
407c478bd9Sstevel@tonic-gate #include <errno.h>
417c478bd9Sstevel@tonic-gate #include <sys/types.h>
427c478bd9Sstevel@tonic-gate #include <sys/stat.h>
437c478bd9Sstevel@tonic-gate #include <sys/mman.h>
447c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
457c478bd9Sstevel@tonic-gate #include <libproc.h>
467c478bd9Sstevel@tonic-gate #include <priv.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #define	TRUE	1
497c478bd9Sstevel@tonic-gate #define	FALSE	0
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate static	int	interrupt;
527c478bd9Sstevel@tonic-gate static	char	*command;
537c478bd9Sstevel@tonic-gate static	int	Fflag;
547c478bd9Sstevel@tonic-gate static	int	kbytes = FALSE;
557c478bd9Sstevel@tonic-gate static	int	mbytes = FALSE;
567c478bd9Sstevel@tonic-gate static	char	set_current[RLIM_NLIMITS];
577c478bd9Sstevel@tonic-gate static	char	set_maximum[RLIM_NLIMITS];
587c478bd9Sstevel@tonic-gate static	struct rlimit64 rlimit[RLIM_NLIMITS];
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate static	void	intr(int);
617c478bd9Sstevel@tonic-gate static	int	parse_limits(int, char *);
627c478bd9Sstevel@tonic-gate static	void	show_limits(struct ps_prochandle *);
637c478bd9Sstevel@tonic-gate static	int	set_limits(struct ps_prochandle *);
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate static void
667c478bd9Sstevel@tonic-gate usage()
677c478bd9Sstevel@tonic-gate {
687c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
69*43051d27SRobert Mustacchi 	    "usage:\n"
70*43051d27SRobert Mustacchi 	    "    For each process, report all resource limits:\n"
71*43051d27SRobert Mustacchi 	    "\t%s [-km] pid ...\n"
72*43051d27SRobert Mustacchi 	    "\t-k\treport file sizes in kilobytes\n"
73*43051d27SRobert Mustacchi 	    "\t-m\treport file/memory sizes in megabytes\n"
74*43051d27SRobert Mustacchi 	    "    For each process, set specified resource limits:\n"
75*43051d27SRobert Mustacchi 	    "\t%s -{cdfnstv} soft,hard ... pid ...\n"
76*43051d27SRobert Mustacchi 	    "\t-c soft,hard\tset core file size limits\n"
77*43051d27SRobert Mustacchi 	    "\t-d soft,hard\tset data segment (heap) size limits\n"
78*43051d27SRobert Mustacchi 	    "\t-f soft,hard\tset file size limits\n"
79*43051d27SRobert Mustacchi 	    "\t-n soft,hard\tset file descriptor limits\n"
80*43051d27SRobert Mustacchi 	    "\t-s soft,hard\tset stack segment size limits\n"
81*43051d27SRobert Mustacchi 	    "\t-t soft,hard\tset CPU time limits\n"
82*43051d27SRobert Mustacchi 	    "\t-v soft,hard\tset virtual memory size limits\n"
83*43051d27SRobert Mustacchi 	    "\t(default units are as shown by the output of '%s pid')\n",
84*43051d27SRobert Mustacchi 	    command, command, command);
857c478bd9Sstevel@tonic-gate 	exit(2);
867c478bd9Sstevel@tonic-gate }
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate int
897c478bd9Sstevel@tonic-gate main(int argc, char **argv)
907c478bd9Sstevel@tonic-gate {
917c478bd9Sstevel@tonic-gate 	int retc = 0;
927c478bd9Sstevel@tonic-gate 	int opt;
937c478bd9Sstevel@tonic-gate 	int errflg = 0;
947c478bd9Sstevel@tonic-gate 	int set = FALSE;
957c478bd9Sstevel@tonic-gate 	struct ps_prochandle *Pr;
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	if ((command = strrchr(argv[0], '/')) != NULL)
987c478bd9Sstevel@tonic-gate 		command++;
997c478bd9Sstevel@tonic-gate 	else
1007c478bd9Sstevel@tonic-gate 		command = argv[0];
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "Fkmc:d:f:n:s:t:v:")) != EOF) {
1037c478bd9Sstevel@tonic-gate 		switch (opt) {
1047c478bd9Sstevel@tonic-gate 		case 'F':		/* force grabbing (no O_EXCL) */
1057c478bd9Sstevel@tonic-gate 			Fflag = PGRAB_FORCE;
1067c478bd9Sstevel@tonic-gate 			break;
1077c478bd9Sstevel@tonic-gate 		case 'k':
1087c478bd9Sstevel@tonic-gate 			kbytes = TRUE;
1097c478bd9Sstevel@tonic-gate 			mbytes = FALSE;
1107c478bd9Sstevel@tonic-gate 			break;
1117c478bd9Sstevel@tonic-gate 		case 'm':
1127c478bd9Sstevel@tonic-gate 			kbytes = FALSE;
1137c478bd9Sstevel@tonic-gate 			mbytes = TRUE;
1147c478bd9Sstevel@tonic-gate 			break;
1157c478bd9Sstevel@tonic-gate 		case 'c':	/* core file size */
1167c478bd9Sstevel@tonic-gate 			set = TRUE;
1177c478bd9Sstevel@tonic-gate 			errflg += parse_limits(RLIMIT_CORE, optarg);
1187c478bd9Sstevel@tonic-gate 			break;
1197c478bd9Sstevel@tonic-gate 		case 'd':	/* data segment size */
1207c478bd9Sstevel@tonic-gate 			set = TRUE;
1217c478bd9Sstevel@tonic-gate 			errflg += parse_limits(RLIMIT_DATA, optarg);
1227c478bd9Sstevel@tonic-gate 			break;
1237c478bd9Sstevel@tonic-gate 		case 'f':	/* file size */
1247c478bd9Sstevel@tonic-gate 			set = TRUE;
1257c478bd9Sstevel@tonic-gate 			errflg += parse_limits(RLIMIT_FSIZE, optarg);
1267c478bd9Sstevel@tonic-gate 			break;
1277c478bd9Sstevel@tonic-gate 		case 'n':	/* file descriptors */
1287c478bd9Sstevel@tonic-gate 			set = TRUE;
1297c478bd9Sstevel@tonic-gate 			errflg += parse_limits(RLIMIT_NOFILE, optarg);
1307c478bd9Sstevel@tonic-gate 			break;
1317c478bd9Sstevel@tonic-gate 		case 's':	/* stack segment size */
1327c478bd9Sstevel@tonic-gate 			set = TRUE;
1337c478bd9Sstevel@tonic-gate 			errflg += parse_limits(RLIMIT_STACK, optarg);
1347c478bd9Sstevel@tonic-gate 			break;
1357c478bd9Sstevel@tonic-gate 		case 't':	/* CPU time */
1367c478bd9Sstevel@tonic-gate 			set = TRUE;
1377c478bd9Sstevel@tonic-gate 			errflg += parse_limits(RLIMIT_CPU, optarg);
1387c478bd9Sstevel@tonic-gate 			break;
1397c478bd9Sstevel@tonic-gate 		case 'v':	/* virtual memory size */
1407c478bd9Sstevel@tonic-gate 			set = TRUE;
1417c478bd9Sstevel@tonic-gate 			errflg += parse_limits(RLIMIT_VMEM, optarg);
1427c478bd9Sstevel@tonic-gate 			break;
1437c478bd9Sstevel@tonic-gate 		default:
1447c478bd9Sstevel@tonic-gate 			errflg = 1;
1457c478bd9Sstevel@tonic-gate 			break;
1467c478bd9Sstevel@tonic-gate 		}
1477c478bd9Sstevel@tonic-gate 	}
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	argc -= optind;
1507c478bd9Sstevel@tonic-gate 	argv += optind;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	if (errflg || argc <= 0)
1537c478bd9Sstevel@tonic-gate 		usage();
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	/* catch signals from terminal */
1567c478bd9Sstevel@tonic-gate 	if (sigset(SIGHUP, SIG_IGN) == SIG_DFL)
1577c478bd9Sstevel@tonic-gate 		(void) sigset(SIGHUP, intr);
1587c478bd9Sstevel@tonic-gate 	if (sigset(SIGINT, SIG_IGN) == SIG_DFL)
1597c478bd9Sstevel@tonic-gate 		(void) sigset(SIGINT, intr);
1607c478bd9Sstevel@tonic-gate 	if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL)
1617c478bd9Sstevel@tonic-gate 		(void) sigset(SIGQUIT, intr);
1627c478bd9Sstevel@tonic-gate 	(void) sigset(SIGPIPE, intr);
1637c478bd9Sstevel@tonic-gate 	(void) sigset(SIGTERM, intr);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	while (--argc >= 0 && !interrupt) {
1667c478bd9Sstevel@tonic-gate 		psinfo_t psinfo;
1677c478bd9Sstevel@tonic-gate 		char *arg;
1687c478bd9Sstevel@tonic-gate 		pid_t pid;
1697c478bd9Sstevel@tonic-gate 		int gret;
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);	/* process-at-a-time */
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 		/* get the specified pid and the psinfo struct */
1747c478bd9Sstevel@tonic-gate 		if ((pid = proc_arg_psinfo(arg = *argv++, PR_ARG_PIDS,
1757c478bd9Sstevel@tonic-gate 		    &psinfo, &gret)) == -1) {
1767c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: cannot examine %s: %s\n",
177*43051d27SRobert Mustacchi 			    command, arg, Pgrab_error(gret));
1787c478bd9Sstevel@tonic-gate 			retc = 1;
1797c478bd9Sstevel@tonic-gate 		} else if ((Pr = Pgrab(pid, Fflag, &gret)) != NULL) {
1807c478bd9Sstevel@tonic-gate 			if (Pcreate_agent(Pr) == 0) {
1817c478bd9Sstevel@tonic-gate 				if (set) {
1827c478bd9Sstevel@tonic-gate 					if (set_limits(Pr) != 0)
1837c478bd9Sstevel@tonic-gate 						retc = 1;
1847c478bd9Sstevel@tonic-gate 				} else {
1857c478bd9Sstevel@tonic-gate 					proc_unctrl_psinfo(&psinfo);
1867c478bd9Sstevel@tonic-gate 					(void) printf("%d:\t%.70s\n",
187*43051d27SRobert Mustacchi 					    (int)pid, psinfo.pr_psargs);
1887c478bd9Sstevel@tonic-gate 					show_limits(Pr);
1897c478bd9Sstevel@tonic-gate 				}
1907c478bd9Sstevel@tonic-gate 				Pdestroy_agent(Pr);
1917c478bd9Sstevel@tonic-gate 			} else {
1927c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
193*43051d27SRobert Mustacchi 				    "%s: cannot control process %d\n",
194*43051d27SRobert Mustacchi 				    command, (int)pid);
1957c478bd9Sstevel@tonic-gate 				retc = 1;
1967c478bd9Sstevel@tonic-gate 			}
1977c478bd9Sstevel@tonic-gate 			Prelease(Pr, 0);
1987c478bd9Sstevel@tonic-gate 		} else {
1997c478bd9Sstevel@tonic-gate 			if ((gret == G_SYS || gret == G_SELF) && !set) {
2007c478bd9Sstevel@tonic-gate 				proc_unctrl_psinfo(&psinfo);
2017c478bd9Sstevel@tonic-gate 				(void) printf("%d:\t%.70s\n", (int)pid,
202*43051d27SRobert Mustacchi 				    psinfo.pr_psargs);
2037c478bd9Sstevel@tonic-gate 				if (gret == G_SYS)
2047c478bd9Sstevel@tonic-gate 					(void) printf("  [system process]\n");
2057c478bd9Sstevel@tonic-gate 				else
2067c478bd9Sstevel@tonic-gate 					show_limits(NULL);
2077c478bd9Sstevel@tonic-gate 			} else {
2087c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
209*43051d27SRobert Mustacchi 				    "%s: %s: %d\n",
210*43051d27SRobert Mustacchi 				    command, Pgrab_error(gret), (int)pid);
2117c478bd9Sstevel@tonic-gate 				retc = 1;
2127c478bd9Sstevel@tonic-gate 			}
2137c478bd9Sstevel@tonic-gate 		}
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	if (interrupt)
2177c478bd9Sstevel@tonic-gate 		retc = 1;
2187c478bd9Sstevel@tonic-gate 	return (retc);
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate static void
2227c478bd9Sstevel@tonic-gate intr(int sig)
2237c478bd9Sstevel@tonic-gate {
2247c478bd9Sstevel@tonic-gate 	interrupt = sig;
2257c478bd9Sstevel@tonic-gate }
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate /* ------ begin specific code ------ */
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate /*
2307c478bd9Sstevel@tonic-gate  * Compute a limit, given a string:
2317c478bd9Sstevel@tonic-gate  *	unlimited	unlimited
2327c478bd9Sstevel@tonic-gate  *	nnn k		nnn kilobytes
2337c478bd9Sstevel@tonic-gate  *	nnn m		nnn megabytes (minutes for CPU time)
2347c478bd9Sstevel@tonic-gate  *	nnn h		nnn hours (for CPU time only)
2357c478bd9Sstevel@tonic-gate  *	mm : ss		minutes and seconds (for CPU time only)
2367c478bd9Sstevel@tonic-gate  */
2377c478bd9Sstevel@tonic-gate static int
2387c478bd9Sstevel@tonic-gate limit_value(int which, char *arg, rlim64_t *limit)
2397c478bd9Sstevel@tonic-gate {
2407c478bd9Sstevel@tonic-gate 	rlim64_t value;
2417c478bd9Sstevel@tonic-gate 	rlim64_t unit;
2427c478bd9Sstevel@tonic-gate 	char *lastc;
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	if (strcmp(arg, "unlimited") == 0) {
2457c478bd9Sstevel@tonic-gate 		*limit = RLIM64_INFINITY;
2467c478bd9Sstevel@tonic-gate 		return (0);
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	if (which == RLIMIT_CPU && strchr(arg, ':') != NULL) {
2507c478bd9Sstevel@tonic-gate 		char *minutes = strtok_r(arg, " \t:", &lastc);
2517c478bd9Sstevel@tonic-gate 		char *seconds = strtok_r(NULL, " \t", &lastc);
2527c478bd9Sstevel@tonic-gate 		rlim64_t sec;
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 		if (seconds != NULL && strtok_r(NULL, " \t", &lastc) != NULL)
2557c478bd9Sstevel@tonic-gate 			return (1);
2567c478bd9Sstevel@tonic-gate 		value = strtoull(minutes, &lastc, 10);
2577c478bd9Sstevel@tonic-gate 		if (*lastc != '\0' || value > RLIM64_INFINITY / 60)
2587c478bd9Sstevel@tonic-gate 			return (1);
2597c478bd9Sstevel@tonic-gate 		if (seconds == NULL || *seconds == '\0')
2607c478bd9Sstevel@tonic-gate 			sec = 0;
2617c478bd9Sstevel@tonic-gate 		else {
2627c478bd9Sstevel@tonic-gate 			sec = strtoull(seconds, &lastc, 10);
2637c478bd9Sstevel@tonic-gate 			if (*lastc != '\0' || sec > 60)
2647c478bd9Sstevel@tonic-gate 				return (1);
2657c478bd9Sstevel@tonic-gate 		}
2667c478bd9Sstevel@tonic-gate 		value = value * 60 + sec;
2677c478bd9Sstevel@tonic-gate 		if (value > RLIM64_INFINITY)
2687c478bd9Sstevel@tonic-gate 			value = RLIM64_INFINITY;
2697c478bd9Sstevel@tonic-gate 		*limit = value;
2707c478bd9Sstevel@tonic-gate 		return (0);
2717c478bd9Sstevel@tonic-gate 	}
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 	switch (*(lastc = arg + strlen(arg) - 1)) {
2747c478bd9Sstevel@tonic-gate 	case 'k':
2757c478bd9Sstevel@tonic-gate 		unit = 1024;
2767c478bd9Sstevel@tonic-gate 		*lastc = '\0';
2777c478bd9Sstevel@tonic-gate 		break;
2787c478bd9Sstevel@tonic-gate 	case 'm':
2797c478bd9Sstevel@tonic-gate 		if (which == RLIMIT_CPU)
2807c478bd9Sstevel@tonic-gate 			unit = 60;
2817c478bd9Sstevel@tonic-gate 		else
2827c478bd9Sstevel@tonic-gate 			unit = 1024 * 1024;
2837c478bd9Sstevel@tonic-gate 		*lastc = '\0';
2847c478bd9Sstevel@tonic-gate 		break;
2857c478bd9Sstevel@tonic-gate 	case 'h':
2867c478bd9Sstevel@tonic-gate 		if (which == RLIMIT_CPU)
2877c478bd9Sstevel@tonic-gate 			unit = 60 * 60;
2887c478bd9Sstevel@tonic-gate 		else
2897c478bd9Sstevel@tonic-gate 			return (1);
2907c478bd9Sstevel@tonic-gate 		*lastc = '\0';
2917c478bd9Sstevel@tonic-gate 		break;
2927c478bd9Sstevel@tonic-gate 	default:
2937c478bd9Sstevel@tonic-gate 		switch (which) {
2947c478bd9Sstevel@tonic-gate 		case RLIMIT_CPU:	unit = 1;	break;
2957c478bd9Sstevel@tonic-gate 		case RLIMIT_FSIZE:	unit = 512;	break;
2967c478bd9Sstevel@tonic-gate 		case RLIMIT_DATA:	unit = 1024;	break;
2977c478bd9Sstevel@tonic-gate 		case RLIMIT_STACK:	unit = 1024;	break;
2987c478bd9Sstevel@tonic-gate 		case RLIMIT_CORE:	unit = 512;	break;
2997c478bd9Sstevel@tonic-gate 		case RLIMIT_NOFILE:	unit = 1;	break;
3007c478bd9Sstevel@tonic-gate 		case RLIMIT_VMEM:	unit = 1024;	break;
3017c478bd9Sstevel@tonic-gate 		}
3027c478bd9Sstevel@tonic-gate 		break;
3037c478bd9Sstevel@tonic-gate 	}
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	value = strtoull(arg, &lastc, 10);
3067c478bd9Sstevel@tonic-gate 	if (*lastc != '\0' || value > RLIM64_INFINITY / unit)
3077c478bd9Sstevel@tonic-gate 		return (1);
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	value *= unit;
3107c478bd9Sstevel@tonic-gate 	if (value > RLIM64_INFINITY)
3117c478bd9Sstevel@tonic-gate 		value = RLIM64_INFINITY;
3127c478bd9Sstevel@tonic-gate 	*limit = value;
3137c478bd9Sstevel@tonic-gate 	return (0);
3147c478bd9Sstevel@tonic-gate }
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate static int
3177c478bd9Sstevel@tonic-gate parse_limits(int which, char *arg)
3187c478bd9Sstevel@tonic-gate {
3197c478bd9Sstevel@tonic-gate 	char *lastc;
3207c478bd9Sstevel@tonic-gate 	char *soft = strtok_r(arg, " \t,", &lastc);
3217c478bd9Sstevel@tonic-gate 	char *hard = strtok_r(NULL, " \t", &lastc);
3227c478bd9Sstevel@tonic-gate 	struct rlimit64 *rp = &rlimit[which];
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	if (hard != NULL && strtok_r(NULL, " \t", &lastc) != NULL)
3257c478bd9Sstevel@tonic-gate 		return (1);
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	if (soft == NULL || *soft == '\0') {
3287c478bd9Sstevel@tonic-gate 		rp->rlim_cur = 0;
3297c478bd9Sstevel@tonic-gate 		set_current[which] = FALSE;
3307c478bd9Sstevel@tonic-gate 	} else {
3317c478bd9Sstevel@tonic-gate 		if (limit_value(which, soft, &rp->rlim_cur) != 0)
3327c478bd9Sstevel@tonic-gate 			return (1);
3337c478bd9Sstevel@tonic-gate 		set_current[which] = TRUE;
3347c478bd9Sstevel@tonic-gate 	}
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	if (hard == NULL || *hard == '\0') {
3377c478bd9Sstevel@tonic-gate 		rp->rlim_max = 0;
3387c478bd9Sstevel@tonic-gate 		set_maximum[which] = FALSE;
3397c478bd9Sstevel@tonic-gate 	} else {
3407c478bd9Sstevel@tonic-gate 		if (limit_value(which, hard, &rp->rlim_max) != 0)
3417c478bd9Sstevel@tonic-gate 			return (1);
3427c478bd9Sstevel@tonic-gate 		set_maximum[which] = TRUE;
3437c478bd9Sstevel@tonic-gate 	}
3447c478bd9Sstevel@tonic-gate 	if (set_current[which] && set_maximum[which] &&
3457c478bd9Sstevel@tonic-gate 	    rp->rlim_cur > rp->rlim_max)
3467c478bd9Sstevel@tonic-gate 		return (1);
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	return (0);
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate static void
3527c478bd9Sstevel@tonic-gate limit_adjust(struct rlimit64 *rp, int units)
3537c478bd9Sstevel@tonic-gate {
3547c478bd9Sstevel@tonic-gate 	if (rp->rlim_cur != RLIM64_INFINITY)
3557c478bd9Sstevel@tonic-gate 		rp->rlim_cur /= units;
3567c478bd9Sstevel@tonic-gate 	if (rp->rlim_max != RLIM64_INFINITY)
3577c478bd9Sstevel@tonic-gate 		rp->rlim_max /= units;
3587c478bd9Sstevel@tonic-gate }
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate static char *
3617c478bd9Sstevel@tonic-gate limit_values(struct rlimit64 *rp)
3627c478bd9Sstevel@tonic-gate {
3637c478bd9Sstevel@tonic-gate 	static char buffer[64];
3647c478bd9Sstevel@tonic-gate 	char buf1[32];
3657c478bd9Sstevel@tonic-gate 	char buf2[32];
3667c478bd9Sstevel@tonic-gate 	char *s1;
3677c478bd9Sstevel@tonic-gate 	char *s2;
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	if (rp->rlim_cur == RLIM64_INFINITY)
3707c478bd9Sstevel@tonic-gate 		s1 = "unlimited";
3717c478bd9Sstevel@tonic-gate 	else {
3727c478bd9Sstevel@tonic-gate 		(void) sprintf(s1 = buf1, "%lld", rp->rlim_cur);
3737c478bd9Sstevel@tonic-gate 		if (strlen(s1) < 8)
3747c478bd9Sstevel@tonic-gate 			(void) strcat(s1, "\t");
3757c478bd9Sstevel@tonic-gate 	}
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	if (rp->rlim_max == RLIM64_INFINITY)
3787c478bd9Sstevel@tonic-gate 		s2 = "unlimited";
3797c478bd9Sstevel@tonic-gate 	else {
3807c478bd9Sstevel@tonic-gate 		(void) sprintf(s2 = buf2, "%lld", rp->rlim_max);
3817c478bd9Sstevel@tonic-gate 	}
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	(void) sprintf(buffer, "%s\t%s", s1, s2);
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	return (buffer);
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate static void
3897c478bd9Sstevel@tonic-gate show_limits(struct ps_prochandle *Pr)
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate 	struct rlimit64 rlim;
3927c478bd9Sstevel@tonic-gate 	int resource;
3937c478bd9Sstevel@tonic-gate 	char buf[32];
3947c478bd9Sstevel@tonic-gate 	char *s;
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	(void) printf("   resource\t\t current\t maximum\n");
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	for (resource = 0; resource < RLIM_NLIMITS; resource++) {
3997c478bd9Sstevel@tonic-gate 		if (pr_getrlimit64(Pr, resource, &rlim) != 0)
4007c478bd9Sstevel@tonic-gate 			continue;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 		switch (resource) {
4037c478bd9Sstevel@tonic-gate 		case RLIMIT_CPU:
4047c478bd9Sstevel@tonic-gate 			s = "  time(seconds)\t\t";
4057c478bd9Sstevel@tonic-gate 			break;
4067c478bd9Sstevel@tonic-gate 		case RLIMIT_FSIZE:
4077c478bd9Sstevel@tonic-gate 			if (kbytes) {
4087c478bd9Sstevel@tonic-gate 				s = "  file(kbytes)\t\t";
4097c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024);
4107c478bd9Sstevel@tonic-gate 			} else if (mbytes) {
4117c478bd9Sstevel@tonic-gate 				s = "  file(mbytes)\t\t";
4127c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024 * 1024);
4137c478bd9Sstevel@tonic-gate 			} else {
4147c478bd9Sstevel@tonic-gate 				s = "  file(blocks)\t\t";
4157c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 512);
4167c478bd9Sstevel@tonic-gate 			}
4177c478bd9Sstevel@tonic-gate 			break;
4187c478bd9Sstevel@tonic-gate 		case RLIMIT_DATA:
4197c478bd9Sstevel@tonic-gate 			if (mbytes) {
4207c478bd9Sstevel@tonic-gate 				s = "  data(mbytes)\t\t";
4217c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024 * 1024);
4227c478bd9Sstevel@tonic-gate 			} else {
4237c478bd9Sstevel@tonic-gate 				s = "  data(kbytes)\t\t";
4247c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024);
4257c478bd9Sstevel@tonic-gate 			}
4267c478bd9Sstevel@tonic-gate 			break;
4277c478bd9Sstevel@tonic-gate 		case RLIMIT_STACK:
4287c478bd9Sstevel@tonic-gate 			if (mbytes) {
4297c478bd9Sstevel@tonic-gate 				s = "  stack(mbytes)\t\t";
4307c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024 * 1024);
4317c478bd9Sstevel@tonic-gate 			} else {
4327c478bd9Sstevel@tonic-gate 				s = "  stack(kbytes)\t\t";
4337c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024);
4347c478bd9Sstevel@tonic-gate 			}
4357c478bd9Sstevel@tonic-gate 			break;
4367c478bd9Sstevel@tonic-gate 		case RLIMIT_CORE:
4377c478bd9Sstevel@tonic-gate 			if (kbytes) {
4387c478bd9Sstevel@tonic-gate 				s = "  coredump(kbytes)\t";
4397c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024);
4407c478bd9Sstevel@tonic-gate 			} else if (mbytes) {
4417c478bd9Sstevel@tonic-gate 				s = "  coredump(mbytes)\t";
4427c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024 * 1024);
4437c478bd9Sstevel@tonic-gate 			} else {
4447c478bd9Sstevel@tonic-gate 				s = "  coredump(blocks)\t";
4457c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 512);
4467c478bd9Sstevel@tonic-gate 			}
4477c478bd9Sstevel@tonic-gate 			break;
4487c478bd9Sstevel@tonic-gate 		case RLIMIT_NOFILE:
4497c478bd9Sstevel@tonic-gate 			s = "  nofiles(descriptors)\t";
4507c478bd9Sstevel@tonic-gate 			break;
4517c478bd9Sstevel@tonic-gate 		case RLIMIT_VMEM:
4527c478bd9Sstevel@tonic-gate 			if (mbytes) {
4537c478bd9Sstevel@tonic-gate 				s = "  vmemory(mbytes)\t";
4547c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024 * 1024);
4557c478bd9Sstevel@tonic-gate 			} else {
4567c478bd9Sstevel@tonic-gate 				s = "  vmemory(kbytes)\t";
4577c478bd9Sstevel@tonic-gate 				limit_adjust(&rlim, 1024);
4587c478bd9Sstevel@tonic-gate 			}
4597c478bd9Sstevel@tonic-gate 			break;
4607c478bd9Sstevel@tonic-gate 		default:
4617c478bd9Sstevel@tonic-gate 			(void) sprintf(buf, "  rlimit #%d\t", resource);
4627c478bd9Sstevel@tonic-gate 			s = buf;
4637c478bd9Sstevel@tonic-gate 			break;
4647c478bd9Sstevel@tonic-gate 		}
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 		(void) printf("%s%s\n", s, limit_values(&rlim));
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate }
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate static int
4717c478bd9Sstevel@tonic-gate set_one_limit(struct ps_prochandle *Pr, int which, rlim64_t cur, rlim64_t max)
4727c478bd9Sstevel@tonic-gate {
4737c478bd9Sstevel@tonic-gate 	struct rlimit64 rlim;
4747c478bd9Sstevel@tonic-gate 	int be_su = 0;
4757c478bd9Sstevel@tonic-gate 	prpriv_t *old_prpriv = NULL, *new_prpriv = NULL;
4767c478bd9Sstevel@tonic-gate 	priv_set_t *eset, *pset;
4777c478bd9Sstevel@tonic-gate 	int ret = 0;
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	if (pr_getrlimit64(Pr, which, &rlim) != 0) {
4807c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
4817c478bd9Sstevel@tonic-gate 		    "%s: unable to get process limit for pid %d: %s\n",
4827c478bd9Sstevel@tonic-gate 		    command, Pstatus(Pr)->pr_pid, strerror(errno));
4837c478bd9Sstevel@tonic-gate 		return (1);
4847c478bd9Sstevel@tonic-gate 	}
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	if (!set_current[which])
4877c478bd9Sstevel@tonic-gate 		cur = rlim.rlim_cur;
4887c478bd9Sstevel@tonic-gate 	if (!set_maximum[which])
4897c478bd9Sstevel@tonic-gate 		max = rlim.rlim_max;
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	if (max < cur)
4927c478bd9Sstevel@tonic-gate 		max = cur;
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	if (max > rlim.rlim_max && Pr != NULL)
4957c478bd9Sstevel@tonic-gate 		be_su = 1;
4967c478bd9Sstevel@tonic-gate 	rlim.rlim_cur = cur;
4977c478bd9Sstevel@tonic-gate 	rlim.rlim_max = max;
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	if (be_su) {
5007c478bd9Sstevel@tonic-gate 		new_prpriv = proc_get_priv(Pstatus(Pr)->pr_pid);
5017c478bd9Sstevel@tonic-gate 		if (new_prpriv == NULL) {
5027c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
5037c478bd9Sstevel@tonic-gate 			    "%s: unable to get process privileges for pid"
5047c478bd9Sstevel@tonic-gate 			    " %d: %s\n", command, Pstatus(Pr)->pr_pid,
5057c478bd9Sstevel@tonic-gate 			    strerror(errno));
5067c478bd9Sstevel@tonic-gate 			return (1);
5077c478bd9Sstevel@tonic-gate 		}
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 		/*
5107c478bd9Sstevel@tonic-gate 		 * We only have to change the process privileges if it doesn't
5117c478bd9Sstevel@tonic-gate 		 * already have PRIV_SYS_RESOURCE.  In addition, we want to make
5127c478bd9Sstevel@tonic-gate 		 * sure that we don't leave a process with elevated privileges,
5137c478bd9Sstevel@tonic-gate 		 * so we make sure the process dies if we exit unexpectedly.
5147c478bd9Sstevel@tonic-gate 		 */
5157c478bd9Sstevel@tonic-gate 		eset = (priv_set_t *)
5167c478bd9Sstevel@tonic-gate 		    &new_prpriv->pr_sets[new_prpriv->pr_setsize *
5177c478bd9Sstevel@tonic-gate 		    priv_getsetbyname(PRIV_EFFECTIVE)];
5187c478bd9Sstevel@tonic-gate 		pset = (priv_set_t *)
5197c478bd9Sstevel@tonic-gate 		    &new_prpriv->pr_sets[new_prpriv->pr_setsize *
5207c478bd9Sstevel@tonic-gate 		    priv_getsetbyname(PRIV_PERMITTED)];
5217c478bd9Sstevel@tonic-gate 		if (!priv_ismember(eset, PRIV_SYS_RESOURCE)) {
5227c478bd9Sstevel@tonic-gate 			/* Keep track of original privileges */
5237c478bd9Sstevel@tonic-gate 			old_prpriv = proc_get_priv(Pstatus(Pr)->pr_pid);
5247c478bd9Sstevel@tonic-gate 			if (old_prpriv == NULL) {
525*43051d27SRobert Mustacchi 				proc_free_priv(new_prpriv);
5267c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
5277c478bd9Sstevel@tonic-gate 				    "%s: unable to get process privileges "
5287c478bd9Sstevel@tonic-gate 				    "for pid %d: %s\n", command,
5297c478bd9Sstevel@tonic-gate 				    Pstatus(Pr)->pr_pid, strerror(errno));
5307c478bd9Sstevel@tonic-gate 				return (1);
5317c478bd9Sstevel@tonic-gate 			}
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 			(void) priv_addset(eset, PRIV_SYS_RESOURCE);
5347c478bd9Sstevel@tonic-gate 			(void) priv_addset(pset, PRIV_SYS_RESOURCE);
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 			if (Psetflags(Pr, PR_KLC) != 0 ||
5377c478bd9Sstevel@tonic-gate 			    Psetpriv(Pr, new_prpriv) != 0) {
5387c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
5397c478bd9Sstevel@tonic-gate 				    "%s: unable to set process privileges for"
5407c478bd9Sstevel@tonic-gate 				    " pid %d: %s\n", command,
5417c478bd9Sstevel@tonic-gate 				    Pstatus(Pr)->pr_pid, strerror(errno));
5427c478bd9Sstevel@tonic-gate 				(void) Punsetflags(Pr, PR_KLC);
543*43051d27SRobert Mustacchi 				proc_free_priv(new_prpriv);
544*43051d27SRobert Mustacchi 				proc_free_priv(old_prpriv);
5457c478bd9Sstevel@tonic-gate 				return (1);
5467c478bd9Sstevel@tonic-gate 			}
5477c478bd9Sstevel@tonic-gate 		}
5487c478bd9Sstevel@tonic-gate 	}
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	if (pr_setrlimit64(Pr, which, &rlim) != 0) {
5517c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
5527c478bd9Sstevel@tonic-gate 		    "%s: cannot set resource limit for pid %d: %s\n",
5537c478bd9Sstevel@tonic-gate 		    command, Pstatus(Pr)->pr_pid, strerror(errno));
5547c478bd9Sstevel@tonic-gate 		ret = 1;
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	if (old_prpriv != NULL) {
5587c478bd9Sstevel@tonic-gate 		if (Psetpriv(Pr, old_prpriv) != 0) {
5597c478bd9Sstevel@tonic-gate 			/*
5607c478bd9Sstevel@tonic-gate 			 * If this fails, we can't leave a process hanging
5617c478bd9Sstevel@tonic-gate 			 * around with elevated privileges, so we'll have to
5627c478bd9Sstevel@tonic-gate 			 * release the process from libproc, knowing that it
5637c478bd9Sstevel@tonic-gate 			 * will be killed (since we set PR_KLC).
5647c478bd9Sstevel@tonic-gate 			 */
5657c478bd9Sstevel@tonic-gate 			Pdestroy_agent(Pr);
5667c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
5677c478bd9Sstevel@tonic-gate 			    "%s: cannot relinquish privileges for pid %d."
5687c478bd9Sstevel@tonic-gate 			    " The process was killed.",
5697c478bd9Sstevel@tonic-gate 			    command, Pstatus(Pr)->pr_pid);
5707c478bd9Sstevel@tonic-gate 			ret = 1;
5717c478bd9Sstevel@tonic-gate 		}
5727c478bd9Sstevel@tonic-gate 		if (Punsetflags(Pr, PR_KLC) != 0) {
5737c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
5747c478bd9Sstevel@tonic-gate 			    "%s: cannot relinquish privileges for pid %d."
5757c478bd9Sstevel@tonic-gate 			    " The process was killed.",
5767c478bd9Sstevel@tonic-gate 			    command, Pstatus(Pr)->pr_pid);
5777c478bd9Sstevel@tonic-gate 			ret = 1;
5787c478bd9Sstevel@tonic-gate 		}
5797c478bd9Sstevel@tonic-gate 
580*43051d27SRobert Mustacchi 		proc_free_priv(old_prpriv);
5817c478bd9Sstevel@tonic-gate 	}
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	if (new_prpriv != NULL)
584*43051d27SRobert Mustacchi 		proc_free_priv(new_prpriv);
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	return (ret);
5877c478bd9Sstevel@tonic-gate }
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate static int
5907c478bd9Sstevel@tonic-gate set_limits(struct ps_prochandle *Pr)
5917c478bd9Sstevel@tonic-gate {
5927c478bd9Sstevel@tonic-gate 	int which;
5937c478bd9Sstevel@tonic-gate 	int retc = 0;
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	for (which = 0; which < RLIM_NLIMITS; which++) {
5967c478bd9Sstevel@tonic-gate 		if (set_current[which] || set_maximum[which]) {
5977c478bd9Sstevel@tonic-gate 			if (set_one_limit(Pr, which, rlimit[which].rlim_cur,
5987c478bd9Sstevel@tonic-gate 			    rlimit[which].rlim_max) != 0)
5997c478bd9Sstevel@tonic-gate 				retc = 1;
6007c478bd9Sstevel@tonic-gate 		}
6017c478bd9Sstevel@tonic-gate 	}
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	return (retc);
6047c478bd9Sstevel@tonic-gate }
605