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