miscbltin.c revision 181905
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 * 4. Neither the name of the University nor the names of its contributors 171556Srgrimes * may be used to endorse or promote products derived from this software 181556Srgrimes * without specific prior written permission. 191556Srgrimes * 201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301556Srgrimes * SUCH DAMAGE. 311556Srgrimes */ 321556Srgrimes 331556Srgrimes#ifndef lint 3436150Scharnier#if 0 3536150Scharnierstatic char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95"; 3636150Scharnier#endif 371556Srgrimes#endif /* not lint */ 3899110Sobrien#include <sys/cdefs.h> 3999110Sobrien__FBSDID("$FreeBSD: head/bin/sh/miscbltin.c 181905 2008-08-20 08:31:58Z ed $"); 401556Srgrimes 411556Srgrimes/* 4246684Skris * Miscellaneous builtins. 431556Srgrimes */ 441556Srgrimes 4517987Speter#include <sys/types.h> 4617987Speter#include <sys/stat.h> 4717987Speter#include <sys/time.h> 4817987Speter#include <sys/resource.h> 4917987Speter#include <unistd.h> 5017987Speter#include <ctype.h> 5118016Speter#include <errno.h> 52104282Smux#include <stdint.h> 5318018Speter#include <stdio.h> 5438536Scracauer#include <stdlib.h> 5529983Smsmith#include <termios.h> 5617987Speter 571556Srgrimes#include "shell.h" 581556Srgrimes#include "options.h" 591556Srgrimes#include "var.h" 601556Srgrimes#include "output.h" 611556Srgrimes#include "memalloc.h" 621556Srgrimes#include "error.h" 631556Srgrimes#include "mystring.h" 641556Srgrimes 651556Srgrimes#undef eflag 661556Srgrimes 67149018Sstefanfint readcmd(int, char **); 68149018Sstefanfint umaskcmd(int, char **); 69149018Sstefanfint ulimitcmd(int, char **); 70149018Sstefanf 711556Srgrimes/* 7250394Stg * The read builtin. The -r option causes backslashes to be treated like 7350394Stg * ordinary characters. 741556Srgrimes * 751556Srgrimes * This uses unbuffered input, which may be avoidable in some cases. 761556Srgrimes */ 771556Srgrimes 7817987Speterint 7990111Simpreadcmd(int argc __unused, char **argv __unused) 8017987Speter{ 811556Srgrimes char **ap; 821556Srgrimes int backslash; 831556Srgrimes char c; 8450394Stg int rflag; 851556Srgrimes char *prompt; 861556Srgrimes char *ifs; 871556Srgrimes char *p; 881556Srgrimes int startword; 891556Srgrimes int status; 901556Srgrimes int i; 9129983Smsmith struct timeval tv; 9229983Smsmith char *tvptr; 9329983Smsmith fd_set ifds; 9429983Smsmith struct termios told, tnew; 9529983Smsmith int tsaved; 961556Srgrimes 9750394Stg rflag = 0; 981556Srgrimes prompt = NULL; 9929983Smsmith tv.tv_sec = -1; 10029983Smsmith tv.tv_usec = 0; 10150394Stg while ((i = nextopt("erp:t:")) != '\0') { 10229983Smsmith switch(i) { 10329983Smsmith case 'p': 10459436Scracauer prompt = shoptarg; 10529983Smsmith break; 10629983Smsmith case 'e': 10729983Smsmith break; 10850394Stg case 'r': 10950394Stg rflag = 1; 11050394Stg break; 11129983Smsmith case 't': 11259436Scracauer tv.tv_sec = strtol(shoptarg, &tvptr, 0); 11359436Scracauer if (tvptr == shoptarg) 11429983Smsmith error("timeout value"); 11529983Smsmith switch(*tvptr) { 11629983Smsmith case 0: 11729983Smsmith case 's': 11829983Smsmith break; 11929983Smsmith case 'h': 12029983Smsmith tv.tv_sec *= 60; 12129983Smsmith /* FALLTHROUGH */ 12229983Smsmith case 'm': 12329983Smsmith tv.tv_sec *= 60; 12429983Smsmith break; 12529983Smsmith default: 12629983Smsmith error("timeout unit"); 12729983Smsmith } 12829983Smsmith break; 12929983Smsmith } 1301556Srgrimes } 1311556Srgrimes if (prompt && isatty(0)) { 1321556Srgrimes out2str(prompt); 1331556Srgrimes flushall(); 1341556Srgrimes } 1351556Srgrimes if (*(ap = argptr) == NULL) 1361556Srgrimes error("arg count"); 1371556Srgrimes if ((ifs = bltinlookup("IFS", 1)) == NULL) 1381556Srgrimes ifs = nullstr; 13929983Smsmith 14029983Smsmith if (tv.tv_sec >= 0) { 14129983Smsmith /* 14229983Smsmith * See if we can disable input processing; this will 14329983Smsmith * not give the desired result if we are in a pipeline 14429983Smsmith * and someone upstream is still in line-by-line mode. 14529983Smsmith */ 14629983Smsmith tsaved = 0; 14729983Smsmith if (tcgetattr(0, &told) == 0) { 14829983Smsmith memcpy(&tnew, &told, sizeof(told)); 14929983Smsmith cfmakeraw(&tnew); 15029983Smsmith tcsetattr(0, TCSANOW, &tnew); 15129983Smsmith tsaved = 1; 15229983Smsmith } 15329983Smsmith /* 15429983Smsmith * Wait for something to become available. 15529983Smsmith */ 15629983Smsmith FD_ZERO(&ifds); 15729983Smsmith FD_SET(0, &ifds); 15829983Smsmith status = select(1, &ifds, NULL, NULL, &tv); 15929983Smsmith if (tsaved) 16029983Smsmith tcsetattr(0, TCSANOW, &told); 16129983Smsmith /* 16229983Smsmith * If there's nothing ready, return an error. 16329983Smsmith */ 16429983Smsmith if (status <= 0) 16529983Smsmith return(1); 16629983Smsmith } 16729983Smsmith 1681556Srgrimes status = 0; 1691556Srgrimes startword = 1; 1701556Srgrimes backslash = 0; 1711556Srgrimes STARTSTACKSTR(p); 1721556Srgrimes for (;;) { 17380381Ssheldonh if (read(STDIN_FILENO, &c, 1) != 1) { 1741556Srgrimes status = 1; 1751556Srgrimes break; 1761556Srgrimes } 1771556Srgrimes if (c == '\0') 1781556Srgrimes continue; 1791556Srgrimes if (backslash) { 1801556Srgrimes backslash = 0; 1811556Srgrimes if (c != '\n') 1821556Srgrimes STPUTC(c, p); 1831556Srgrimes continue; 1841556Srgrimes } 18550394Stg if (!rflag && c == '\\') { 1861556Srgrimes backslash++; 1871556Srgrimes continue; 1881556Srgrimes } 1891556Srgrimes if (c == '\n') 1901556Srgrimes break; 1911556Srgrimes if (startword && *ifs == ' ' && strchr(ifs, c)) { 1921556Srgrimes continue; 1931556Srgrimes } 1941556Srgrimes startword = 0; 195149825Srse if (ap[1] != NULL && strchr(ifs, c) != NULL) { 1961556Srgrimes STACKSTRNUL(p); 1971556Srgrimes setvar(*ap, stackblock(), 0); 1981556Srgrimes ap++; 1991556Srgrimes startword = 1; 2001556Srgrimes STARTSTACKSTR(p); 2011556Srgrimes } else { 2021556Srgrimes STPUTC(c, p); 2031556Srgrimes } 2041556Srgrimes } 2051556Srgrimes STACKSTRNUL(p); 2061556Srgrimes setvar(*ap, stackblock(), 0); 2071556Srgrimes while (*++ap != NULL) 2081556Srgrimes setvar(*ap, nullstr, 0); 2091556Srgrimes return status; 2101556Srgrimes} 2111556Srgrimes 2121556Srgrimes 2131556Srgrimes 21417987Speterint 21590111Simpumaskcmd(int argc __unused, char **argv) 21617987Speter{ 21717987Speter char *ap; 2181556Srgrimes int mask; 2191556Srgrimes int i; 22017987Speter int symbolic_mode = 0; 2211556Srgrimes 22217987Speter while ((i = nextopt("S")) != '\0') { 22317987Speter symbolic_mode = 1; 2241556Srgrimes } 22511571Sjoerg 22617987Speter INTOFF; 22717987Speter mask = umask(0); 22817987Speter umask(mask); 22917987Speter INTON; 23011571Sjoerg 23117987Speter if ((ap = *argptr) == NULL) { 23217987Speter if (symbolic_mode) { 23317987Speter char u[4], g[4], o[4]; 23411571Sjoerg 23517987Speter i = 0; 23617987Speter if ((mask & S_IRUSR) == 0) 23717987Speter u[i++] = 'r'; 23817987Speter if ((mask & S_IWUSR) == 0) 23917987Speter u[i++] = 'w'; 24017987Speter if ((mask & S_IXUSR) == 0) 24117987Speter u[i++] = 'x'; 24217987Speter u[i] = '\0'; 24311571Sjoerg 24417987Speter i = 0; 24517987Speter if ((mask & S_IRGRP) == 0) 24617987Speter g[i++] = 'r'; 24717987Speter if ((mask & S_IWGRP) == 0) 24817987Speter g[i++] = 'w'; 24917987Speter if ((mask & S_IXGRP) == 0) 25017987Speter g[i++] = 'x'; 25117987Speter g[i] = '\0'; 25211571Sjoerg 25317987Speter i = 0; 25417987Speter if ((mask & S_IROTH) == 0) 25517987Speter o[i++] = 'r'; 25617987Speter if ((mask & S_IWOTH) == 0) 25717987Speter o[i++] = 'w'; 25817987Speter if ((mask & S_IXOTH) == 0) 25917987Speter o[i++] = 'x'; 26017987Speter o[i] = '\0'; 26111571Sjoerg 26217987Speter out1fmt("u=%s,g=%s,o=%s\n", u, g, o); 26317987Speter } else { 26417987Speter out1fmt("%.4o\n", mask); 26517987Speter } 26617987Speter } else { 26717987Speter if (isdigit(*ap)) { 26817987Speter mask = 0; 26917987Speter do { 27017987Speter if (*ap >= '8' || *ap < '0') 271149918Sstefanf error("Illegal number: %s", *argptr); 27217987Speter mask = (mask << 3) + (*ap - '0'); 27317987Speter } while (*++ap != '\0'); 27417987Speter umask(mask); 27517987Speter } else { 27620425Ssteve void *set; 277151795Sstefanf INTOFF; 27817987Speter if ((set = setmode (ap)) == 0) 27941844Simp error("Illegal number: %s", ap); 28011571Sjoerg 28117987Speter mask = getmode (set, ~mask & 0777); 28217987Speter umask(~mask & 0777); 28341844Simp free(set); 284151795Sstefanf INTON; 28517987Speter } 28617987Speter } 28711571Sjoerg return 0; 28811571Sjoerg} 28911571Sjoerg 29017987Speter/* 29117987Speter * ulimit builtin 29217987Speter * 29317987Speter * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and 29417987Speter * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with 29517987Speter * ash by J.T. Conklin. 29617987Speter * 29717987Speter * Public domain. 29817987Speter */ 29911571Sjoerg 30017987Speterstruct limits { 30117987Speter const char *name; 30218016Speter const char *units; 30317987Speter int cmd; 30417987Speter int factor; /* multiply by to get rlim_{cur,max} values */ 30517987Speter char option; 30617987Speter}; 30711571Sjoerg 30817987Speterstatic const struct limits limits[] = { 30917987Speter#ifdef RLIMIT_CPU 31018016Speter { "cpu time", "seconds", RLIMIT_CPU, 1, 't' }, 31117987Speter#endif 31217987Speter#ifdef RLIMIT_FSIZE 31318016Speter { "file size", "512-blocks", RLIMIT_FSIZE, 512, 'f' }, 31417987Speter#endif 31517987Speter#ifdef RLIMIT_DATA 31618016Speter { "data seg size", "kbytes", RLIMIT_DATA, 1024, 'd' }, 31717987Speter#endif 31817987Speter#ifdef RLIMIT_STACK 31918016Speter { "stack size", "kbytes", RLIMIT_STACK, 1024, 's' }, 32017987Speter#endif 32117987Speter#ifdef RLIMIT_CORE 32218016Speter { "core file size", "512-blocks", RLIMIT_CORE, 512, 'c' }, 32317987Speter#endif 32417987Speter#ifdef RLIMIT_RSS 32518016Speter { "max memory size", "kbytes", RLIMIT_RSS, 1024, 'm' }, 32617987Speter#endif 32717987Speter#ifdef RLIMIT_MEMLOCK 32818016Speter { "locked memory", "kbytes", RLIMIT_MEMLOCK, 1024, 'l' }, 32917987Speter#endif 33017987Speter#ifdef RLIMIT_NPROC 33118016Speter { "max user processes", (char *)0, RLIMIT_NPROC, 1, 'u' }, 33217987Speter#endif 33317987Speter#ifdef RLIMIT_NOFILE 33418016Speter { "open files", (char *)0, RLIMIT_NOFILE, 1, 'n' }, 33517987Speter#endif 33617987Speter#ifdef RLIMIT_VMEM 33718016Speter { "virtual mem size", "kbytes", RLIMIT_VMEM, 1024, 'v' }, 33817987Speter#endif 33917987Speter#ifdef RLIMIT_SWAP 34018016Speter { "swap limit", "kbytes", RLIMIT_SWAP, 1024, 'w' }, 34117987Speter#endif 34252072Sgreen#ifdef RLIMIT_SBSIZE 34352072Sgreen { "sbsize", "bytes", RLIMIT_SBSIZE, 1, 'b' }, 34452072Sgreen#endif 345181905Sed#ifdef RLIMIT_NPTS 346181905Sed { "pseudo-terminals", (char *)0, RLIMIT_NPTS, 1, 'p' }, 347181905Sed#endif 34818016Speter { (char *) 0, (char *)0, 0, 0, '\0' } 34917987Speter}; 35017987Speter 35117987Speterint 35290111Simpulimitcmd(int argc __unused, char **argv __unused) 35317987Speter{ 35425222Ssteve int c; 355104282Smux rlim_t val = 0; 35617987Speter enum { SOFT = 0x1, HARD = 0x2 } 35717987Speter how = SOFT | HARD; 35817987Speter const struct limits *l; 35917987Speter int set, all = 0; 36017987Speter int optc, what; 36117987Speter struct rlimit limit; 36211571Sjoerg 36317987Speter what = 'f'; 364181905Sed while ((optc = nextopt("HSatfdsmcnuvlbp")) != '\0') 36517987Speter switch (optc) { 36611571Sjoerg case 'H': 36717987Speter how = HARD; 36811571Sjoerg break; 36911571Sjoerg case 'S': 37017987Speter how = SOFT; 37111571Sjoerg break; 37211571Sjoerg case 'a': 37317987Speter all = 1; 37411571Sjoerg break; 37517987Speter default: 37617987Speter what = optc; 37711571Sjoerg } 37811571Sjoerg 37917987Speter for (l = limits; l->name && l->option != what; l++) 38017987Speter ; 38117987Speter if (!l->name) 382104208Stjr error("internal error (%c)", what); 38317987Speter 38417987Speter set = *argptr ? 1 : 0; 38517987Speter if (set) { 38617987Speter char *p = *argptr; 38717987Speter 38817987Speter if (all || argptr[1]) 389104208Stjr error("too many arguments"); 39017987Speter if (strcmp(p, "unlimited") == 0) 39111571Sjoerg val = RLIM_INFINITY; 39211571Sjoerg else { 393104282Smux val = 0; 39417987Speter 39517987Speter while ((c = *p++) >= '0' && c <= '9') 39617987Speter { 39717987Speter val = (val * 10) + (long)(c - '0'); 398104282Smux if (val < 0) 39917987Speter break; 40017987Speter } 40117987Speter if (c) 402104208Stjr error("bad number"); 40317987Speter val *= l->factor; 40411571Sjoerg } 40517987Speter } 40617987Speter if (all) { 407155301Sschweikh for (l = limits; l->name; l++) { 40818016Speter char optbuf[40]; 40918016Speter if (getrlimit(l->cmd, &limit) < 0) 410104208Stjr error("can't get limit: %s", strerror(errno)); 41117987Speter if (how & SOFT) 41217987Speter val = limit.rlim_cur; 41317987Speter else if (how & HARD) 41417987Speter val = limit.rlim_max; 41517987Speter 41618016Speter if (l->units) 41718016Speter snprintf(optbuf, sizeof(optbuf), 41818019Speter "(%s, -%c) ", l->units, l->option); 41918016Speter else 42018016Speter snprintf(optbuf, sizeof(optbuf), 42118019Speter "(-%c) ", l->option); 42218019Speter out1fmt("%-18s %18s ", l->name, optbuf); 42317987Speter if (val == RLIM_INFINITY) 42417987Speter out1fmt("unlimited\n"); 42517987Speter else 42617987Speter { 42717987Speter val /= l->factor; 428104282Smux out1fmt("%jd\n", (intmax_t)val); 42917987Speter } 43011571Sjoerg } 43117987Speter return 0; 43211571Sjoerg } 43317987Speter 43418016Speter if (getrlimit(l->cmd, &limit) < 0) 435104208Stjr error("can't get limit: %s", strerror(errno)); 43617987Speter if (set) { 43717987Speter if (how & SOFT) 43817987Speter limit.rlim_cur = val; 43917987Speter if (how & HARD) 44017987Speter limit.rlim_max = val; 44117987Speter if (setrlimit(l->cmd, &limit) < 0) 442104208Stjr error("bad limit: %s", strerror(errno)); 44317987Speter } else { 44417987Speter if (how & SOFT) 44517987Speter val = limit.rlim_cur; 44617987Speter else if (how & HARD) 44717987Speter val = limit.rlim_max; 44817987Speter 44917987Speter if (val == RLIM_INFINITY) 45017987Speter out1fmt("unlimited\n"); 45117987Speter else 45217987Speter { 45317987Speter val /= l->factor; 454104282Smux out1fmt("%jd\n", (intmax_t)val); 45517987Speter } 45617987Speter } 45711571Sjoerg return 0; 45811571Sjoerg} 459