]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - bin/sh/miscbltin.c
Merge branch 'releng/11.3' into releng-CDN/11.3
[FreeBSD/FreeBSD.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         ptrdiff_t lastnonifs, lastnonifsws;
104         struct timeval tv;
105         char *tvptr;
106         fd_set ifds;
107         ssize_t nread;
108         int sig;
109
110         rflag = 0;
111         prompt = NULL;
112         tv.tv_sec = -1;
113         tv.tv_usec = 0;
114         while ((i = nextopt("erp:t:")) != '\0') {
115                 switch(i) {
116                 case 'p':
117                         prompt = shoptarg;
118                         break;
119                 case 'e':
120                         break;
121                 case 'r':
122                         rflag = 1;
123                         break;
124                 case 't':
125                         tv.tv_sec = strtol(shoptarg, &tvptr, 0);
126                         if (tvptr == shoptarg)
127                                 error("timeout value");
128                         switch(*tvptr) {
129                         case 0:
130                         case 's':
131                                 break;
132                         case 'h':
133                                 tv.tv_sec *= 60;
134                                 /* FALLTHROUGH */
135                         case 'm':
136                                 tv.tv_sec *= 60;
137                                 break;
138                         default:
139                                 error("timeout unit");
140                         }
141                         break;
142                 }
143         }
144         if (prompt && isatty(0)) {
145                 out2str(prompt);
146                 flushall();
147         }
148         if (*(ap = argptr) == NULL)
149                 error("arg count");
150         if ((ifs = bltinlookup("IFS", 1)) == NULL)
151                 ifs = " \t\n";
152
153         if (tv.tv_sec >= 0) {
154                 /*
155                  * Wait for something to become available.
156                  */
157                 FD_ZERO(&ifds);
158                 FD_SET(0, &ifds);
159                 status = select(1, &ifds, NULL, NULL, &tv);
160                 /*
161                  * If there's nothing ready, return an error.
162                  */
163                 if (status <= 0) {
164                         sig = pendingsig;
165                         return (128 + (sig != 0 ? sig : SIGALRM));
166                 }
167         }
168
169         status = 0;
170         startword = 2;
171         backslash = 0;
172         STARTSTACKSTR(p);
173         lastnonifs = lastnonifsws = -1;
174         for (;;) {
175                 nread = read(STDIN_FILENO, &c, 1);
176                 if (nread == -1) {
177                         if (errno == EINTR) {
178                                 sig = pendingsig;
179                                 if (sig == 0)
180                                         continue;
181                                 status = 128 + sig;
182                                 break;
183                         }
184                         warning("read error: %s", strerror(errno));
185                         status = 2;
186                         break;
187                 } else if (nread != 1) {
188                         status = 1;
189                         break;
190                 }
191                 if (c == '\0')
192                         continue;
193                 CHECKSTRSPACE(1, p);
194                 if (backslash) {
195                         backslash = 0;
196                         if (c != '\n') {
197                                 startword = 0;
198                                 lastnonifs = lastnonifsws = p - stackblock();
199                                 USTPUTC(c, p);
200                         }
201                         continue;
202                 }
203                 if (!rflag && c == '\\') {
204                         backslash++;
205                         continue;
206                 }
207                 if (c == '\n')
208                         break;
209                 if (strchr(ifs, c))
210                         is_ifs = strchr(" \t\n", c) ? 1 : 2;
211                 else
212                         is_ifs = 0;
213
214                 if (startword != 0) {
215                         if (is_ifs == 1) {
216                                 /* Ignore leading IFS whitespace */
217                                 if (saveall)
218                                         USTPUTC(c, p);
219                                 continue;
220                         }
221                         if (is_ifs == 2 && startword == 1) {
222                                 /* Only one non-whitespace IFS per word */
223                                 startword = 2;
224                                 if (saveall) {
225                                         lastnonifsws = p - stackblock();
226                                         USTPUTC(c, p);
227                                 }
228                                 continue;
229                         }
230                 }
231
232                 if (is_ifs == 0) {
233                         /* append this character to the current variable */
234                         startword = 0;
235                         if (saveall)
236                                 /* Not just a spare terminator */
237                                 saveall++;
238                         lastnonifs = lastnonifsws = p - stackblock();
239                         USTPUTC(c, p);
240                         continue;
241                 }
242
243                 /* end of variable... */
244                 startword = is_ifs;
245
246                 if (ap[1] == NULL) {
247                         /* Last variable needs all IFS chars */
248                         saveall++;
249                         if (is_ifs == 2)
250                                 lastnonifsws = p - stackblock();
251                         USTPUTC(c, p);
252                         continue;
253                 }
254
255                 STACKSTRNUL(p);
256                 setvar(*ap, stackblock(), 0);
257                 ap++;
258                 STARTSTACKSTR(p);
259                 lastnonifs = lastnonifsws = -1;
260         }
261         STACKSTRNUL(p);
262
263         /*
264          * Remove trailing IFS chars: always remove whitespace, don't remove
265          * non-whitespace unless it was naked
266          */
267         if (saveall <= 1)
268                 lastnonifsws = lastnonifs;
269         stackblock()[lastnonifsws + 1] = '\0';
270         setvar(*ap, stackblock(), 0);
271
272         /* Set any remaining args to "" */
273         while (*++ap != NULL)
274                 setvar(*ap, "", 0);
275         return status;
276 }
277
278
279
280 int
281 umaskcmd(int argc __unused, char **argv __unused)
282 {
283         char *ap;
284         int mask;
285         int i;
286         int symbolic_mode = 0;
287
288         while ((i = nextopt("S")) != '\0') {
289                 symbolic_mode = 1;
290         }
291
292         INTOFF;
293         mask = umask(0);
294         umask(mask);
295         INTON;
296
297         if ((ap = *argptr) == NULL) {
298                 if (symbolic_mode) {
299                         char u[4], g[4], o[4];
300
301                         i = 0;
302                         if ((mask & S_IRUSR) == 0)
303                                 u[i++] = 'r';
304                         if ((mask & S_IWUSR) == 0)
305                                 u[i++] = 'w';
306                         if ((mask & S_IXUSR) == 0)
307                                 u[i++] = 'x';
308                         u[i] = '\0';
309
310                         i = 0;
311                         if ((mask & S_IRGRP) == 0)
312                                 g[i++] = 'r';
313                         if ((mask & S_IWGRP) == 0)
314                                 g[i++] = 'w';
315                         if ((mask & S_IXGRP) == 0)
316                                 g[i++] = 'x';
317                         g[i] = '\0';
318
319                         i = 0;
320                         if ((mask & S_IROTH) == 0)
321                                 o[i++] = 'r';
322                         if ((mask & S_IWOTH) == 0)
323                                 o[i++] = 'w';
324                         if ((mask & S_IXOTH) == 0)
325                                 o[i++] = 'x';
326                         o[i] = '\0';
327
328                         out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
329                 } else {
330                         out1fmt("%.4o\n", mask);
331                 }
332         } else {
333                 if (is_digit(*ap)) {
334                         mask = 0;
335                         do {
336                                 if (*ap >= '8' || *ap < '0')
337                                         error("Illegal number: %s", *argptr);
338                                 mask = (mask << 3) + (*ap - '0');
339                         } while (*++ap != '\0');
340                         umask(mask);
341                 } else {
342                         void *set;
343                         INTOFF;
344                         if ((set = setmode (ap)) == NULL)
345                                 error("Illegal number: %s", ap);
346
347                         mask = getmode (set, ~mask & 0777);
348                         umask(~mask & 0777);
349                         free(set);
350                         INTON;
351                 }
352         }
353         return 0;
354 }
355
356 /*
357  * ulimit builtin
358  *
359  * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
360  * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
361  * ash by J.T. Conklin.
362  *
363  * Public domain.
364  */
365
366 struct limits {
367         const char *name;
368         const char *units;
369         int     cmd;
370         int     factor; /* multiply by to get rlim_{cur,max} values */
371         char    option;
372 };
373
374 static const struct limits limits[] = {
375 #ifdef RLIMIT_CPU
376         { "cpu time",           "seconds",      RLIMIT_CPU,        1, 't' },
377 #endif
378 #ifdef RLIMIT_FSIZE
379         { "file size",          "512-blocks",   RLIMIT_FSIZE,    512, 'f' },
380 #endif
381 #ifdef RLIMIT_DATA
382         { "data seg size",      "kbytes",       RLIMIT_DATA,    1024, 'd' },
383 #endif
384 #ifdef RLIMIT_STACK
385         { "stack size",         "kbytes",       RLIMIT_STACK,   1024, 's' },
386 #endif
387 #ifdef  RLIMIT_CORE
388         { "core file size",     "512-blocks",   RLIMIT_CORE,     512, 'c' },
389 #endif
390 #ifdef RLIMIT_RSS
391         { "max memory size",    "kbytes",       RLIMIT_RSS,     1024, 'm' },
392 #endif
393 #ifdef RLIMIT_MEMLOCK
394         { "locked memory",      "kbytes",       RLIMIT_MEMLOCK, 1024, 'l' },
395 #endif
396 #ifdef RLIMIT_NPROC
397         { "max user processes", (char *)0,      RLIMIT_NPROC,      1, 'u' },
398 #endif
399 #ifdef RLIMIT_NOFILE
400         { "open files",         (char *)0,      RLIMIT_NOFILE,     1, 'n' },
401 #endif
402 #ifdef RLIMIT_VMEM
403         { "virtual mem size",   "kbytes",       RLIMIT_VMEM,    1024, 'v' },
404 #endif
405 #ifdef RLIMIT_SWAP
406         { "swap limit",         "kbytes",       RLIMIT_SWAP,    1024, 'w' },
407 #endif
408 #ifdef RLIMIT_SBSIZE
409         { "socket buffer size", "bytes",        RLIMIT_SBSIZE,     1, 'b' },
410 #endif
411 #ifdef RLIMIT_NPTS
412         { "pseudo-terminals",   (char *)0,      RLIMIT_NPTS,       1, 'p' },
413 #endif
414 #ifdef RLIMIT_KQUEUES
415         { "kqueues",            (char *)0,      RLIMIT_KQUEUES,    1, 'k' },
416 #endif
417 #ifdef RLIMIT_UMTXP
418         { "umtx shared locks",  (char *)0,      RLIMIT_UMTXP,      1, 'o' },
419 #endif
420         { (char *) 0,           (char *)0,      0,                 0, '\0' }
421 };
422
423 enum limithow { SOFT = 0x1, HARD = 0x2 };
424
425 static void
426 printlimit(enum limithow how, const struct rlimit *limit,
427     const struct limits *l)
428 {
429         rlim_t val = 0;
430
431         if (how & SOFT)
432                 val = limit->rlim_cur;
433         else if (how & HARD)
434                 val = limit->rlim_max;
435         if (val == RLIM_INFINITY)
436                 out1str("unlimited\n");
437         else
438         {
439                 val /= l->factor;
440                 out1fmt("%jd\n", (intmax_t)val);
441         }
442 }
443
444 int
445 ulimitcmd(int argc __unused, char **argv __unused)
446 {
447         rlim_t val = 0;
448         enum limithow how = SOFT | HARD;
449         const struct limits     *l;
450         int             set, all = 0;
451         int             optc, what;
452         struct rlimit   limit;
453
454         what = 'f';
455         while ((optc = nextopt("HSatfdsmcnuvlbpwko")) != '\0')
456                 switch (optc) {
457                 case 'H':
458                         how = HARD;
459                         break;
460                 case 'S':
461                         how = SOFT;
462                         break;
463                 case 'a':
464                         all = 1;
465                         break;
466                 default:
467                         what = optc;
468                 }
469
470         for (l = limits; l->name && l->option != what; l++)
471                 ;
472         if (!l->name)
473                 error("internal error (%c)", what);
474
475         set = *argptr ? 1 : 0;
476         if (set) {
477                 char *p = *argptr;
478
479                 if (all || argptr[1])
480                         error("too many arguments");
481                 if (strcmp(p, "unlimited") == 0)
482                         val = RLIM_INFINITY;
483                 else {
484                         char *end;
485                         uintmax_t uval;
486
487                         if (*p < '0' || *p > '9')
488                                 error("bad number");
489                         errno = 0;
490                         uval = strtoumax(p, &end, 10);
491                         if (errno != 0 || *end != '\0')
492                                 error("bad number");
493                         if (uval > UINTMAX_MAX / l->factor)
494                                 error("bad number");
495                         uval *= l->factor;
496                         val = (rlim_t)uval;
497                         if (val < 0 || (uintmax_t)val != uval ||
498                             val == RLIM_INFINITY)
499                                 error("bad number");
500                 }
501         }
502         if (all) {
503                 for (l = limits; l->name; l++) {
504                         char optbuf[40];
505                         if (getrlimit(l->cmd, &limit) < 0)
506                                 error("can't get limit: %s", strerror(errno));
507
508                         if (l->units)
509                                 snprintf(optbuf, sizeof(optbuf),
510                                         "(%s, -%c) ", l->units, l->option);
511                         else
512                                 snprintf(optbuf, sizeof(optbuf),
513                                         "(-%c) ", l->option);
514                         out1fmt("%-18s %18s ", l->name, optbuf);
515                         printlimit(how, &limit, l);
516                 }
517                 return 0;
518         }
519
520         if (getrlimit(l->cmd, &limit) < 0)
521                 error("can't get limit: %s", strerror(errno));
522         if (set) {
523                 if (how & SOFT)
524                         limit.rlim_cur = val;
525                 if (how & HARD)
526                         limit.rlim_max = val;
527                 if (setrlimit(l->cmd, &limit) < 0)
528                         error("bad limit: %s", strerror(errno));
529         } else
530                 printlimit(how, &limit, l);
531         return 0;
532 }