diff options
Diffstat (limited to 'src/miscbltin.c')
-rw-r--r-- | src/miscbltin.c | 472 |
1 files changed, 472 insertions, 0 deletions
diff --git a/src/miscbltin.c b/src/miscbltin.c new file mode 100644 index 0000000..8472d79 --- /dev/null +++ b/src/miscbltin.c @@ -0,0 +1,472 @@ +/* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Kenneth Almquist. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#ifndef lint +#if 0 +static char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95"; +#else +__RCSID("$NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $"); +#endif +#endif /* not lint */ + +/* + * Miscelaneous builtins. + */ + +#include <sys/types.h> /* quad_t */ +#include <sys/param.h> /* BSD4_4 */ +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <unistd.h> +#include <stdlib.h> +#include <ctype.h> +#include <stdint.h> + +#include "shell.h" +#include "options.h" +#include "var.h" +#include "output.h" +#include "memalloc.h" +#include "error.h" +#include "miscbltin.h" +#include "mystring.h" +#include "main.h" + +#undef rflag + +#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 +typedef enum __rlimit_resource rlim_t; +#endif + + + +/* + * The read builtin. The -e option causes backslashes to escape the + * following character. + * + * This uses unbuffered input, which may be avoidable in some cases. + */ + +int +readcmd(int argc, char **argv) +{ + char **ap; + int backslash; + char c; + int rflag; + char *prompt; + const char *ifs; + char *p; + int startword; + int status; + int i; + + rflag = 0; + prompt = NULL; + while ((i = nextopt("p:r")) != '\0') { + if (i == 'p') + prompt = optionarg; + else + rflag = 1; + } + if (prompt && isatty(0)) { + out2str(prompt); +#ifdef FLUSHERR + flushall(); +#endif + } + if (*(ap = argptr) == NULL) + error("arg count"); + if ((ifs = bltinlookup("IFS")) == NULL) + ifs = defifs; + status = 0; + startword = 1; + backslash = 0; + STARTSTACKSTR(p); + for (;;) { + if (read(0, &c, 1) != 1) { + status = 1; + break; + } + if (c == '\0') + continue; + if (backslash) { + backslash = 0; + if (c != '\n') + goto put; + continue; + } + if (!rflag && c == '\\') { + backslash++; + continue; + } + if (c == '\n') + break; + if (startword && *ifs == ' ' && strchr(ifs, c)) { + continue; + } + startword = 0; + if (ap[1] != NULL && strchr(ifs, c) != NULL) { + STACKSTRNUL(p); + setvar(*ap, stackblock(), 0); + ap++; + startword = 1; + STARTSTACKSTR(p); + } else { +put: + STPUTC(c, p); + } + } + STACKSTRNUL(p); + /* Remove trailing blanks */ + while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL) + *p = '\0'; + setvar(*ap, stackblock(), 0); + while (*++ap != NULL) + setvar(*ap, nullstr, 0); + return status; +} + + + +/* + * umask builtin + * + * This code was ripped from pdksh 5.2.14 and hacked for use with + * dash by Herbert Xu. + * + * Public domain. + */ + +int +umaskcmd(int argc, char **argv) +{ + char *ap; + int mask; + int i; + int symbolic_mode = 0; + + while ((i = nextopt("S")) != '\0') { + symbolic_mode = 1; + } + + INTOFF; + mask = umask(0); + umask(mask); + INTON; + + if ((ap = *argptr) == NULL) { + if (symbolic_mode) { + char buf[18]; + int j; + + mask = ~mask; + ap = buf; + for (i = 0; i < 3; i++) { + *ap++ = "ugo"[i]; + *ap++ = '='; + for (j = 0; j < 3; j++) + if (mask & (1 << (8 - (3*i + j)))) + *ap++ = "rwx"[j]; + *ap++ = ','; + } + ap[-1] = '\0'; + out1fmt("%s\n", buf); + } else { + out1fmt("%.4o\n", mask); + } + } else { + int new_mask; + + if (isdigit(*ap)) { + new_mask = 0; + do { + if (*ap >= '8' || *ap < '0') + error(illnum, *argptr); + new_mask = (new_mask << 3) + (*ap - '0'); + } while (*++ap != '\0'); + } else { + int positions, new_val; + char op; + + mask = ~mask; + new_mask = mask; + positions = 0; + while (*ap) { + while (*ap && strchr("augo", *ap)) + switch (*ap++) { + case 'a': positions |= 0111; break; + case 'u': positions |= 0100; break; + case 'g': positions |= 0010; break; + case 'o': positions |= 0001; break; + } + if (!positions) + positions = 0111; /* default is a */ + if (!strchr("=+-", op = *ap)) + break; + ap++; + new_val = 0; + while (*ap && strchr("rwxugoXs", *ap)) + switch (*ap++) { + case 'r': new_val |= 04; break; + case 'w': new_val |= 02; break; + case 'x': new_val |= 01; break; + case 'u': new_val |= mask >> 6; + break; + case 'g': new_val |= mask >> 3; + break; + case 'o': new_val |= mask >> 0; + break; + case 'X': if (mask & 0111) + new_val |= 01; + break; + case 's': /* ignored */ + break; + } + new_val = (new_val & 07) * positions; + switch (op) { + case '-': + new_mask &= ~new_val; + break; + case '=': + new_mask = new_val + | (new_mask & ~(positions * 07)); + break; + case '+': + new_mask |= new_val; + } + if (*ap == ',') { + positions = 0; + ap++; + } else if (!strchr("=+-", *ap)) + break; + } + if (*ap) { + error("Illegal mode: %s", *argptr); + return 1; + } + new_mask = ~new_mask; + } + umask(new_mask); + } + return 0; +} + +/* + * ulimit builtin + * + * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and + * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with + * ash by J.T. Conklin. + * + * Public domain. + */ + +struct limits { + const char *name; + int cmd; + int factor; /* multiply by to get rlim_{cur,max} values */ + char option; +}; + +static const struct limits limits[] = { +#ifdef RLIMIT_CPU + { "time(seconds)", RLIMIT_CPU, 1, 't' }, +#endif +#ifdef RLIMIT_FSIZE + { "file(blocks)", RLIMIT_FSIZE, 512, 'f' }, +#endif +#ifdef RLIMIT_DATA + { "data(kbytes)", RLIMIT_DATA, 1024, 'd' }, +#endif +#ifdef RLIMIT_STACK + { "stack(kbytes)", RLIMIT_STACK, 1024, 's' }, +#endif +#ifdef RLIMIT_CORE + { "coredump(blocks)", RLIMIT_CORE, 512, 'c' }, +#endif +#ifdef RLIMIT_RSS + { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' }, +#endif +#ifdef RLIMIT_MEMLOCK + { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' }, +#endif +#ifdef RLIMIT_NPROC + { "process", RLIMIT_NPROC, 1, 'p' }, +#endif +#ifdef RLIMIT_NOFILE + { "nofiles", RLIMIT_NOFILE, 1, 'n' }, +#endif +#ifdef RLIMIT_AS + { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' }, +#endif +#ifdef RLIMIT_LOCKS + { "locks", RLIMIT_LOCKS, 1, 'w' }, +#endif + { (char *) 0, 0, 0, '\0' } +}; + +enum limtype { SOFT = 0x1, HARD = 0x2 }; + +static void printlim(enum limtype how, const struct rlimit *limit, + const struct limits *l) +{ + rlim_t val; + + val = limit->rlim_max; + if (how & SOFT) + val = limit->rlim_cur; + + if (val == RLIM_INFINITY) + out1fmt("unlimited\n"); + else { + val /= l->factor; + out1fmt("%jd\n", (intmax_t) val); + } +} + +int +ulimitcmd(int argc, char **argv) +{ + int c; + rlim_t val = 0; + enum limtype how = SOFT | HARD; + const struct limits *l; + int set, all = 0; + int optc, what; + struct rlimit limit; + + what = 'f'; + while ((optc = nextopt("HSa" +#ifdef RLIMIT_CPU + "t" +#endif +#ifdef RLIMIT_FSIZE + "f" +#endif +#ifdef RLIMIT_DATA + "d" +#endif +#ifdef RLIMIT_STACK + "s" +#endif +#ifdef RLIMIT_CORE + "c" +#endif +#ifdef RLIMIT_RSS + "m" +#endif +#ifdef RLIMIT_MEMLOCK + "l" +#endif +#ifdef RLIMIT_NPROC + "p" +#endif +#ifdef RLIMIT_NOFILE + "n" +#endif +#ifdef RLIMIT_AS + "v" +#endif +#ifdef RLIMIT_LOCKS + "w" +#endif + )) != '\0') + switch (optc) { + case 'H': + how = HARD; + break; + case 'S': + how = SOFT; + break; + case 'a': + all = 1; + break; + default: + what = optc; + } + + for (l = limits; l->option != what; l++) + ; + + set = *argptr ? 1 : 0; + if (set) { + char *p = *argptr; + + if (all || argptr[1]) + error("too many arguments"); + if (strcmp(p, "unlimited") == 0) + val = RLIM_INFINITY; + else { + val = (rlim_t) 0; + + while ((c = *p++) >= '0' && c <= '9') + { + val = (val * 10) + (long)(c - '0'); + if (val < (rlim_t) 0) + break; + } + if (c) + error("bad number"); + val *= l->factor; + } + } + if (all) { + for (l = limits; l->name; l++) { + getrlimit(l->cmd, &limit); + out1fmt("%-20s ", l->name); + printlim(how, &limit, l); + } + return 0; + } + + getrlimit(l->cmd, &limit); + if (set) { + if (how & HARD) + limit.rlim_max = val; + if (how & SOFT) + limit.rlim_cur = val; + if (setrlimit(l->cmd, &limit) < 0) + error("error setting limit (%s)", strerror(errno)); + } else { + printlim(how, &limit, l); + } + return 0; +} |