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