147129Sbostic /*-
260698Sbostic * Copyright (c) 1991, 1993
360698Sbostic * The Regents of the University of California. All rights reserved.
447129Sbostic *
547129Sbostic * This code is derived from software contributed to Berkeley by
647129Sbostic * Kenneth Almquist.
747129Sbostic *
847129Sbostic * %sccs.include.redist.c%
947129Sbostic */
1047129Sbostic
1147129Sbostic #ifndef lint
12*69272Schristos static char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 05/04/95";
1347129Sbostic #endif /* not lint */
1447129Sbostic
1547129Sbostic /*
1647129Sbostic * Miscelaneous builtins.
1747129Sbostic */
1847129Sbostic
1968925Sbostic #include <sys/types.h>
2068925Sbostic #include <sys/stat.h>
21*69272Schristos #include <sys/time.h>
22*69272Schristos #include <sys/resource.h>
23*69272Schristos #include <unistd.h>
24*69272Schristos #include <ctype.h>
25*69272Schristos
2647129Sbostic #include "shell.h"
2747129Sbostic #include "options.h"
2847129Sbostic #include "var.h"
2947129Sbostic #include "output.h"
3047129Sbostic #include "memalloc.h"
3147129Sbostic #include "error.h"
3247129Sbostic #include "mystring.h"
3347129Sbostic
3447129Sbostic #undef eflag
3547129Sbostic
3647129Sbostic extern char **argptr; /* argument list for builtin command */
3747129Sbostic
3847129Sbostic
3947129Sbostic /*
4047129Sbostic * The read builtin. The -e option causes backslashes to escape the
4147129Sbostic * following character.
4247129Sbostic *
4347129Sbostic * This uses unbuffered input, which may be avoidable in some cases.
4447129Sbostic */
4547129Sbostic
46*69272Schristos int
readcmd(argc,argv)47*69272Schristos readcmd(argc, argv)
48*69272Schristos int argc;
49*69272Schristos char **argv;
50*69272Schristos {
5147129Sbostic char **ap;
5247129Sbostic int backslash;
5347129Sbostic char c;
5447129Sbostic int eflag;
5547129Sbostic char *prompt;
5647129Sbostic char *ifs;
5747129Sbostic char *p;
5847129Sbostic int startword;
5947129Sbostic int status;
6047129Sbostic int i;
6147129Sbostic
6247129Sbostic eflag = 0;
6347129Sbostic prompt = NULL;
6447297Smarc while ((i = nextopt("ep:")) != '\0') {
6547129Sbostic if (i == 'p')
6647129Sbostic prompt = optarg;
6747129Sbostic else
6847129Sbostic eflag = 1;
6947129Sbostic }
7047129Sbostic if (prompt && isatty(0)) {
7147129Sbostic out2str(prompt);
7247129Sbostic flushall();
7347129Sbostic }
7466823Sbostic if (*(ap = argptr) == NULL)
7547129Sbostic error("arg count");
7647129Sbostic if ((ifs = bltinlookup("IFS", 1)) == NULL)
7747129Sbostic ifs = nullstr;
7847129Sbostic status = 0;
7947129Sbostic startword = 1;
8047129Sbostic backslash = 0;
8147129Sbostic STARTSTACKSTR(p);
8247129Sbostic for (;;) {
8347129Sbostic if (read(0, &c, 1) != 1) {
8447129Sbostic status = 1;
8547129Sbostic break;
8647129Sbostic }
8747129Sbostic if (c == '\0')
8847129Sbostic continue;
8947129Sbostic if (backslash) {
9047129Sbostic backslash = 0;
9147129Sbostic if (c != '\n')
9247129Sbostic STPUTC(c, p);
9347129Sbostic continue;
9447129Sbostic }
9547129Sbostic if (eflag && c == '\\') {
9647129Sbostic backslash++;
9747129Sbostic continue;
9847129Sbostic }
9947129Sbostic if (c == '\n')
10047129Sbostic break;
10147129Sbostic if (startword && *ifs == ' ' && strchr(ifs, c)) {
10247129Sbostic continue;
10347129Sbostic }
10447129Sbostic startword = 0;
10547129Sbostic if (backslash && c == '\\') {
10647129Sbostic if (read(0, &c, 1) != 1) {
10747129Sbostic status = 1;
10847129Sbostic break;
10947129Sbostic }
11047129Sbostic STPUTC(c, p);
11147129Sbostic } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
11247129Sbostic STACKSTRNUL(p);
11347129Sbostic setvar(*ap, stackblock(), 0);
11447129Sbostic ap++;
11547129Sbostic startword = 1;
11647129Sbostic STARTSTACKSTR(p);
11747129Sbostic } else {
11847129Sbostic STPUTC(c, p);
11947129Sbostic }
12047129Sbostic }
12147129Sbostic STACKSTRNUL(p);
12247129Sbostic setvar(*ap, stackblock(), 0);
12347129Sbostic while (*++ap != NULL)
12447129Sbostic setvar(*ap, nullstr, 0);
12547129Sbostic return status;
12647129Sbostic }
12747129Sbostic
12847129Sbostic
12947129Sbostic
130*69272Schristos int
umaskcmd(argc,argv)131*69272Schristos umaskcmd(argc, argv)
132*69272Schristos int argc;
133*69272Schristos char **argv;
134*69272Schristos {
13568925Sbostic char *ap;
13647129Sbostic int mask;
13747129Sbostic int i;
13868925Sbostic int symbolic_mode = 0;
13947129Sbostic
14068925Sbostic while ((i = nextopt("S")) != '\0') {
14168925Sbostic symbolic_mode = 1;
14268925Sbostic }
14368925Sbostic
14468925Sbostic INTOFF;
14568925Sbostic mask = umask(0);
14668925Sbostic umask(mask);
14768925Sbostic INTON;
14868925Sbostic
14968925Sbostic if ((ap = *argptr) == NULL) {
15068925Sbostic if (symbolic_mode) {
15168925Sbostic char u[4], g[4], o[4];
15268925Sbostic
15368925Sbostic i = 0;
15468925Sbostic if ((mask & S_IRUSR) == 0)
15568925Sbostic u[i++] = 'r';
15668925Sbostic if ((mask & S_IWUSR) == 0)
15768925Sbostic u[i++] = 'w';
15868925Sbostic if ((mask & S_IXUSR) == 0)
15968925Sbostic u[i++] = 'x';
16068925Sbostic u[i] = '\0';
16168925Sbostic
16268925Sbostic i = 0;
16368925Sbostic if ((mask & S_IRGRP) == 0)
16468925Sbostic g[i++] = 'r';
16568925Sbostic if ((mask & S_IWGRP) == 0)
16668925Sbostic g[i++] = 'w';
16768925Sbostic if ((mask & S_IXGRP) == 0)
16868925Sbostic g[i++] = 'x';
16968925Sbostic g[i] = '\0';
17068925Sbostic
17168925Sbostic i = 0;
17268925Sbostic if ((mask & S_IROTH) == 0)
17368925Sbostic o[i++] = 'r';
17468925Sbostic if ((mask & S_IWOTH) == 0)
17568925Sbostic o[i++] = 'w';
17668925Sbostic if ((mask & S_IXOTH) == 0)
17768925Sbostic o[i++] = 'x';
17868925Sbostic o[i] = '\0';
17968925Sbostic
18068925Sbostic out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
18168925Sbostic } else {
18268925Sbostic out1fmt("%.4o\n", mask);
18368925Sbostic }
18447129Sbostic } else {
18568925Sbostic if (isdigit(*ap)) {
18668925Sbostic mask = 0;
18768925Sbostic do {
18868925Sbostic if (*ap >= '8' || *ap < '0')
18968925Sbostic error("Illegal number: %s", argv[1]);
19068925Sbostic mask = (mask << 3) + (*ap - '0');
19168925Sbostic } while (*++ap != '\0');
19268925Sbostic umask(mask);
19368925Sbostic } else {
19468925Sbostic void *set;
19568925Sbostic if ((set = setmode (ap)) == 0)
19668925Sbostic error("Illegal number: %s", ap);
19768925Sbostic
19868925Sbostic mask = getmode (set, ~mask & 0777);
19968925Sbostic umask(~mask & 0777);
20068925Sbostic }
20147129Sbostic }
20247129Sbostic return 0;
20347129Sbostic }
204*69272Schristos
205*69272Schristos /*
206*69272Schristos * ulimit builtin
207*69272Schristos *
208*69272Schristos * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
209*69272Schristos * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
210*69272Schristos * ash by J.T. Conklin.
211*69272Schristos *
212*69272Schristos * Public domain.
213*69272Schristos */
214*69272Schristos
215*69272Schristos struct limits {
216*69272Schristos const char *name;
217*69272Schristos int cmd;
218*69272Schristos int factor; /* multiply by to get rlim_{cur,max} values */
219*69272Schristos char option;
220*69272Schristos };
221*69272Schristos
222*69272Schristos static const struct limits limits[] = {
223*69272Schristos #ifdef RLIMIT_CPU
224*69272Schristos { "time(seconds)", RLIMIT_CPU, 1, 't' },
225*69272Schristos #endif
226*69272Schristos #ifdef RLIMIT_FSIZE
227*69272Schristos { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
228*69272Schristos #endif
229*69272Schristos #ifdef RLIMIT_DATA
230*69272Schristos { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
231*69272Schristos #endif
232*69272Schristos #ifdef RLIMIT_STACK
233*69272Schristos { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
234*69272Schristos #endif
235*69272Schristos #ifdef RLIMIT_CORE
236*69272Schristos { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
237*69272Schristos #endif
238*69272Schristos #ifdef RLIMIT_RSS
239*69272Schristos { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
240*69272Schristos #endif
241*69272Schristos #ifdef RLIMIT_MEMLOCK
242*69272Schristos { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
243*69272Schristos #endif
244*69272Schristos #ifdef RLIMIT_NPROC
245*69272Schristos { "process(processes)", RLIMIT_NPROC, 1, 'p' },
246*69272Schristos #endif
247*69272Schristos #ifdef RLIMIT_NOFILE
248*69272Schristos { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
249*69272Schristos #endif
250*69272Schristos #ifdef RLIMIT_VMEM
251*69272Schristos { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
252*69272Schristos #endif
253*69272Schristos #ifdef RLIMIT_SWAP
254*69272Schristos { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
255*69272Schristos #endif
256*69272Schristos { (char *) 0, 0, 0, '\0' }
257*69272Schristos };
258*69272Schristos
259*69272Schristos int
ulimitcmd(argc,argv)260*69272Schristos ulimitcmd(argc, argv)
261*69272Schristos int argc;
262*69272Schristos char **argv;
263*69272Schristos {
264*69272Schristos register int c;
265*69272Schristos quad_t val;
266*69272Schristos enum { SOFT = 0x1, HARD = 0x2 }
267*69272Schristos how = SOFT | HARD;
268*69272Schristos const struct limits *l;
269*69272Schristos int set, all = 0;
270*69272Schristos int optc, what;
271*69272Schristos struct rlimit limit;
272*69272Schristos
273*69272Schristos what = 'f';
274*69272Schristos while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
275*69272Schristos switch (optc) {
276*69272Schristos case 'H':
277*69272Schristos how = HARD;
278*69272Schristos break;
279*69272Schristos case 'S':
280*69272Schristos how = SOFT;
281*69272Schristos break;
282*69272Schristos case 'a':
283*69272Schristos all = 1;
284*69272Schristos break;
285*69272Schristos default:
286*69272Schristos what = optc;
287*69272Schristos }
288*69272Schristos
289*69272Schristos for (l = limits; l->name && l->option != what; l++)
290*69272Schristos ;
291*69272Schristos if (!l->name)
292*69272Schristos error("ulimit: internal error (%c)\n", what);
293*69272Schristos
294*69272Schristos set = *argptr ? 1 : 0;
295*69272Schristos if (set) {
296*69272Schristos char *p = *argptr;
297*69272Schristos
298*69272Schristos if (all || argptr[1])
299*69272Schristos error("ulimit: too many arguments\n");
300*69272Schristos if (strcmp(p, "unlimited") == 0)
301*69272Schristos val = RLIM_INFINITY;
302*69272Schristos else {
303*69272Schristos val = (quad_t) 0;
304*69272Schristos
305*69272Schristos while ((c = *p++) >= '0' && c <= '9')
306*69272Schristos {
307*69272Schristos val = (val * 10) + (long)(c - '0');
308*69272Schristos if (val < (quad_t) 0)
309*69272Schristos break;
310*69272Schristos }
311*69272Schristos if (c)
312*69272Schristos error("ulimit: bad number\n");
313*69272Schristos val *= l->factor;
314*69272Schristos }
315*69272Schristos }
316*69272Schristos if (all) {
317*69272Schristos for (l = limits; l->name; l++) {
318*69272Schristos getrlimit(l->cmd, &limit);
319*69272Schristos if (how & SOFT)
320*69272Schristos val = limit.rlim_cur;
321*69272Schristos else if (how & HARD)
322*69272Schristos val = limit.rlim_max;
323*69272Schristos
324*69272Schristos out1fmt("%-20s ", l->name);
325*69272Schristos if (val == RLIM_INFINITY)
326*69272Schristos out1fmt("unlimited\n");
327*69272Schristos else
328*69272Schristos {
329*69272Schristos val /= l->factor;
330*69272Schristos out1fmt("%ld\n", (long) val);
331*69272Schristos }
332*69272Schristos }
333*69272Schristos return 0;
334*69272Schristos }
335*69272Schristos
336*69272Schristos getrlimit(l->cmd, &limit);
337*69272Schristos if (set) {
338*69272Schristos if (how & SOFT)
339*69272Schristos limit.rlim_cur = val;
340*69272Schristos if (how & HARD)
341*69272Schristos limit.rlim_max = val;
342*69272Schristos if (setrlimit(l->cmd, &limit) < 0)
343*69272Schristos error("ulimit: bad limit\n");
344*69272Schristos } else {
345*69272Schristos if (how & SOFT)
346*69272Schristos val = limit.rlim_cur;
347*69272Schristos else if (how & HARD)
348*69272Schristos val = limit.rlim_max;
349*69272Schristos }
350*69272Schristos
351*69272Schristos if (!set) {
352*69272Schristos if (val == RLIM_INFINITY)
353*69272Schristos out1fmt("unlimited\n");
354*69272Schristos else
355*69272Schristos {
356*69272Schristos val /= l->factor;
357*69272Schristos out1fmt("%ld\n", (long) val);
358*69272Schristos }
359*69272Schristos }
360*69272Schristos return 0;
361*69272Schristos }
362