miscbltin.c revision 52072
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1991, 1993 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * This code is derived from software contributed to Berkeley by 61556Srgrimes * Kenneth Almquist. 71556Srgrimes * 81556Srgrimes * Redistribution and use in source and binary forms, with or without 91556Srgrimes * modification, are permitted provided that the following conditions 101556Srgrimes * are met: 111556Srgrimes * 1. Redistributions of source code must retain the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer. 131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer in the 151556Srgrimes * documentation and/or other materials provided with the distribution. 161556Srgrimes * 3. All advertising materials mentioning features or use of this software 171556Srgrimes * must display the following acknowledgement: 181556Srgrimes * This product includes software developed by the University of 191556Srgrimes * California, Berkeley and its contributors. 201556Srgrimes * 4. Neither the name of the University nor the names of its contributors 211556Srgrimes * may be used to endorse or promote products derived from this software 221556Srgrimes * without specific prior written permission. 231556Srgrimes * 241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341556Srgrimes * SUCH DAMAGE. 351556Srgrimes */ 361556Srgrimes 371556Srgrimes#ifndef lint 3836150Scharnier#if 0 3936150Scharnierstatic char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95"; 4036150Scharnier#endif 4136150Scharnierstatic const char rcsid[] = 4250471Speter "$FreeBSD: head/bin/sh/miscbltin.c 52072 1999-10-09 20:56:06Z green $"; 431556Srgrimes#endif /* not lint */ 441556Srgrimes 451556Srgrimes/* 4646684Skris * Miscellaneous builtins. 471556Srgrimes */ 481556Srgrimes 4917987Speter#include <sys/types.h> 5017987Speter#include <sys/stat.h> 5117987Speter#include <sys/time.h> 5217987Speter#include <sys/resource.h> 5317987Speter#include <unistd.h> 5417987Speter#include <ctype.h> 5518016Speter#include <errno.h> 5618018Speter#include <stdio.h> 5738536Scracauer#include <stdlib.h> 5829983Smsmith#include <termios.h> 5917987Speter 601556Srgrimes#include "shell.h" 611556Srgrimes#include "options.h" 621556Srgrimes#include "var.h" 631556Srgrimes#include "output.h" 641556Srgrimes#include "memalloc.h" 651556Srgrimes#include "error.h" 661556Srgrimes#include "mystring.h" 671556Srgrimes 681556Srgrimes#undef eflag 691556Srgrimes 701556Srgrimesextern char **argptr; /* argument list for builtin command */ 711556Srgrimes 721556Srgrimes 731556Srgrimes/* 7450394Stg * The read builtin. The -r option causes backslashes to be treated like 7550394Stg * ordinary characters. 761556Srgrimes * 771556Srgrimes * This uses unbuffered input, which may be avoidable in some cases. 781556Srgrimes */ 791556Srgrimes 8017987Speterint 8117987Speterreadcmd(argc, argv) 8225905Ssteve int argc __unused; 8325905Ssteve char **argv __unused; 8417987Speter{ 851556Srgrimes char **ap; 861556Srgrimes int backslash; 871556Srgrimes char c; 8850394Stg int rflag; 891556Srgrimes char *prompt; 901556Srgrimes char *ifs; 911556Srgrimes char *p; 921556Srgrimes int startword; 931556Srgrimes int status; 941556Srgrimes int i; 9529983Smsmith struct timeval tv; 9629983Smsmith char *tvptr; 9729983Smsmith fd_set ifds; 9829983Smsmith struct termios told, tnew; 9929983Smsmith int tsaved; 1001556Srgrimes 10150394Stg rflag = 0; 1021556Srgrimes prompt = NULL; 10329983Smsmith tv.tv_sec = -1; 10429983Smsmith tv.tv_usec = 0; 10550394Stg while ((i = nextopt("erp:t:")) != '\0') { 10629983Smsmith switch(i) { 10729983Smsmith case 'p': 1081556Srgrimes prompt = optarg; 10929983Smsmith break; 11029983Smsmith case 'e': 11129983Smsmith break; 11250394Stg case 'r': 11350394Stg rflag = 1; 11450394Stg break; 11529983Smsmith case 't': 11629983Smsmith tv.tv_sec = strtol(optarg, &tvptr, 0); 11729983Smsmith if (tvptr == optarg) 11829983Smsmith error("timeout value"); 11929983Smsmith switch(*tvptr) { 12029983Smsmith case 0: 12129983Smsmith case 's': 12229983Smsmith break; 12329983Smsmith case 'h': 12429983Smsmith tv.tv_sec *= 60; 12529983Smsmith /* FALLTHROUGH */ 12629983Smsmith case 'm': 12729983Smsmith tv.tv_sec *= 60; 12829983Smsmith break; 12929983Smsmith default: 13029983Smsmith error("timeout unit"); 13129983Smsmith } 13229983Smsmith break; 13329983Smsmith } 1341556Srgrimes } 1351556Srgrimes if (prompt && isatty(0)) { 1361556Srgrimes out2str(prompt); 1371556Srgrimes flushall(); 1381556Srgrimes } 1391556Srgrimes if (*(ap = argptr) == NULL) 1401556Srgrimes error("arg count"); 1411556Srgrimes if ((ifs = bltinlookup("IFS", 1)) == NULL) 1421556Srgrimes ifs = nullstr; 14329983Smsmith 14429983Smsmith if (tv.tv_sec >= 0) { 14529983Smsmith /* 14629983Smsmith * See if we can disable input processing; this will 14729983Smsmith * not give the desired result if we are in a pipeline 14829983Smsmith * and someone upstream is still in line-by-line mode. 14929983Smsmith */ 15029983Smsmith tsaved = 0; 15129983Smsmith if (tcgetattr(0, &told) == 0) { 15229983Smsmith memcpy(&tnew, &told, sizeof(told)); 15329983Smsmith cfmakeraw(&tnew); 15429983Smsmith tcsetattr(0, TCSANOW, &tnew); 15529983Smsmith tsaved = 1; 15629983Smsmith } 15729983Smsmith /* 15829983Smsmith * Wait for something to become available. 15929983Smsmith */ 16029983Smsmith FD_ZERO(&ifds); 16129983Smsmith FD_SET(0, &ifds); 16229983Smsmith status = select(1, &ifds, NULL, NULL, &tv); 16329983Smsmith if (tsaved) 16429983Smsmith tcsetattr(0, TCSANOW, &told); 16529983Smsmith /* 16629983Smsmith * If there's nothing ready, return an error. 16729983Smsmith */ 16829983Smsmith if (status <= 0) 16929983Smsmith return(1); 17029983Smsmith } 17129983Smsmith 1721556Srgrimes status = 0; 1731556Srgrimes startword = 1; 1741556Srgrimes backslash = 0; 1751556Srgrimes STARTSTACKSTR(p); 1761556Srgrimes for (;;) { 1771556Srgrimes if (read(0, &c, 1) != 1) { 1781556Srgrimes status = 1; 1791556Srgrimes break; 1801556Srgrimes } 1811556Srgrimes if (c == '\0') 1821556Srgrimes continue; 1831556Srgrimes if (backslash) { 1841556Srgrimes backslash = 0; 1851556Srgrimes if (c != '\n') 1861556Srgrimes STPUTC(c, p); 1871556Srgrimes continue; 1881556Srgrimes } 18950394Stg if (!rflag && c == '\\') { 1901556Srgrimes backslash++; 1911556Srgrimes continue; 1921556Srgrimes } 1931556Srgrimes if (c == '\n') 1941556Srgrimes break; 1951556Srgrimes if (startword && *ifs == ' ' && strchr(ifs, c)) { 1961556Srgrimes continue; 1971556Srgrimes } 1981556Srgrimes startword = 0; 1991556Srgrimes if (backslash && c == '\\') { 2001556Srgrimes if (read(0, &c, 1) != 1) { 2011556Srgrimes status = 1; 2021556Srgrimes break; 2031556Srgrimes } 2041556Srgrimes STPUTC(c, p); 2051556Srgrimes } else if (ap[1] != NULL && strchr(ifs, c) != NULL) { 2061556Srgrimes STACKSTRNUL(p); 2071556Srgrimes setvar(*ap, stackblock(), 0); 2081556Srgrimes ap++; 2091556Srgrimes startword = 1; 2101556Srgrimes STARTSTACKSTR(p); 2111556Srgrimes } else { 2121556Srgrimes STPUTC(c, p); 2131556Srgrimes } 2141556Srgrimes } 2151556Srgrimes STACKSTRNUL(p); 2161556Srgrimes setvar(*ap, stackblock(), 0); 2171556Srgrimes while (*++ap != NULL) 2181556Srgrimes setvar(*ap, nullstr, 0); 2191556Srgrimes return status; 2201556Srgrimes} 2211556Srgrimes 2221556Srgrimes 2231556Srgrimes 22417987Speterint 22517987Speterumaskcmd(argc, argv) 22625905Ssteve int argc __unused; 22720425Ssteve char **argv; 22817987Speter{ 22917987Speter char *ap; 2301556Srgrimes int mask; 2311556Srgrimes int i; 23217987Speter int symbolic_mode = 0; 2331556Srgrimes 23417987Speter while ((i = nextopt("S")) != '\0') { 23517987Speter symbolic_mode = 1; 2361556Srgrimes } 23711571Sjoerg 23817987Speter INTOFF; 23917987Speter mask = umask(0); 24017987Speter umask(mask); 24117987Speter INTON; 24211571Sjoerg 24317987Speter if ((ap = *argptr) == NULL) { 24417987Speter if (symbolic_mode) { 24517987Speter char u[4], g[4], o[4]; 24611571Sjoerg 24717987Speter i = 0; 24817987Speter if ((mask & S_IRUSR) == 0) 24917987Speter u[i++] = 'r'; 25017987Speter if ((mask & S_IWUSR) == 0) 25117987Speter u[i++] = 'w'; 25217987Speter if ((mask & S_IXUSR) == 0) 25317987Speter u[i++] = 'x'; 25417987Speter u[i] = '\0'; 25511571Sjoerg 25617987Speter i = 0; 25717987Speter if ((mask & S_IRGRP) == 0) 25817987Speter g[i++] = 'r'; 25917987Speter if ((mask & S_IWGRP) == 0) 26017987Speter g[i++] = 'w'; 26117987Speter if ((mask & S_IXGRP) == 0) 26217987Speter g[i++] = 'x'; 26317987Speter g[i] = '\0'; 26411571Sjoerg 26517987Speter i = 0; 26617987Speter if ((mask & S_IROTH) == 0) 26717987Speter o[i++] = 'r'; 26817987Speter if ((mask & S_IWOTH) == 0) 26917987Speter o[i++] = 'w'; 27017987Speter if ((mask & S_IXOTH) == 0) 27117987Speter o[i++] = 'x'; 27217987Speter o[i] = '\0'; 27311571Sjoerg 27417987Speter out1fmt("u=%s,g=%s,o=%s\n", u, g, o); 27517987Speter } else { 27617987Speter out1fmt("%.4o\n", mask); 27717987Speter } 27817987Speter } else { 27917987Speter if (isdigit(*ap)) { 28017987Speter mask = 0; 28117987Speter do { 28217987Speter if (*ap >= '8' || *ap < '0') 28317987Speter error("Illegal number: %s", argv[1]); 28417987Speter mask = (mask << 3) + (*ap - '0'); 28517987Speter } while (*++ap != '\0'); 28617987Speter umask(mask); 28717987Speter } else { 28820425Ssteve void *set; 28917987Speter if ((set = setmode (ap)) == 0) 29041844Simp error("Illegal number: %s", ap); 29111571Sjoerg 29217987Speter mask = getmode (set, ~mask & 0777); 29317987Speter umask(~mask & 0777); 29441844Simp free(set); 29517987Speter } 29617987Speter } 29711571Sjoerg return 0; 29811571Sjoerg} 29911571Sjoerg 30017987Speter/* 30117987Speter * ulimit builtin 30217987Speter * 30317987Speter * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and 30417987Speter * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with 30517987Speter * ash by J.T. Conklin. 30617987Speter * 30717987Speter * Public domain. 30817987Speter */ 30911571Sjoerg 31017987Speterstruct limits { 31117987Speter const char *name; 31218016Speter const char *units; 31317987Speter int cmd; 31417987Speter int factor; /* multiply by to get rlim_{cur,max} values */ 31517987Speter char option; 31617987Speter}; 31711571Sjoerg 31817987Speterstatic const struct limits limits[] = { 31917987Speter#ifdef RLIMIT_CPU 32018016Speter { "cpu time", "seconds", RLIMIT_CPU, 1, 't' }, 32117987Speter#endif 32217987Speter#ifdef RLIMIT_FSIZE 32318016Speter { "file size", "512-blocks", RLIMIT_FSIZE, 512, 'f' }, 32417987Speter#endif 32517987Speter#ifdef RLIMIT_DATA 32618016Speter { "data seg size", "kbytes", RLIMIT_DATA, 1024, 'd' }, 32717987Speter#endif 32817987Speter#ifdef RLIMIT_STACK 32918016Speter { "stack size", "kbytes", RLIMIT_STACK, 1024, 's' }, 33017987Speter#endif 33117987Speter#ifdef RLIMIT_CORE 33218016Speter { "core file size", "512-blocks", RLIMIT_CORE, 512, 'c' }, 33317987Speter#endif 33417987Speter#ifdef RLIMIT_RSS 33518016Speter { "max memory size", "kbytes", RLIMIT_RSS, 1024, 'm' }, 33617987Speter#endif 33717987Speter#ifdef RLIMIT_MEMLOCK 33818016Speter { "locked memory", "kbytes", RLIMIT_MEMLOCK, 1024, 'l' }, 33917987Speter#endif 34017987Speter#ifdef RLIMIT_NPROC 34118016Speter { "max user processes", (char *)0, RLIMIT_NPROC, 1, 'u' }, 34217987Speter#endif 34317987Speter#ifdef RLIMIT_NOFILE 34418016Speter { "open files", (char *)0, RLIMIT_NOFILE, 1, 'n' }, 34517987Speter#endif 34617987Speter#ifdef RLIMIT_VMEM 34718016Speter { "virtual mem size", "kbytes", RLIMIT_VMEM, 1024, 'v' }, 34817987Speter#endif 34917987Speter#ifdef RLIMIT_SWAP 35018016Speter { "swap limit", "kbytes", RLIMIT_SWAP, 1024, 'w' }, 35117987Speter#endif 35252072Sgreen#ifdef RLIMIT_SBSIZE 35352072Sgreen { "sbsize", "bytes", RLIMIT_SBSIZE, 1, 'b' }, 35452072Sgreen#endif 35518016Speter { (char *) 0, (char *)0, 0, 0, '\0' } 35617987Speter}; 35717987Speter 35817987Speterint 35917987Speterulimitcmd(argc, argv) 36025905Ssteve int argc __unused; 36125905Ssteve char **argv __unused; 36217987Speter{ 36325222Ssteve int c; 36418018Speter quad_t val = 0; 36517987Speter enum { SOFT = 0x1, HARD = 0x2 } 36617987Speter how = SOFT | HARD; 36717987Speter const struct limits *l; 36817987Speter int set, all = 0; 36917987Speter int optc, what; 37017987Speter struct rlimit limit; 37111571Sjoerg 37217987Speter what = 'f'; 37352072Sgreen while ((optc = nextopt("HSatfdsmcnulb")) != '\0') 37417987Speter switch (optc) { 37511571Sjoerg case 'H': 37617987Speter how = HARD; 37711571Sjoerg break; 37811571Sjoerg case 'S': 37917987Speter how = SOFT; 38011571Sjoerg break; 38111571Sjoerg case 'a': 38217987Speter all = 1; 38311571Sjoerg break; 38417987Speter default: 38517987Speter what = optc; 38611571Sjoerg } 38711571Sjoerg 38817987Speter for (l = limits; l->name && l->option != what; l++) 38917987Speter ; 39017987Speter if (!l->name) 39120425Ssteve error("ulimit: internal error (%c)", what); 39217987Speter 39317987Speter set = *argptr ? 1 : 0; 39417987Speter if (set) { 39517987Speter char *p = *argptr; 39617987Speter 39717987Speter if (all || argptr[1]) 39820425Ssteve error("ulimit: too many arguments"); 39917987Speter if (strcmp(p, "unlimited") == 0) 40011571Sjoerg val = RLIM_INFINITY; 40111571Sjoerg else { 40217987Speter val = (quad_t) 0; 40317987Speter 40417987Speter while ((c = *p++) >= '0' && c <= '9') 40517987Speter { 40617987Speter val = (val * 10) + (long)(c - '0'); 40717987Speter if (val < (quad_t) 0) 40817987Speter break; 40917987Speter } 41017987Speter if (c) 41120425Ssteve error("ulimit: bad number"); 41217987Speter val *= l->factor; 41311571Sjoerg } 41417987Speter } 41517987Speter if (all) { 41618016Speter for (l = limits; l->name; l++) { 41718016Speter char optbuf[40]; 41818016Speter if (getrlimit(l->cmd, &limit) < 0) 41920425Ssteve error("ulimit: can't get limit: %s", strerror(errno)); 42017987Speter if (how & SOFT) 42117987Speter val = limit.rlim_cur; 42217987Speter else if (how & HARD) 42317987Speter val = limit.rlim_max; 42417987Speter 42518016Speter if (l->units) 42618016Speter snprintf(optbuf, sizeof(optbuf), 42718019Speter "(%s, -%c) ", l->units, l->option); 42818016Speter else 42918016Speter snprintf(optbuf, sizeof(optbuf), 43018019Speter "(-%c) ", l->option); 43118019Speter out1fmt("%-18s %18s ", l->name, optbuf); 43217987Speter if (val == RLIM_INFINITY) 43317987Speter out1fmt("unlimited\n"); 43417987Speter else 43517987Speter { 43617987Speter val /= l->factor; 43718018Speter out1fmt("%qd\n", (quad_t) val); 43817987Speter } 43911571Sjoerg } 44017987Speter return 0; 44111571Sjoerg } 44217987Speter 44318016Speter if (getrlimit(l->cmd, &limit) < 0) 44420425Ssteve error("ulimit: can't get limit: %s", strerror(errno)); 44517987Speter if (set) { 44617987Speter if (how & SOFT) 44717987Speter limit.rlim_cur = val; 44817987Speter if (how & HARD) 44917987Speter limit.rlim_max = val; 45017987Speter if (setrlimit(l->cmd, &limit) < 0) 45120425Ssteve error("ulimit: bad limit: %s", strerror(errno)); 45217987Speter } else { 45317987Speter if (how & SOFT) 45417987Speter val = limit.rlim_cur; 45517987Speter else if (how & HARD) 45617987Speter val = limit.rlim_max; 45717987Speter 45817987Speter if (val == RLIM_INFINITY) 45917987Speter out1fmt("unlimited\n"); 46017987Speter else 46117987Speter { 46217987Speter val /= l->factor; 46318018Speter out1fmt("%qd\n", (quad_t) val); 46417987Speter } 46517987Speter } 46611571Sjoerg return 0; 46711571Sjoerg} 468