11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1991, 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * This code is derived from software contributed to Berkeley by
61556Srgrimes * Kenneth Almquist.
71556Srgrimes *
81556Srgrimes * Redistribution and use in source and binary forms, with or without
91556Srgrimes * modification, are permitted provided that the following conditions
101556Srgrimes * are met:
111556Srgrimes * 1. Redistributions of source code must retain the above copyright
121556Srgrimes *    notice, this list of conditions and the following disclaimer.
131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer in the
151556Srgrimes *    documentation and/or other materials provided with the distribution.
161556Srgrimes * 4. Neither the name of the University nor the names of its contributors
171556Srgrimes *    may be used to endorse or promote products derived from this software
181556Srgrimes *    without specific prior written permission.
191556Srgrimes *
201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301556Srgrimes * SUCH DAMAGE.
311556Srgrimes */
321556Srgrimes
331556Srgrimes#ifndef lint
3436150Scharnier#if 0
3536150Scharnierstatic char sccsid[] = "@(#)miscbltin.c	8.4 (Berkeley) 5/4/95";
3636150Scharnier#endif
371556Srgrimes#endif /* not lint */
3899110Sobrien#include <sys/cdefs.h>
3999110Sobrien__FBSDID("$FreeBSD: stable/11/bin/sh/miscbltin.c 359077 2020-03-18 18:10:44Z hrs $");
401556Srgrimes
411556Srgrimes/*
4246684Skris * Miscellaneous builtins.
431556Srgrimes */
441556Srgrimes
4517987Speter#include <sys/types.h>
4617987Speter#include <sys/stat.h>
4717987Speter#include <sys/time.h>
4817987Speter#include <sys/resource.h>
4917987Speter#include <unistd.h>
5018016Speter#include <errno.h>
51104282Smux#include <stdint.h>
5218018Speter#include <stdio.h>
5338536Scracauer#include <stdlib.h>
5417987Speter
551556Srgrimes#include "shell.h"
561556Srgrimes#include "options.h"
571556Srgrimes#include "var.h"
581556Srgrimes#include "output.h"
591556Srgrimes#include "memalloc.h"
601556Srgrimes#include "error.h"
611556Srgrimes#include "mystring.h"
62246167Sjilles#include "syntax.h"
63250214Sjilles#include "trap.h"
641556Srgrimes
651556Srgrimes#undef eflag
661556Srgrimes
67359077Shrs#define	READ_BUFLEN	1024
68359077Shrsstruct fdctx {
69359077Shrs	int	fd;
70359077Shrs	size_t	off;	/* offset in buf */
71359077Shrs	size_t	buflen;
72359077Shrs	char	*ep;	/* tail pointer */
73359077Shrs	char	buf[READ_BUFLEN];
74359077Shrs};
75359077Shrs
76359077Shrsstatic void fdctx_init(int, struct fdctx *);
77359077Shrsstatic void fdctx_destroy(struct fdctx *);
78359077Shrsstatic ssize_t fdgetc(struct fdctx *, char *);
79149018Sstefanfint readcmd(int, char **);
80149018Sstefanfint umaskcmd(int, char **);
81149018Sstefanfint ulimitcmd(int, char **);
82149018Sstefanf
83359077Shrsstatic void
84359077Shrsfdctx_init(int fd, struct fdctx *fdc)
85359077Shrs{
86359077Shrs	off_t cur;
87359077Shrs
88359077Shrs	/* Check if fd is seekable. */
89359077Shrs	cur = lseek(fd, 0, SEEK_CUR);
90359077Shrs	*fdc = (struct fdctx){
91359077Shrs		.fd = fd,
92359077Shrs		.buflen = (cur != -1) ? READ_BUFLEN : 1,
93359077Shrs		.ep = &fdc->buf[0],	/* No data */
94359077Shrs	};
95359077Shrs}
96359077Shrs
97359077Shrsstatic ssize_t
98359077Shrsfdgetc(struct fdctx *fdc, char *c)
99359077Shrs{
100359077Shrs	ssize_t nread;
101359077Shrs
102359077Shrs	if (&fdc->buf[fdc->off] == fdc->ep) {
103359077Shrs		nread = read(fdc->fd, fdc->buf, fdc->buflen);
104359077Shrs		if (nread > 0) {
105359077Shrs			fdc->off = 0;
106359077Shrs			fdc->ep = fdc->buf + nread;
107359077Shrs		} else
108359077Shrs			return (nread);
109359077Shrs	}
110359077Shrs	*c = fdc->buf[fdc->off++];
111359077Shrs
112359077Shrs	return (1);
113359077Shrs}
114359077Shrs
115359077Shrsstatic void
116359077Shrsfdctx_destroy(struct fdctx *fdc)
117359077Shrs{
118359077Shrs	off_t residue;
119359077Shrs
120359077Shrs	if (fdc->buflen > 1) {
121359077Shrs	/*
122359077Shrs	 * Reposition the file offset.  Here is the layout of buf:
123359077Shrs	 *
124359077Shrs	 *     | off
125359077Shrs	 *     v
126359077Shrs	 * |*****************|-------|
127359077Shrs	 * buf               ep   buf+buflen
128359077Shrs	 *     |<- residue ->|
129359077Shrs	 *
130359077Shrs	 * off: current character
131359077Shrs	 * ep:  offset just after read(2)
132359077Shrs	 * residue: length for reposition
133359077Shrs	 */
134359077Shrs		residue = (fdc->ep - fdc->buf) - fdc->off;
135359077Shrs		if (residue > 0)
136359077Shrs			(void) lseek(fdc->fd, -residue, SEEK_CUR);
137359077Shrs	}
138359077Shrs}
139359077Shrs
1401556Srgrimes/*
14150394Stg * The read builtin.  The -r option causes backslashes to be treated like
14250394Stg * ordinary characters.
1431556Srgrimes *
1441556Srgrimes * This uses unbuffered input, which may be avoidable in some cases.
145190295Sstefanf *
146190295Sstefanf * Note that if IFS=' :' then read x y should work so that:
147190295Sstefanf * 'a b'	x='a', y='b'
148190295Sstefanf * ' a b '	x='a', y='b'
149190295Sstefanf * ':b'		x='',  y='b'
150190295Sstefanf * ':'		x='',  y=''
151190295Sstefanf * '::'		x='',  y=''
152190295Sstefanf * ': :'	x='',  y=''
153190295Sstefanf * ':::'	x='',  y='::'
154190295Sstefanf * ':b c:'	x='',  y='b c:'
1551556Srgrimes */
1561556Srgrimes
15717987Speterint
15890111Simpreadcmd(int argc __unused, char **argv __unused)
15917987Speter{
1601556Srgrimes	char **ap;
1611556Srgrimes	int backslash;
1621556Srgrimes	char c;
16350394Stg	int rflag;
1641556Srgrimes	char *prompt;
165201053Sjilles	const char *ifs;
1661556Srgrimes	char *p;
1671556Srgrimes	int startword;
1681556Srgrimes	int status;
1691556Srgrimes	int i;
170190295Sstefanf	int is_ifs;
171190295Sstefanf	int saveall = 0;
172287308Sjilles	ptrdiff_t lastnonifs, lastnonifsws;
17329983Smsmith	struct timeval tv;
17429983Smsmith	char *tvptr;
17529983Smsmith	fd_set ifds;
176250214Sjilles	ssize_t nread;
177250214Sjilles	int sig;
178359077Shrs	struct fdctx fdctx;
1791556Srgrimes
18050394Stg	rflag = 0;
1811556Srgrimes	prompt = NULL;
18229983Smsmith	tv.tv_sec = -1;
18329983Smsmith	tv.tv_usec = 0;
18450394Stg	while ((i = nextopt("erp:t:")) != '\0') {
18529983Smsmith		switch(i) {
18629983Smsmith		case 'p':
18759436Scracauer			prompt = shoptarg;
18829983Smsmith			break;
18929983Smsmith		case 'e':
19029983Smsmith			break;
19150394Stg		case 'r':
19250394Stg			rflag = 1;
19350394Stg			break;
19429983Smsmith		case 't':
19559436Scracauer			tv.tv_sec = strtol(shoptarg, &tvptr, 0);
19659436Scracauer			if (tvptr == shoptarg)
19729983Smsmith				error("timeout value");
19829983Smsmith			switch(*tvptr) {
19929983Smsmith			case 0:
20029983Smsmith			case 's':
20129983Smsmith				break;
20229983Smsmith			case 'h':
20329983Smsmith				tv.tv_sec *= 60;
20429983Smsmith				/* FALLTHROUGH */
20529983Smsmith			case 'm':
20629983Smsmith				tv.tv_sec *= 60;
20729983Smsmith				break;
20829983Smsmith			default:
20929983Smsmith				error("timeout unit");
21029983Smsmith			}
21129983Smsmith			break;
21229983Smsmith		}
2131556Srgrimes	}
2141556Srgrimes	if (prompt && isatty(0)) {
2151556Srgrimes		out2str(prompt);
2161556Srgrimes		flushall();
2171556Srgrimes	}
2181556Srgrimes	if (*(ap = argptr) == NULL)
2191556Srgrimes		error("arg count");
2201556Srgrimes	if ((ifs = bltinlookup("IFS", 1)) == NULL)
221190298Sstefanf		ifs = " \t\n";
22229983Smsmith
22329983Smsmith	if (tv.tv_sec >= 0) {
22429983Smsmith		/*
22529983Smsmith		 * Wait for something to become available.
22629983Smsmith		 */
22729983Smsmith		FD_ZERO(&ifds);
22829983Smsmith		FD_SET(0, &ifds);
22929983Smsmith		status = select(1, &ifds, NULL, NULL, &tv);
23029983Smsmith		/*
23129983Smsmith		 * If there's nothing ready, return an error.
23229983Smsmith		 */
233250214Sjilles		if (status <= 0) {
234250214Sjilles			sig = pendingsig;
235250214Sjilles			return (128 + (sig != 0 ? sig : SIGALRM));
236250214Sjilles		}
23729983Smsmith	}
23829983Smsmith
2391556Srgrimes	status = 0;
240190295Sstefanf	startword = 2;
2411556Srgrimes	backslash = 0;
2421556Srgrimes	STARTSTACKSTR(p);
243287308Sjilles	lastnonifs = lastnonifsws = -1;
244359077Shrs	fdctx_init(STDIN_FILENO, &fdctx);
2451556Srgrimes	for (;;) {
246359077Shrs		nread = fdgetc(&fdctx, &c);
247250214Sjilles		if (nread == -1) {
248250214Sjilles			if (errno == EINTR) {
249250214Sjilles				sig = pendingsig;
250250214Sjilles				if (sig == 0)
251250214Sjilles					continue;
252250214Sjilles				status = 128 + sig;
253250214Sjilles				break;
254250214Sjilles			}
255250214Sjilles			warning("read error: %s", strerror(errno));
256250214Sjilles			status = 2;
257250214Sjilles			break;
258250214Sjilles		} else if (nread != 1) {
2591556Srgrimes			status = 1;
2601556Srgrimes			break;
2611556Srgrimes		}
2621556Srgrimes		if (c == '\0')
2631556Srgrimes			continue;
264215783Sjilles		CHECKSTRSPACE(1, p);
2651556Srgrimes		if (backslash) {
2661556Srgrimes			backslash = 0;
267286826Sjilles			if (c != '\n') {
268286826Sjilles				startword = 0;
269287308Sjilles				lastnonifs = lastnonifsws = p - stackblock();
270215783Sjilles				USTPUTC(c, p);
271286826Sjilles			}
2721556Srgrimes			continue;
2731556Srgrimes		}
27450394Stg		if (!rflag && c == '\\') {
2751556Srgrimes			backslash++;
2761556Srgrimes			continue;
2771556Srgrimes		}
2781556Srgrimes		if (c == '\n')
2791556Srgrimes			break;
280190295Sstefanf		if (strchr(ifs, c))
281190295Sstefanf			is_ifs = strchr(" \t\n", c) ? 1 : 2;
282190295Sstefanf		else
283190295Sstefanf			is_ifs = 0;
284190295Sstefanf
285190295Sstefanf		if (startword != 0) {
286190295Sstefanf			if (is_ifs == 1) {
287190295Sstefanf				/* Ignore leading IFS whitespace */
288190295Sstefanf				if (saveall)
289215783Sjilles					USTPUTC(c, p);
290190295Sstefanf				continue;
291190295Sstefanf			}
292190295Sstefanf			if (is_ifs == 2 && startword == 1) {
293190295Sstefanf				/* Only one non-whitespace IFS per word */
294190295Sstefanf				startword = 2;
295287308Sjilles				if (saveall) {
296287308Sjilles					lastnonifsws = p - stackblock();
297215783Sjilles					USTPUTC(c, p);
298287308Sjilles				}
299190295Sstefanf				continue;
300190295Sstefanf			}
301190295Sstefanf		}
302190295Sstefanf
303190295Sstefanf		if (is_ifs == 0) {
304190295Sstefanf			/* append this character to the current variable */
305190295Sstefanf			startword = 0;
306190295Sstefanf			if (saveall)
307190295Sstefanf				/* Not just a spare terminator */
308190295Sstefanf				saveall++;
309287308Sjilles			lastnonifs = lastnonifsws = p - stackblock();
310215783Sjilles			USTPUTC(c, p);
3111556Srgrimes			continue;
3121556Srgrimes		}
313190295Sstefanf
314190295Sstefanf		/* end of variable... */
315190295Sstefanf		startword = is_ifs;
316190295Sstefanf
317190295Sstefanf		if (ap[1] == NULL) {
318190295Sstefanf			/* Last variable needs all IFS chars */
319190295Sstefanf			saveall++;
320287308Sjilles			if (is_ifs == 2)
321287308Sjilles				lastnonifsws = p - stackblock();
322215783Sjilles			USTPUTC(c, p);
323190295Sstefanf			continue;
3241556Srgrimes		}
325190295Sstefanf
326190295Sstefanf		STACKSTRNUL(p);
327190295Sstefanf		setvar(*ap, stackblock(), 0);
328190295Sstefanf		ap++;
329190295Sstefanf		STARTSTACKSTR(p);
330287308Sjilles		lastnonifs = lastnonifsws = -1;
3311556Srgrimes	}
332359077Shrs	fdctx_destroy(&fdctx);
3331556Srgrimes	STACKSTRNUL(p);
334190295Sstefanf
335287308Sjilles	/*
336287308Sjilles	 * Remove trailing IFS chars: always remove whitespace, don't remove
337287308Sjilles	 * non-whitespace unless it was naked
338287308Sjilles	 */
339287308Sjilles	if (saveall <= 1)
340287308Sjilles		lastnonifsws = lastnonifs;
341287308Sjilles	stackblock()[lastnonifsws + 1] = '\0';
3421556Srgrimes	setvar(*ap, stackblock(), 0);
343190295Sstefanf
344190295Sstefanf	/* Set any remaining args to "" */
3451556Srgrimes	while (*++ap != NULL)
346278820Sjilles		setvar(*ap, "", 0);
3471556Srgrimes	return status;
3481556Srgrimes}
3491556Srgrimes
3501556Srgrimes
3511556Srgrimes
35217987Speterint
353201053Sjillesumaskcmd(int argc __unused, char **argv __unused)
35417987Speter{
35517987Speter	char *ap;
3561556Srgrimes	int mask;
3571556Srgrimes	int i;
35817987Speter	int symbolic_mode = 0;
3591556Srgrimes
36017987Speter	while ((i = nextopt("S")) != '\0') {
36117987Speter		symbolic_mode = 1;
3621556Srgrimes	}
36311571Sjoerg
36417987Speter	INTOFF;
36517987Speter	mask = umask(0);
36617987Speter	umask(mask);
36717987Speter	INTON;
36811571Sjoerg
36917987Speter	if ((ap = *argptr) == NULL) {
37017987Speter		if (symbolic_mode) {
37117987Speter			char u[4], g[4], o[4];
37211571Sjoerg
37317987Speter			i = 0;
37417987Speter			if ((mask & S_IRUSR) == 0)
37517987Speter				u[i++] = 'r';
37617987Speter			if ((mask & S_IWUSR) == 0)
37717987Speter				u[i++] = 'w';
37817987Speter			if ((mask & S_IXUSR) == 0)
37917987Speter				u[i++] = 'x';
38017987Speter			u[i] = '\0';
38111571Sjoerg
38217987Speter			i = 0;
38317987Speter			if ((mask & S_IRGRP) == 0)
38417987Speter				g[i++] = 'r';
38517987Speter			if ((mask & S_IWGRP) == 0)
38617987Speter				g[i++] = 'w';
38717987Speter			if ((mask & S_IXGRP) == 0)
38817987Speter				g[i++] = 'x';
38917987Speter			g[i] = '\0';
39011571Sjoerg
39117987Speter			i = 0;
39217987Speter			if ((mask & S_IROTH) == 0)
39317987Speter				o[i++] = 'r';
39417987Speter			if ((mask & S_IWOTH) == 0)
39517987Speter				o[i++] = 'w';
39617987Speter			if ((mask & S_IXOTH) == 0)
39717987Speter				o[i++] = 'x';
39817987Speter			o[i] = '\0';
39911571Sjoerg
40017987Speter			out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
40117987Speter		} else {
40217987Speter			out1fmt("%.4o\n", mask);
40317987Speter		}
40417987Speter	} else {
405246167Sjilles		if (is_digit(*ap)) {
40617987Speter			mask = 0;
40717987Speter			do {
40817987Speter				if (*ap >= '8' || *ap < '0')
409149918Sstefanf					error("Illegal number: %s", *argptr);
41017987Speter				mask = (mask << 3) + (*ap - '0');
41117987Speter			} while (*++ap != '\0');
41217987Speter			umask(mask);
41317987Speter		} else {
41420425Ssteve			void *set;
415151795Sstefanf			INTOFF;
416297761Spfg			if ((set = setmode (ap)) == NULL)
41741844Simp				error("Illegal number: %s", ap);
41811571Sjoerg
41917987Speter			mask = getmode (set, ~mask & 0777);
42017987Speter			umask(~mask & 0777);
42141844Simp			free(set);
422151795Sstefanf			INTON;
42317987Speter		}
42417987Speter	}
42511571Sjoerg	return 0;
42611571Sjoerg}
42711571Sjoerg
42817987Speter/*
42917987Speter * ulimit builtin
43017987Speter *
43117987Speter * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
43217987Speter * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
43317987Speter * ash by J.T. Conklin.
43417987Speter *
43517987Speter * Public domain.
43617987Speter */
43711571Sjoerg
43817987Speterstruct limits {
43917987Speter	const char *name;
44018016Speter	const char *units;
44117987Speter	int	cmd;
44217987Speter	int	factor;	/* multiply by to get rlim_{cur,max} values */
44317987Speter	char	option;
44417987Speter};
44511571Sjoerg
44617987Speterstatic const struct limits limits[] = {
44717987Speter#ifdef RLIMIT_CPU
44818016Speter	{ "cpu time",		"seconds",	RLIMIT_CPU,	   1, 't' },
44917987Speter#endif
45017987Speter#ifdef RLIMIT_FSIZE
45118016Speter	{ "file size",		"512-blocks",	RLIMIT_FSIZE,	 512, 'f' },
45217987Speter#endif
45317987Speter#ifdef RLIMIT_DATA
45418016Speter	{ "data seg size",	"kbytes",	RLIMIT_DATA,	1024, 'd' },
45517987Speter#endif
45617987Speter#ifdef RLIMIT_STACK
45718016Speter	{ "stack size",		"kbytes",	RLIMIT_STACK,	1024, 's' },
45817987Speter#endif
45917987Speter#ifdef  RLIMIT_CORE
46018016Speter	{ "core file size",	"512-blocks",	RLIMIT_CORE,	 512, 'c' },
46117987Speter#endif
46217987Speter#ifdef RLIMIT_RSS
46318016Speter	{ "max memory size",	"kbytes",	RLIMIT_RSS,	1024, 'm' },
46417987Speter#endif
46517987Speter#ifdef RLIMIT_MEMLOCK
46618016Speter	{ "locked memory",	"kbytes",	RLIMIT_MEMLOCK, 1024, 'l' },
46717987Speter#endif
46817987Speter#ifdef RLIMIT_NPROC
46918016Speter	{ "max user processes",	(char *)0,	RLIMIT_NPROC,      1, 'u' },
47017987Speter#endif
47117987Speter#ifdef RLIMIT_NOFILE
47218016Speter	{ "open files",		(char *)0,	RLIMIT_NOFILE,     1, 'n' },
47317987Speter#endif
47417987Speter#ifdef RLIMIT_VMEM
47518016Speter	{ "virtual mem size",	"kbytes",	RLIMIT_VMEM,	1024, 'v' },
47617987Speter#endif
47717987Speter#ifdef RLIMIT_SWAP
47818016Speter	{ "swap limit",		"kbytes",	RLIMIT_SWAP,	1024, 'w' },
47917987Speter#endif
48052072Sgreen#ifdef RLIMIT_SBSIZE
481301452Sjilles	{ "socket buffer size",	"bytes",	RLIMIT_SBSIZE,	   1, 'b' },
48252072Sgreen#endif
483181905Sed#ifdef RLIMIT_NPTS
484181905Sed	{ "pseudo-terminals",	(char *)0,	RLIMIT_NPTS,	   1, 'p' },
485181905Sed#endif
486256850Skib#ifdef RLIMIT_KQUEUES
487256850Skib	{ "kqueues",		(char *)0,	RLIMIT_KQUEUES,	   1, 'k' },
488256850Skib#endif
489296162Skib#ifdef RLIMIT_UMTXP
490301452Sjilles	{ "umtx shared locks",	(char *)0,	RLIMIT_UMTXP,	   1, 'o' },
491296162Skib#endif
49218016Speter	{ (char *) 0,		(char *)0,	0,		   0, '\0' }
49317987Speter};
49417987Speter
495268873Sjillesenum limithow { SOFT = 0x1, HARD = 0x2 };
496268873Sjilles
497268873Sjillesstatic void
498268873Sjillesprintlimit(enum limithow how, const struct rlimit *limit,
499268873Sjilles    const struct limits *l)
500268873Sjilles{
501268873Sjilles	rlim_t val = 0;
502268873Sjilles
503268873Sjilles	if (how & SOFT)
504268873Sjilles		val = limit->rlim_cur;
505268873Sjilles	else if (how & HARD)
506268873Sjilles		val = limit->rlim_max;
507268873Sjilles	if (val == RLIM_INFINITY)
508268873Sjilles		out1str("unlimited\n");
509268873Sjilles	else
510268873Sjilles	{
511268873Sjilles		val /= l->factor;
512268873Sjilles		out1fmt("%jd\n", (intmax_t)val);
513268873Sjilles	}
514268873Sjilles}
515268873Sjilles
51617987Speterint
51790111Simpulimitcmd(int argc __unused, char **argv __unused)
51817987Speter{
519104282Smux	rlim_t val = 0;
520268873Sjilles	enum limithow how = SOFT | HARD;
52117987Speter	const struct limits	*l;
52217987Speter	int		set, all = 0;
52317987Speter	int		optc, what;
52417987Speter	struct rlimit	limit;
52511571Sjoerg
52617987Speter	what = 'f';
527296723Skib	while ((optc = nextopt("HSatfdsmcnuvlbpwko")) != '\0')
52817987Speter		switch (optc) {
52911571Sjoerg		case 'H':
53017987Speter			how = HARD;
53111571Sjoerg			break;
53211571Sjoerg		case 'S':
53317987Speter			how = SOFT;
53411571Sjoerg			break;
53511571Sjoerg		case 'a':
53617987Speter			all = 1;
53711571Sjoerg			break;
53817987Speter		default:
53917987Speter			what = optc;
54011571Sjoerg		}
54111571Sjoerg
54217987Speter	for (l = limits; l->name && l->option != what; l++)
54317987Speter		;
54417987Speter	if (!l->name)
545104208Stjr		error("internal error (%c)", what);
54617987Speter
54717987Speter	set = *argptr ? 1 : 0;
54817987Speter	if (set) {
54917987Speter		char *p = *argptr;
55017987Speter
55117987Speter		if (all || argptr[1])
552104208Stjr			error("too many arguments");
55317987Speter		if (strcmp(p, "unlimited") == 0)
55411571Sjoerg			val = RLIM_INFINITY;
55511571Sjoerg		else {
556268304Sjilles			char *end;
557268304Sjilles			uintmax_t uval;
55817987Speter
559268304Sjilles			if (*p < '0' || *p > '9')
560104208Stjr				error("bad number");
561268304Sjilles			errno = 0;
562268304Sjilles			uval = strtoumax(p, &end, 10);
563268304Sjilles			if (errno != 0 || *end != '\0')
564268304Sjilles				error("bad number");
565268304Sjilles			if (uval > UINTMAX_MAX / l->factor)
566268304Sjilles				error("bad number");
567268304Sjilles			uval *= l->factor;
568268304Sjilles			val = (rlim_t)uval;
569268304Sjilles			if (val < 0 || (uintmax_t)val != uval ||
570268304Sjilles			    val == RLIM_INFINITY)
571268304Sjilles				error("bad number");
57211571Sjoerg		}
57317987Speter	}
57417987Speter	if (all) {
575155301Sschweikh		for (l = limits; l->name; l++) {
57618016Speter			char optbuf[40];
57718016Speter			if (getrlimit(l->cmd, &limit) < 0)
578104208Stjr				error("can't get limit: %s", strerror(errno));
57917987Speter
58018016Speter			if (l->units)
58118016Speter				snprintf(optbuf, sizeof(optbuf),
58218019Speter					"(%s, -%c) ", l->units, l->option);
58318016Speter			else
58418016Speter				snprintf(optbuf, sizeof(optbuf),
58518019Speter					"(-%c) ", l->option);
58618019Speter			out1fmt("%-18s %18s ", l->name, optbuf);
587268873Sjilles			printlimit(how, &limit, l);
58811571Sjoerg		}
58917987Speter		return 0;
59011571Sjoerg	}
59117987Speter
59218016Speter	if (getrlimit(l->cmd, &limit) < 0)
593104208Stjr		error("can't get limit: %s", strerror(errno));
59417987Speter	if (set) {
59517987Speter		if (how & SOFT)
59617987Speter			limit.rlim_cur = val;
59717987Speter		if (how & HARD)
59817987Speter			limit.rlim_max = val;
59917987Speter		if (setrlimit(l->cmd, &limit) < 0)
600104208Stjr			error("bad limit: %s", strerror(errno));
601268873Sjilles	} else
602268873Sjilles		printlimit(how, &limit, l);
60311571Sjoerg	return 0;
60411571Sjoerg}
605