miscbltin.c revision 267654
1189251Ssam/*- 2189251Ssam * Copyright (c) 1991, 1993 3189251Ssam * The Regents of the University of California. All rights reserved. 4189251Ssam * 5189251Ssam * This code is derived from software contributed to Berkeley by 6189251Ssam * Kenneth Almquist. 7189251Ssam * 8189251Ssam * Redistribution and use in source and binary forms, with or without 9189251Ssam * modification, are permitted provided that the following conditions 10189251Ssam * are met: 11189251Ssam * 1. Redistributions of source code must retain the above copyright 12189251Ssam * notice, this list of conditions and the following disclaimer. 13189251Ssam * 2. Redistributions in binary form must reproduce the above copyright 14189251Ssam * notice, this list of conditions and the following disclaimer in the 15189251Ssam * documentation and/or other materials provided with the distribution. 16189251Ssam * 4. Neither the name of the University nor the names of its contributors 17189251Ssam * may be used to endorse or promote products derived from this software 18189251Ssam * without specific prior written permission. 19189251Ssam * 20189251Ssam * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21189251Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22189251Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23189251Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24189251Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25189251Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26189251Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27189251Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28189251Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29189251Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30189251Ssam * SUCH DAMAGE. 31189251Ssam */ 32189251Ssam 33189251Ssam#ifndef lint 34189251Ssam#if 0 35189251Ssamstatic char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95"; 36189251Ssam#endif 37189251Ssam#endif /* not lint */ 38189251Ssam#include <sys/cdefs.h> 39189251Ssam__FBSDID("$FreeBSD: releng/9.3/bin/sh/miscbltin.c 221975 2011-05-15 22:09:27Z jilles $"); 40189251Ssam 41189251Ssam/* 42189251Ssam * Miscellaneous builtins. 43189251Ssam */ 44189251Ssam 45189251Ssam#include <sys/types.h> 46189251Ssam#include <sys/stat.h> 47189251Ssam#include <sys/time.h> 48189251Ssam#include <sys/resource.h> 49189251Ssam#include <unistd.h> 50189251Ssam#include <ctype.h> 51189251Ssam#include <errno.h> 52189251Ssam#include <stdint.h> 53189251Ssam#include <stdio.h> 54189251Ssam#include <stdlib.h> 55189251Ssam#include <termios.h> 56189251Ssam 57189251Ssam#include "shell.h" 58189251Ssam#include "options.h" 59189251Ssam#include "var.h" 60189251Ssam#include "output.h" 61189251Ssam#include "memalloc.h" 62189251Ssam#include "error.h" 63189251Ssam#include "mystring.h" 64189251Ssam 65189251Ssam#undef eflag 66189251Ssam 67189251Ssamint readcmd(int, char **); 68189251Ssamint umaskcmd(int, char **); 69189251Ssamint ulimitcmd(int, char **); 70189251Ssam 71189251Ssam/* 72189251Ssam * The read builtin. The -r option causes backslashes to be treated like 73189251Ssam * ordinary characters. 74189251Ssam * 75189251Ssam * This uses unbuffered input, which may be avoidable in some cases. 76189251Ssam * 77189251Ssam * Note that if IFS=' :' then read x y should work so that: 78189251Ssam * 'a b' x='a', y='b' 79189251Ssam * ' a b ' x='a', y='b' 80189251Ssam * ':b' x='', y='b' 81189251Ssam * ':' x='', y='' 82189251Ssam * '::' x='', y='' 83189251Ssam * ': :' x='', y='' 84189251Ssam * ':::' x='', y='::' 85189251Ssam * ':b c:' x='', y='b c:' 86189251Ssam */ 87189251Ssam 88189251Ssamint 89189251Ssamreadcmd(int argc __unused, char **argv __unused) 90189251Ssam{ 91189251Ssam char **ap; 92189251Ssam int backslash; 93189251Ssam char c; 94189251Ssam int rflag; 95189251Ssam char *prompt; 96189251Ssam const char *ifs; 97189251Ssam char *p; 98189251Ssam int startword; 99189251Ssam int status; 100189251Ssam int i; 101189251Ssam int is_ifs; 102189251Ssam int saveall = 0; 103189251Ssam struct timeval tv; 104189251Ssam char *tvptr; 105189251Ssam fd_set ifds; 106189251Ssam 107189251Ssam rflag = 0; 108189251Ssam prompt = NULL; 109189251Ssam tv.tv_sec = -1; 110189251Ssam tv.tv_usec = 0; 111189251Ssam while ((i = nextopt("erp:t:")) != '\0') { 112189251Ssam switch(i) { 113189251Ssam case 'p': 114189251Ssam prompt = shoptarg; 115189251Ssam break; 116189251Ssam case 'e': 117189251Ssam break; 118189251Ssam case 'r': 119189251Ssam rflag = 1; 120189251Ssam break; 121189251Ssam case 't': 122189251Ssam tv.tv_sec = strtol(shoptarg, &tvptr, 0); 123189251Ssam if (tvptr == shoptarg) 124189251Ssam error("timeout value"); 125189251Ssam switch(*tvptr) { 126189251Ssam case 0: 127189251Ssam case 's': 128189251Ssam break; 129189251Ssam case 'h': 130189251Ssam tv.tv_sec *= 60; 131189251Ssam /* FALLTHROUGH */ 132189251Ssam case 'm': 133189251Ssam tv.tv_sec *= 60; 134189251Ssam break; 135189251Ssam default: 136189251Ssam error("timeout unit"); 137189251Ssam } 138189251Ssam break; 139189251Ssam } 140189251Ssam } 141189251Ssam if (prompt && isatty(0)) { 142189251Ssam out2str(prompt); 143189251Ssam flushall(); 144189251Ssam } 145189251Ssam if (*(ap = argptr) == NULL) 146189251Ssam error("arg count"); 147189251Ssam if ((ifs = bltinlookup("IFS", 1)) == NULL) 148189251Ssam ifs = " \t\n"; 149189251Ssam 150189251Ssam if (tv.tv_sec >= 0) { 151189251Ssam /* 152189251Ssam * Wait for something to become available. 153189251Ssam */ 154189251Ssam FD_ZERO(&ifds); 155189251Ssam FD_SET(0, &ifds); 156189251Ssam status = select(1, &ifds, NULL, NULL, &tv); 157189251Ssam /* 158189251Ssam * If there's nothing ready, return an error. 159189251Ssam */ 160189251Ssam if (status <= 0) 161189251Ssam return(1); 162189251Ssam } 163189251Ssam 164189251Ssam status = 0; 165189251Ssam startword = 2; 166189251Ssam backslash = 0; 167189251Ssam STARTSTACKSTR(p); 168189251Ssam for (;;) { 169189251Ssam if (read(STDIN_FILENO, &c, 1) != 1) { 170189251Ssam status = 1; 171189251Ssam break; 172189251Ssam } 173189251Ssam if (c == '\0') 174189251Ssam continue; 175189251Ssam CHECKSTRSPACE(1, p); 176189251Ssam if (backslash) { 177189251Ssam backslash = 0; 178189251Ssam startword = 0; 179189251Ssam if (c != '\n') 180189251Ssam USTPUTC(c, p); 181189251Ssam continue; 182189251Ssam } 183189251Ssam if (!rflag && c == '\\') { 184189251Ssam backslash++; 185189251Ssam continue; 186189251Ssam } 187189251Ssam if (c == '\n') 188189251Ssam break; 189189251Ssam if (strchr(ifs, c)) 190189251Ssam is_ifs = strchr(" \t\n", c) ? 1 : 2; 191189251Ssam else 192189251Ssam is_ifs = 0; 193189251Ssam 194189251Ssam if (startword != 0) { 195189251Ssam if (is_ifs == 1) { 196189251Ssam /* Ignore leading IFS whitespace */ 197189251Ssam if (saveall) 198189251Ssam USTPUTC(c, p); 199189251Ssam continue; 200189251Ssam } 201189251Ssam if (is_ifs == 2 && startword == 1) { 202189251Ssam /* Only one non-whitespace IFS per word */ 203189251Ssam startword = 2; 204189251Ssam if (saveall) 205189251Ssam USTPUTC(c, p); 206189251Ssam continue; 207189251Ssam } 208189251Ssam } 209189251Ssam 210189251Ssam if (is_ifs == 0) { 211189251Ssam /* append this character to the current variable */ 212189251Ssam startword = 0; 213189251Ssam if (saveall) 214189251Ssam /* Not just a spare terminator */ 215189251Ssam saveall++; 216189251Ssam USTPUTC(c, p); 217189251Ssam continue; 218189251Ssam } 219189251Ssam 220189251Ssam /* end of variable... */ 221189251Ssam startword = is_ifs; 222189251Ssam 223189251Ssam if (ap[1] == NULL) { 224189251Ssam /* Last variable needs all IFS chars */ 225189251Ssam saveall++; 226189251Ssam USTPUTC(c, p); 227189251Ssam continue; 228189251Ssam } 229189251Ssam 230189251Ssam STACKSTRNUL(p); 231189251Ssam setvar(*ap, stackblock(), 0); 232189251Ssam ap++; 233189251Ssam STARTSTACKSTR(p); 234189251Ssam } 235189251Ssam STACKSTRNUL(p); 236189251Ssam 237189251Ssam /* Remove trailing IFS chars */ 238189251Ssam for (; stackblock() <= --p; *p = 0) { 239189251Ssam if (!strchr(ifs, *p)) 240189251Ssam break; 241189251Ssam if (strchr(" \t\n", *p)) 242189251Ssam /* Always remove whitespace */ 243189251Ssam continue; 244189251Ssam if (saveall > 1) 245189251Ssam /* Don't remove non-whitespace unless it was naked */ 246189251Ssam break; 247189251Ssam } 248189251Ssam setvar(*ap, stackblock(), 0); 249189251Ssam 250189251Ssam /* Set any remaining args to "" */ 251189251Ssam while (*++ap != NULL) 252189251Ssam setvar(*ap, nullstr, 0); 253189251Ssam return status; 254189251Ssam} 255189251Ssam 256189251Ssam 257189251Ssam 258189251Ssamint 259189251Ssamumaskcmd(int argc __unused, char **argv __unused) 260189251Ssam{ 261189251Ssam char *ap; 262189251Ssam int mask; 263189251Ssam int i; 264189251Ssam int symbolic_mode = 0; 265189251Ssam 266189251Ssam while ((i = nextopt("S")) != '\0') { 267189251Ssam symbolic_mode = 1; 268189251Ssam } 269189251Ssam 270189251Ssam INTOFF; 271189251Ssam mask = umask(0); 272189251Ssam umask(mask); 273189251Ssam INTON; 274189251Ssam 275189251Ssam if ((ap = *argptr) == NULL) { 276189251Ssam if (symbolic_mode) { 277189251Ssam char u[4], g[4], o[4]; 278189251Ssam 279189251Ssam i = 0; 280189251Ssam if ((mask & S_IRUSR) == 0) 281189251Ssam u[i++] = 'r'; 282189251Ssam if ((mask & S_IWUSR) == 0) 283189251Ssam u[i++] = 'w'; 284189251Ssam if ((mask & S_IXUSR) == 0) 285189251Ssam u[i++] = 'x'; 286189251Ssam u[i] = '\0'; 287189251Ssam 288189251Ssam i = 0; 289189251Ssam if ((mask & S_IRGRP) == 0) 290189251Ssam g[i++] = 'r'; 291189251Ssam if ((mask & S_IWGRP) == 0) 292189251Ssam g[i++] = 'w'; 293189251Ssam if ((mask & S_IXGRP) == 0) 294189251Ssam g[i++] = 'x'; 295189251Ssam g[i] = '\0'; 296189251Ssam 297189251Ssam i = 0; 298189251Ssam if ((mask & S_IROTH) == 0) 299189251Ssam o[i++] = 'r'; 300189251Ssam if ((mask & S_IWOTH) == 0) 301189251Ssam o[i++] = 'w'; 302189251Ssam if ((mask & S_IXOTH) == 0) 303189251Ssam o[i++] = 'x'; 304189251Ssam o[i] = '\0'; 305189251Ssam 306189251Ssam out1fmt("u=%s,g=%s,o=%s\n", u, g, o); 307189251Ssam } else { 308189251Ssam out1fmt("%.4o\n", mask); 309189251Ssam } 310189251Ssam } else { 311189251Ssam if (isdigit(*ap)) { 312189251Ssam mask = 0; 313189251Ssam do { 314189251Ssam if (*ap >= '8' || *ap < '0') 315189251Ssam error("Illegal number: %s", *argptr); 316189251Ssam mask = (mask << 3) + (*ap - '0'); 317189251Ssam } while (*++ap != '\0'); 318189251Ssam umask(mask); 319189251Ssam } else { 320189251Ssam void *set; 321189251Ssam INTOFF; 322189251Ssam if ((set = setmode (ap)) == 0) 323189251Ssam error("Illegal number: %s", ap); 324189251Ssam 325189251Ssam mask = getmode (set, ~mask & 0777); 326189251Ssam umask(~mask & 0777); 327189251Ssam free(set); 328189251Ssam INTON; 329189251Ssam } 330189251Ssam } 331189251Ssam return 0; 332189251Ssam} 333189251Ssam 334189251Ssam/* 335189251Ssam * ulimit builtin 336189251Ssam * 337189251Ssam * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and 338189251Ssam * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with 339189251Ssam * ash by J.T. Conklin. 340189251Ssam * 341189251Ssam * Public domain. 342189251Ssam */ 343189251Ssam 344189251Ssamstruct limits { 345189251Ssam const char *name; 346189251Ssam const char *units; 347189251Ssam int cmd; 348189251Ssam int factor; /* multiply by to get rlim_{cur,max} values */ 349189251Ssam char option; 350189251Ssam}; 351189251Ssam 352189251Ssamstatic const struct limits limits[] = { 353189251Ssam#ifdef RLIMIT_CPU 354189251Ssam { "cpu time", "seconds", RLIMIT_CPU, 1, 't' }, 355189251Ssam#endif 356189251Ssam#ifdef RLIMIT_FSIZE 357189251Ssam { "file size", "512-blocks", RLIMIT_FSIZE, 512, 'f' }, 358189251Ssam#endif 359189251Ssam#ifdef RLIMIT_DATA 360189251Ssam { "data seg size", "kbytes", RLIMIT_DATA, 1024, 'd' }, 361189251Ssam#endif 362189251Ssam#ifdef RLIMIT_STACK 363189251Ssam { "stack size", "kbytes", RLIMIT_STACK, 1024, 's' }, 364189251Ssam#endif 365189251Ssam#ifdef RLIMIT_CORE 366189251Ssam { "core file size", "512-blocks", RLIMIT_CORE, 512, 'c' }, 367189251Ssam#endif 368189251Ssam#ifdef RLIMIT_RSS 369189251Ssam { "max memory size", "kbytes", RLIMIT_RSS, 1024, 'm' }, 370189251Ssam#endif 371189251Ssam#ifdef RLIMIT_MEMLOCK 372189251Ssam { "locked memory", "kbytes", RLIMIT_MEMLOCK, 1024, 'l' }, 373189251Ssam#endif 374189251Ssam#ifdef RLIMIT_NPROC 375189251Ssam { "max user processes", (char *)0, RLIMIT_NPROC, 1, 'u' }, 376189251Ssam#endif 377189251Ssam#ifdef RLIMIT_NOFILE 378189251Ssam { "open files", (char *)0, RLIMIT_NOFILE, 1, 'n' }, 379189251Ssam#endif 380189251Ssam#ifdef RLIMIT_VMEM 381189251Ssam { "virtual mem size", "kbytes", RLIMIT_VMEM, 1024, 'v' }, 382189251Ssam#endif 383189251Ssam#ifdef RLIMIT_SWAP 384189251Ssam { "swap limit", "kbytes", RLIMIT_SWAP, 1024, 'w' }, 385189251Ssam#endif 386189251Ssam#ifdef RLIMIT_SBSIZE 387189251Ssam { "sbsize", "bytes", RLIMIT_SBSIZE, 1, 'b' }, 388189251Ssam#endif 389189251Ssam#ifdef RLIMIT_NPTS 390189251Ssam { "pseudo-terminals", (char *)0, RLIMIT_NPTS, 1, 'p' }, 391189251Ssam#endif 392189251Ssam { (char *) 0, (char *)0, 0, 0, '\0' } 393189251Ssam}; 394189251Ssam 395189251Ssamint 396189251Ssamulimitcmd(int argc __unused, char **argv __unused) 397189251Ssam{ 398189251Ssam int c; 399189251Ssam rlim_t val = 0; 400189251Ssam enum { SOFT = 0x1, HARD = 0x2 } 401189251Ssam how = SOFT | HARD; 402189251Ssam const struct limits *l; 403189251Ssam int set, all = 0; 404189251Ssam int optc, what; 405189251Ssam struct rlimit limit; 406189251Ssam 407189251Ssam what = 'f'; 408189251Ssam while ((optc = nextopt("HSatfdsmcnuvlbpw")) != '\0') 409189251Ssam switch (optc) { 410189251Ssam case 'H': 411189251Ssam how = HARD; 412189251Ssam break; 413189251Ssam case 'S': 414189251Ssam how = SOFT; 415189251Ssam break; 416189251Ssam case 'a': 417189251Ssam all = 1; 418189251Ssam break; 419189251Ssam default: 420189251Ssam what = optc; 421189251Ssam } 422189251Ssam 423189251Ssam for (l = limits; l->name && l->option != what; l++) 424189251Ssam ; 425189251Ssam if (!l->name) 426189251Ssam error("internal error (%c)", what); 427189251Ssam 428189251Ssam set = *argptr ? 1 : 0; 429189251Ssam if (set) { 430189251Ssam char *p = *argptr; 431189251Ssam 432189251Ssam if (all || argptr[1]) 433189251Ssam error("too many arguments"); 434189251Ssam if (strcmp(p, "unlimited") == 0) 435189251Ssam val = RLIM_INFINITY; 436189251Ssam else { 437189251Ssam val = 0; 438189251Ssam 439189251Ssam while ((c = *p++) >= '0' && c <= '9') 440189251Ssam { 441189251Ssam val = (val * 10) + (long)(c - '0'); 442189251Ssam if (val < 0) 443189251Ssam break; 444189251Ssam } 445189251Ssam if (c) 446189251Ssam error("bad number"); 447189251Ssam val *= l->factor; 448189251Ssam } 449189251Ssam } 450189251Ssam if (all) { 451189251Ssam for (l = limits; l->name; l++) { 452189251Ssam char optbuf[40]; 453189251Ssam if (getrlimit(l->cmd, &limit) < 0) 454189251Ssam error("can't get limit: %s", strerror(errno)); 455189251Ssam if (how & SOFT) 456189251Ssam val = limit.rlim_cur; 457189251Ssam else if (how & HARD) 458189251Ssam val = limit.rlim_max; 459189251Ssam 460189251Ssam if (l->units) 461189251Ssam snprintf(optbuf, sizeof(optbuf), 462189251Ssam "(%s, -%c) ", l->units, l->option); 463189251Ssam else 464189251Ssam snprintf(optbuf, sizeof(optbuf), 465189251Ssam "(-%c) ", l->option); 466189251Ssam out1fmt("%-18s %18s ", l->name, optbuf); 467189251Ssam if (val == RLIM_INFINITY) 468189251Ssam out1str("unlimited\n"); 469189251Ssam else 470189251Ssam { 471189251Ssam val /= l->factor; 472189251Ssam out1fmt("%jd\n", (intmax_t)val); 473189251Ssam } 474189251Ssam } 475189251Ssam return 0; 476189251Ssam } 477189251Ssam 478189251Ssam if (getrlimit(l->cmd, &limit) < 0) 479189251Ssam error("can't get limit: %s", strerror(errno)); 480189251Ssam if (set) { 481189251Ssam if (how & SOFT) 482189251Ssam limit.rlim_cur = val; 483189251Ssam if (how & HARD) 484189251Ssam limit.rlim_max = val; 485189251Ssam if (setrlimit(l->cmd, &limit) < 0) 486189251Ssam error("bad limit: %s", strerror(errno)); 487189251Ssam } else { 488189251Ssam if (how & SOFT) 489189251Ssam val = limit.rlim_cur; 490189251Ssam else if (how & HARD) 491189251Ssam val = limit.rlim_max; 492189251Ssam 493189251Ssam if (val == RLIM_INFINITY) 494189251Ssam out1str("unlimited\n"); 495189251Ssam else 496189251Ssam { 497189251Ssam val /= l->factor; 498189251Ssam out1fmt("%jd\n", (intmax_t)val); 499189251Ssam } 500189251Ssam } 501189251Ssam return 0; 502189251Ssam} 503189251Ssam