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