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