]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - bin/sh/miscbltin.c
Copy head (r256279) to stable/10 as part of the 10.0-RELEASE cycle.
[FreeBSD/stable/10.git] / bin / sh / miscbltin.c
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  * 4. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95";
36 #endif
37 #endif /* not lint */
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40
41 /*
42  * Miscellaneous builtins.
43  */
44
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <sys/time.h>
48 #include <sys/resource.h>
49 #include <unistd.h>
50 #include <errno.h>
51 #include <stdint.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54
55 #include "shell.h"
56 #include "options.h"
57 #include "var.h"
58 #include "output.h"
59 #include "memalloc.h"
60 #include "error.h"
61 #include "mystring.h"
62 #include "syntax.h"
63 #include "trap.h"
64
65 #undef eflag
66
67 int readcmd(int, char **);
68 int umaskcmd(int, char **);
69 int ulimitcmd(int, char **);
70
71 /*
72  * The read builtin.  The -r option causes backslashes to be treated like
73  * ordinary characters.
74  *
75  * This uses unbuffered input, which may be avoidable in some cases.
76  *
77  * Note that if IFS=' :' then read x y should work so that:
78  * 'a b'        x='a', y='b'
79  * ' a b '      x='a', y='b'
80  * ':b'         x='',  y='b'
81  * ':'          x='',  y=''
82  * '::'         x='',  y=''
83  * ': :'        x='',  y=''
84  * ':::'        x='',  y='::'
85  * ':b c:'      x='',  y='b c:'
86  */
87
88 int
89 readcmd(int argc __unused, char **argv __unused)
90 {
91         char **ap;
92         int backslash;
93         char c;
94         int rflag;
95         char *prompt;
96         const char *ifs;
97         char *p;
98         int startword;
99         int status;
100         int i;
101         int is_ifs;
102         int saveall = 0;
103         struct timeval tv;
104         char *tvptr;
105         fd_set ifds;
106         ssize_t nread;
107         int sig;
108
109         rflag = 0;
110         prompt = NULL;
111         tv.tv_sec = -1;
112         tv.tv_usec = 0;
113         while ((i = nextopt("erp:t:")) != '\0') {
114                 switch(i) {
115                 case 'p':
116                         prompt = shoptarg;
117                         break;
118                 case 'e':
119                         break;
120                 case 'r':
121                         rflag = 1;
122                         break;
123                 case 't':
124                         tv.tv_sec = strtol(shoptarg, &tvptr, 0);
125                         if (tvptr == shoptarg)
126                                 error("timeout value");
127                         switch(*tvptr) {
128                         case 0:
129                         case 's':
130                                 break;
131                         case 'h':
132                                 tv.tv_sec *= 60;
133                                 /* FALLTHROUGH */
134                         case 'm':
135                                 tv.tv_sec *= 60;
136                                 break;
137                         default:
138                                 error("timeout unit");
139                         }
140                         break;
141                 }
142         }
143         if (prompt && isatty(0)) {
144                 out2str(prompt);
145                 flushall();
146         }
147         if (*(ap = argptr) == NULL)
148                 error("arg count");
149         if ((ifs = bltinlookup("IFS", 1)) == NULL)
150                 ifs = " \t\n";
151
152         if (tv.tv_sec >= 0) {
153                 /*
154                  * Wait for something to become available.
155                  */
156                 FD_ZERO(&ifds);
157                 FD_SET(0, &ifds);
158                 status = select(1, &ifds, NULL, NULL, &tv);
159                 /*
160                  * If there's nothing ready, return an error.
161                  */
162                 if (status <= 0) {
163                         sig = pendingsig;
164                         return (128 + (sig != 0 ? sig : SIGALRM));
165                 }
166         }
167
168         status = 0;
169         startword = 2;
170         backslash = 0;
171         STARTSTACKSTR(p);
172         for (;;) {
173                 nread = read(STDIN_FILENO, &c, 1);
174                 if (nread == -1) {
175                         if (errno == EINTR) {
176                                 sig = pendingsig;
177                                 if (sig == 0)
178                                         continue;
179                                 status = 128 + sig;
180                                 break;
181                         }
182                         warning("read error: %s", strerror(errno));
183                         status = 2;
184                         break;
185                 } else if (nread != 1) {
186                         status = 1;
187                         break;
188                 }
189                 if (c == '\0')
190                         continue;
191                 CHECKSTRSPACE(1, p);
192                 if (backslash) {
193                         backslash = 0;
194                         startword = 0;
195                         if (c != '\n')
196                                 USTPUTC(c, p);
197                         continue;
198                 }
199                 if (!rflag && c == '\\') {
200                         backslash++;
201                         continue;
202                 }
203                 if (c == '\n')
204                         break;
205                 if (strchr(ifs, c))
206                         is_ifs = strchr(" \t\n", c) ? 1 : 2;
207                 else
208                         is_ifs = 0;
209
210                 if (startword != 0) {
211                         if (is_ifs == 1) {
212                                 /* Ignore leading IFS whitespace */
213                                 if (saveall)
214                                         USTPUTC(c, p);
215                                 continue;
216                         }
217                         if (is_ifs == 2 && startword == 1) {
218                                 /* Only one non-whitespace IFS per word */
219                                 startword = 2;
220                                 if (saveall)
221                                         USTPUTC(c, p);
222                                 continue;
223                         }
224                 }
225
226                 if (is_ifs == 0) {
227                         /* append this character to the current variable */
228                         startword = 0;
229                         if (saveall)
230                                 /* Not just a spare terminator */
231                                 saveall++;
232                         USTPUTC(c, p);
233                         continue;
234                 }
235
236                 /* end of variable... */
237                 startword = is_ifs;
238
239                 if (ap[1] == NULL) {
240                         /* Last variable needs all IFS chars */
241                         saveall++;
242                         USTPUTC(c, p);
243                         continue;
244                 }
245
246                 STACKSTRNUL(p);
247                 setvar(*ap, stackblock(), 0);
248                 ap++;
249                 STARTSTACKSTR(p);
250         }
251         STACKSTRNUL(p);
252
253         /* Remove trailing IFS chars */
254         for (; stackblock() <= --p; *p = 0) {
255                 if (!strchr(ifs, *p))
256                         break;
257                 if (strchr(" \t\n", *p))
258                         /* Always remove whitespace */
259                         continue;
260                 if (saveall > 1)
261                         /* Don't remove non-whitespace unless it was naked */
262                         break;
263         }
264         setvar(*ap, stackblock(), 0);
265
266         /* Set any remaining args to "" */
267         while (*++ap != NULL)
268                 setvar(*ap, nullstr, 0);
269         return status;
270 }
271
272
273
274 int
275 umaskcmd(int argc __unused, char **argv __unused)
276 {
277         char *ap;
278         int mask;
279         int i;
280         int symbolic_mode = 0;
281
282         while ((i = nextopt("S")) != '\0') {
283                 symbolic_mode = 1;
284         }
285
286         INTOFF;
287         mask = umask(0);
288         umask(mask);
289         INTON;
290
291         if ((ap = *argptr) == NULL) {
292                 if (symbolic_mode) {
293                         char u[4], g[4], o[4];
294
295                         i = 0;
296                         if ((mask & S_IRUSR) == 0)
297                                 u[i++] = 'r';
298                         if ((mask & S_IWUSR) == 0)
299                                 u[i++] = 'w';
300                         if ((mask & S_IXUSR) == 0)
301                                 u[i++] = 'x';
302                         u[i] = '\0';
303
304                         i = 0;
305                         if ((mask & S_IRGRP) == 0)
306                                 g[i++] = 'r';
307                         if ((mask & S_IWGRP) == 0)
308                                 g[i++] = 'w';
309                         if ((mask & S_IXGRP) == 0)
310                                 g[i++] = 'x';
311                         g[i] = '\0';
312
313                         i = 0;
314                         if ((mask & S_IROTH) == 0)
315                                 o[i++] = 'r';
316                         if ((mask & S_IWOTH) == 0)
317                                 o[i++] = 'w';
318                         if ((mask & S_IXOTH) == 0)
319                                 o[i++] = 'x';
320                         o[i] = '\0';
321
322                         out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
323                 } else {
324                         out1fmt("%.4o\n", mask);
325                 }
326         } else {
327                 if (is_digit(*ap)) {
328                         mask = 0;
329                         do {
330                                 if (*ap >= '8' || *ap < '0')
331                                         error("Illegal number: %s", *argptr);
332                                 mask = (mask << 3) + (*ap - '0');
333                         } while (*++ap != '\0');
334                         umask(mask);
335                 } else {
336                         void *set;
337                         INTOFF;
338                         if ((set = setmode (ap)) == 0)
339                                 error("Illegal number: %s", ap);
340
341                         mask = getmode (set, ~mask & 0777);
342                         umask(~mask & 0777);
343                         free(set);
344                         INTON;
345                 }
346         }
347         return 0;
348 }
349
350 /*
351  * ulimit builtin
352  *
353  * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
354  * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
355  * ash by J.T. Conklin.
356  *
357  * Public domain.
358  */
359
360 struct limits {
361         const char *name;
362         const char *units;
363         int     cmd;
364         int     factor; /* multiply by to get rlim_{cur,max} values */
365         char    option;
366 };
367
368 static const struct limits limits[] = {
369 #ifdef RLIMIT_CPU
370         { "cpu time",           "seconds",      RLIMIT_CPU,        1, 't' },
371 #endif
372 #ifdef RLIMIT_FSIZE
373         { "file size",          "512-blocks",   RLIMIT_FSIZE,    512, 'f' },
374 #endif
375 #ifdef RLIMIT_DATA
376         { "data seg size",      "kbytes",       RLIMIT_DATA,    1024, 'd' },
377 #endif
378 #ifdef RLIMIT_STACK
379         { "stack size",         "kbytes",       RLIMIT_STACK,   1024, 's' },
380 #endif
381 #ifdef  RLIMIT_CORE
382         { "core file size",     "512-blocks",   RLIMIT_CORE,     512, 'c' },
383 #endif
384 #ifdef RLIMIT_RSS
385         { "max memory size",    "kbytes",       RLIMIT_RSS,     1024, 'm' },
386 #endif
387 #ifdef RLIMIT_MEMLOCK
388         { "locked memory",      "kbytes",       RLIMIT_MEMLOCK, 1024, 'l' },
389 #endif
390 #ifdef RLIMIT_NPROC
391         { "max user processes", (char *)0,      RLIMIT_NPROC,      1, 'u' },
392 #endif
393 #ifdef RLIMIT_NOFILE
394         { "open files",         (char *)0,      RLIMIT_NOFILE,     1, 'n' },
395 #endif
396 #ifdef RLIMIT_VMEM
397         { "virtual mem size",   "kbytes",       RLIMIT_VMEM,    1024, 'v' },
398 #endif
399 #ifdef RLIMIT_SWAP
400         { "swap limit",         "kbytes",       RLIMIT_SWAP,    1024, 'w' },
401 #endif
402 #ifdef RLIMIT_SBSIZE
403         { "sbsize",             "bytes",        RLIMIT_SBSIZE,     1, 'b' },
404 #endif
405 #ifdef RLIMIT_NPTS
406         { "pseudo-terminals",   (char *)0,      RLIMIT_NPTS,       1, 'p' },
407 #endif
408         { (char *) 0,           (char *)0,      0,                 0, '\0' }
409 };
410
411 int
412 ulimitcmd(int argc __unused, char **argv __unused)
413 {
414         int     c;
415         rlim_t val = 0;
416         enum { SOFT = 0x1, HARD = 0x2 }
417                         how = SOFT | HARD;
418         const struct limits     *l;
419         int             set, all = 0;
420         int             optc, what;
421         struct rlimit   limit;
422
423         what = 'f';
424         while ((optc = nextopt("HSatfdsmcnuvlbpw")) != '\0')
425                 switch (optc) {
426                 case 'H':
427                         how = HARD;
428                         break;
429                 case 'S':
430                         how = SOFT;
431                         break;
432                 case 'a':
433                         all = 1;
434                         break;
435                 default:
436                         what = optc;
437                 }
438
439         for (l = limits; l->name && l->option != what; l++)
440                 ;
441         if (!l->name)
442                 error("internal error (%c)", what);
443
444         set = *argptr ? 1 : 0;
445         if (set) {
446                 char *p = *argptr;
447
448                 if (all || argptr[1])
449                         error("too many arguments");
450                 if (strcmp(p, "unlimited") == 0)
451                         val = RLIM_INFINITY;
452                 else {
453                         val = 0;
454
455                         while ((c = *p++) >= '0' && c <= '9')
456                         {
457                                 val = (val * 10) + (long)(c - '0');
458                                 if (val < 0)
459                                         break;
460                         }
461                         if (c)
462                                 error("bad number");
463                         val *= l->factor;
464                 }
465         }
466         if (all) {
467                 for (l = limits; l->name; l++) {
468                         char optbuf[40];
469                         if (getrlimit(l->cmd, &limit) < 0)
470                                 error("can't get limit: %s", strerror(errno));
471                         if (how & SOFT)
472                                 val = limit.rlim_cur;
473                         else if (how & HARD)
474                                 val = limit.rlim_max;
475
476                         if (l->units)
477                                 snprintf(optbuf, sizeof(optbuf),
478                                         "(%s, -%c) ", l->units, l->option);
479                         else
480                                 snprintf(optbuf, sizeof(optbuf),
481                                         "(-%c) ", l->option);
482                         out1fmt("%-18s %18s ", l->name, optbuf);
483                         if (val == RLIM_INFINITY)
484                                 out1str("unlimited\n");
485                         else
486                         {
487                                 val /= l->factor;
488                                 out1fmt("%jd\n", (intmax_t)val);
489                         }
490                 }
491                 return 0;
492         }
493
494         if (getrlimit(l->cmd, &limit) < 0)
495                 error("can't get limit: %s", strerror(errno));
496         if (set) {
497                 if (how & SOFT)
498                         limit.rlim_cur = val;
499                 if (how & HARD)
500                         limit.rlim_max = val;
501                 if (setrlimit(l->cmd, &limit) < 0)
502                         error("bad limit: %s", strerror(errno));
503         } else {
504                 if (how & SOFT)
505                         val = limit.rlim_cur;
506                 else if (how & HARD)
507                         val = limit.rlim_max;
508
509                 if (val == RLIM_INFINITY)
510                         out1str("unlimited\n");
511                 else
512                 {
513                         val /= l->factor;
514                         out1fmt("%jd\n", (intmax_t)val);
515                 }
516         }
517         return 0;
518 }