xref: /freebsd/bin/sh/miscbltin.c (revision afb033d5c4f01a464f57fe8e68d741246d9df492)
1 /*-
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Kenneth Almquist.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	$Id: miscbltin.c,v 1.11 1997/02/22 13:58:35 peter Exp $
37  */
38 
39 #ifndef lint
40 static char const sccsid[] = "@(#)miscbltin.c	8.4 (Berkeley) 5/4/95";
41 #endif /* not lint */
42 
43 /*
44  * Miscelaneous builtins.
45  */
46 
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <sys/time.h>
50 #include <sys/resource.h>
51 #include <unistd.h>
52 #include <ctype.h>
53 #include <errno.h>
54 #include <stdio.h>
55 
56 #include "shell.h"
57 #include "options.h"
58 #include "var.h"
59 #include "output.h"
60 #include "memalloc.h"
61 #include "error.h"
62 #include "mystring.h"
63 
64 #undef eflag
65 
66 extern char **argptr;		/* argument list for builtin command */
67 
68 
69 /*
70  * The read builtin.  The -e option causes backslashes to escape the
71  * following character.
72  *
73  * This uses unbuffered input, which may be avoidable in some cases.
74  */
75 
76 int
77 readcmd(argc, argv)
78 	int argc;
79 	char **argv;
80 {
81 	char **ap;
82 	int backslash;
83 	char c;
84 	int eflag;
85 	char *prompt;
86 	char *ifs;
87 	char *p;
88 	int startword;
89 	int status;
90 	int i;
91 
92 	eflag = 0;
93 	prompt = NULL;
94 	while ((i = nextopt("ep:")) != '\0') {
95 		if (i == 'p')
96 			prompt = optarg;
97 		else
98 			eflag = 1;
99 	}
100 	if (prompt && isatty(0)) {
101 		out2str(prompt);
102 		flushall();
103 	}
104 	if (*(ap = argptr) == NULL)
105 		error("arg count");
106 	if ((ifs = bltinlookup("IFS", 1)) == NULL)
107 		ifs = nullstr;
108 	status = 0;
109 	startword = 1;
110 	backslash = 0;
111 	STARTSTACKSTR(p);
112 	for (;;) {
113 		if (read(0, &c, 1) != 1) {
114 			status = 1;
115 			break;
116 		}
117 		if (c == '\0')
118 			continue;
119 		if (backslash) {
120 			backslash = 0;
121 			if (c != '\n')
122 				STPUTC(c, p);
123 			continue;
124 		}
125 		if (eflag && c == '\\') {
126 			backslash++;
127 			continue;
128 		}
129 		if (c == '\n')
130 			break;
131 		if (startword && *ifs == ' ' && strchr(ifs, c)) {
132 			continue;
133 		}
134 		startword = 0;
135 		if (backslash && c == '\\') {
136 			if (read(0, &c, 1) != 1) {
137 				status = 1;
138 				break;
139 			}
140 			STPUTC(c, p);
141 		} else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
142 			STACKSTRNUL(p);
143 			setvar(*ap, stackblock(), 0);
144 			ap++;
145 			startword = 1;
146 			STARTSTACKSTR(p);
147 		} else {
148 			STPUTC(c, p);
149 		}
150 	}
151 	STACKSTRNUL(p);
152 	setvar(*ap, stackblock(), 0);
153 	while (*++ap != NULL)
154 		setvar(*ap, nullstr, 0);
155 	return status;
156 }
157 
158 
159 
160 int
161 umaskcmd(argc, argv)
162 	int argc;
163 	char **argv;
164 {
165 	char *ap;
166 	int mask;
167 	int i;
168 	int symbolic_mode = 0;
169 
170 	while ((i = nextopt("S")) != '\0') {
171 		symbolic_mode = 1;
172 	}
173 
174 	INTOFF;
175 	mask = umask(0);
176 	umask(mask);
177 	INTON;
178 
179 	if ((ap = *argptr) == NULL) {
180 		if (symbolic_mode) {
181 			char u[4], g[4], o[4];
182 
183 			i = 0;
184 			if ((mask & S_IRUSR) == 0)
185 				u[i++] = 'r';
186 			if ((mask & S_IWUSR) == 0)
187 				u[i++] = 'w';
188 			if ((mask & S_IXUSR) == 0)
189 				u[i++] = 'x';
190 			u[i] = '\0';
191 
192 			i = 0;
193 			if ((mask & S_IRGRP) == 0)
194 				g[i++] = 'r';
195 			if ((mask & S_IWGRP) == 0)
196 				g[i++] = 'w';
197 			if ((mask & S_IXGRP) == 0)
198 				g[i++] = 'x';
199 			g[i] = '\0';
200 
201 			i = 0;
202 			if ((mask & S_IROTH) == 0)
203 				o[i++] = 'r';
204 			if ((mask & S_IWOTH) == 0)
205 				o[i++] = 'w';
206 			if ((mask & S_IXOTH) == 0)
207 				o[i++] = 'x';
208 			o[i] = '\0';
209 
210 			out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
211 		} else {
212 			out1fmt("%.4o\n", mask);
213 		}
214 	} else {
215 		if (isdigit(*ap)) {
216 			mask = 0;
217 			do {
218 				if (*ap >= '8' || *ap < '0')
219 					error("Illegal number: %s", argv[1]);
220 				mask = (mask << 3) + (*ap - '0');
221 			} while (*++ap != '\0');
222 			umask(mask);
223 		} else {
224 			void *set;
225 			if ((set = setmode (ap)) == 0)
226 					error("Illegal number: %s", ap);
227 
228 			mask = getmode (set, ~mask & 0777);
229 			umask(~mask & 0777);
230 		}
231 	}
232 	return 0;
233 }
234 
235 /*
236  * ulimit builtin
237  *
238  * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
239  * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
240  * ash by J.T. Conklin.
241  *
242  * Public domain.
243  */
244 
245 struct limits {
246 	const char *name;
247 	const char *units;
248 	int	cmd;
249 	int	factor;	/* multiply by to get rlim_{cur,max} values */
250 	char	option;
251 };
252 
253 static const struct limits limits[] = {
254 #ifdef RLIMIT_CPU
255 	{ "cpu time",		"seconds",	RLIMIT_CPU,	   1, 't' },
256 #endif
257 #ifdef RLIMIT_FSIZE
258 	{ "file size",		"512-blocks",	RLIMIT_FSIZE,	 512, 'f' },
259 #endif
260 #ifdef RLIMIT_DATA
261 	{ "data seg size",	"kbytes",	RLIMIT_DATA,	1024, 'd' },
262 #endif
263 #ifdef RLIMIT_STACK
264 	{ "stack size",		"kbytes",	RLIMIT_STACK,	1024, 's' },
265 #endif
266 #ifdef  RLIMIT_CORE
267 	{ "core file size",	"512-blocks",	RLIMIT_CORE,	 512, 'c' },
268 #endif
269 #ifdef RLIMIT_RSS
270 	{ "max memory size",	"kbytes",	RLIMIT_RSS,	1024, 'm' },
271 #endif
272 #ifdef RLIMIT_MEMLOCK
273 	{ "locked memory",	"kbytes",	RLIMIT_MEMLOCK, 1024, 'l' },
274 #endif
275 #ifdef RLIMIT_NPROC
276 	{ "max user processes",	(char *)0,	RLIMIT_NPROC,      1, 'u' },
277 #endif
278 #ifdef RLIMIT_NOFILE
279 	{ "open files",		(char *)0,	RLIMIT_NOFILE,     1, 'n' },
280 #endif
281 #ifdef RLIMIT_VMEM
282 	{ "virtual mem size",	"kbytes",	RLIMIT_VMEM,	1024, 'v' },
283 #endif
284 #ifdef RLIMIT_SWAP
285 	{ "swap limit",		"kbytes",	RLIMIT_SWAP,	1024, 'w' },
286 #endif
287 	{ (char *) 0,		(char *)0,	0,		   0, '\0' }
288 };
289 
290 int
291 ulimitcmd(argc, argv)
292 	int argc;
293 	char **argv;
294 {
295 	int	c;
296 	quad_t val = 0;
297 	enum { SOFT = 0x1, HARD = 0x2 }
298 			how = SOFT | HARD;
299 	const struct limits	*l;
300 	int		set, all = 0;
301 	int		optc, what;
302 	struct rlimit	limit;
303 
304 	what = 'f';
305 	while ((optc = nextopt("HSatfdsmcnul")) != '\0')
306 		switch (optc) {
307 		case 'H':
308 			how = HARD;
309 			break;
310 		case 'S':
311 			how = SOFT;
312 			break;
313 		case 'a':
314 			all = 1;
315 			break;
316 		default:
317 			what = optc;
318 		}
319 
320 	for (l = limits; l->name && l->option != what; l++)
321 		;
322 	if (!l->name)
323 		error("ulimit: internal error (%c)", what);
324 
325 	set = *argptr ? 1 : 0;
326 	if (set) {
327 		char *p = *argptr;
328 
329 		if (all || argptr[1])
330 			error("ulimit: too many arguments");
331 		if (strcmp(p, "unlimited") == 0)
332 			val = RLIM_INFINITY;
333 		else {
334 			val = (quad_t) 0;
335 
336 			while ((c = *p++) >= '0' && c <= '9')
337 			{
338 				val = (val * 10) + (long)(c - '0');
339 				if (val < (quad_t) 0)
340 					break;
341 			}
342 			if (c)
343 				error("ulimit: bad number");
344 			val *= l->factor;
345 		}
346 	}
347 	if (all) {
348 		for (l = limits; l->name; l++) {
349 			char optbuf[40];
350 			if (getrlimit(l->cmd, &limit) < 0)
351 				error("ulimit: can't get limit: %s", strerror(errno));
352 			if (how & SOFT)
353 				val = limit.rlim_cur;
354 			else if (how & HARD)
355 				val = limit.rlim_max;
356 
357 			if (l->units)
358 				snprintf(optbuf, sizeof(optbuf),
359 					"(%s, -%c) ", l->units, l->option);
360 			else
361 				snprintf(optbuf, sizeof(optbuf),
362 					"(-%c) ", l->option);
363 			out1fmt("%-18s %18s ", l->name, optbuf);
364 			if (val == RLIM_INFINITY)
365 				out1fmt("unlimited\n");
366 			else
367 			{
368 				val /= l->factor;
369 				out1fmt("%qd\n", (quad_t) val);
370 			}
371 		}
372 		return 0;
373 	}
374 
375 	if (getrlimit(l->cmd, &limit) < 0)
376 		error("ulimit: can't get limit: %s", strerror(errno));
377 	if (set) {
378 		if (how & SOFT)
379 			limit.rlim_cur = val;
380 		if (how & HARD)
381 			limit.rlim_max = val;
382 		if (setrlimit(l->cmd, &limit) < 0)
383 			error("ulimit: bad limit: %s", strerror(errno));
384 	} else {
385 		if (how & SOFT)
386 			val = limit.rlim_cur;
387 		else if (how & HARD)
388 			val = limit.rlim_max;
389 
390 		if (val == RLIM_INFINITY)
391 			out1fmt("unlimited\n");
392 		else
393 		{
394 			val /= l->factor;
395 			out1fmt("%qd\n", (quad_t) val);
396 		}
397 	}
398 	return 0;
399 }
400