miscbltin.c revision 190298
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 190298 2009-03-22 22:57:53Z stefanf $"); 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. 76190295Sstefanf * 77190295Sstefanf * Note that if IFS=' :' then read x y should work so that: 78190295Sstefanf * 'a b' x='a', y='b' 79190295Sstefanf * ' a b ' x='a', y='b' 80190295Sstefanf * ':b' x='', y='b' 81190295Sstefanf * ':' x='', y='' 82190295Sstefanf * '::' x='', y='' 83190295Sstefanf * ': :' x='', y='' 84190295Sstefanf * ':::' x='', y='::' 85190295Sstefanf * ':b c:' x='', y='b c:' 861556Srgrimes */ 871556Srgrimes 8817987Speterint 8990111Simpreadcmd(int argc __unused, char **argv __unused) 9017987Speter{ 911556Srgrimes char **ap; 921556Srgrimes int backslash; 931556Srgrimes char c; 9450394Stg int rflag; 951556Srgrimes char *prompt; 961556Srgrimes char *ifs; 971556Srgrimes char *p; 981556Srgrimes int startword; 991556Srgrimes int status; 1001556Srgrimes int i; 101190295Sstefanf int is_ifs; 102190295Sstefanf int saveall = 0; 10329983Smsmith struct timeval tv; 10429983Smsmith char *tvptr; 10529983Smsmith fd_set ifds; 10629983Smsmith struct termios told, tnew; 10729983Smsmith int tsaved; 1081556Srgrimes 10950394Stg rflag = 0; 1101556Srgrimes prompt = NULL; 11129983Smsmith tv.tv_sec = -1; 11229983Smsmith tv.tv_usec = 0; 11350394Stg while ((i = nextopt("erp:t:")) != '\0') { 11429983Smsmith switch(i) { 11529983Smsmith case 'p': 11659436Scracauer prompt = shoptarg; 11729983Smsmith break; 11829983Smsmith case 'e': 11929983Smsmith break; 12050394Stg case 'r': 12150394Stg rflag = 1; 12250394Stg break; 12329983Smsmith case 't': 12459436Scracauer tv.tv_sec = strtol(shoptarg, &tvptr, 0); 12559436Scracauer if (tvptr == shoptarg) 12629983Smsmith error("timeout value"); 12729983Smsmith switch(*tvptr) { 12829983Smsmith case 0: 12929983Smsmith case 's': 13029983Smsmith break; 13129983Smsmith case 'h': 13229983Smsmith tv.tv_sec *= 60; 13329983Smsmith /* FALLTHROUGH */ 13429983Smsmith case 'm': 13529983Smsmith tv.tv_sec *= 60; 13629983Smsmith break; 13729983Smsmith default: 13829983Smsmith error("timeout unit"); 13929983Smsmith } 14029983Smsmith break; 14129983Smsmith } 1421556Srgrimes } 1431556Srgrimes if (prompt && isatty(0)) { 1441556Srgrimes out2str(prompt); 1451556Srgrimes flushall(); 1461556Srgrimes } 1471556Srgrimes if (*(ap = argptr) == NULL) 1481556Srgrimes error("arg count"); 1491556Srgrimes if ((ifs = bltinlookup("IFS", 1)) == NULL) 150190298Sstefanf ifs = " \t\n"; 15129983Smsmith 15229983Smsmith if (tv.tv_sec >= 0) { 15329983Smsmith /* 15429983Smsmith * See if we can disable input processing; this will 15529983Smsmith * not give the desired result if we are in a pipeline 15629983Smsmith * and someone upstream is still in line-by-line mode. 15729983Smsmith */ 15829983Smsmith tsaved = 0; 15929983Smsmith if (tcgetattr(0, &told) == 0) { 16029983Smsmith memcpy(&tnew, &told, sizeof(told)); 16129983Smsmith cfmakeraw(&tnew); 162189542Sed tnew.c_iflag |= told.c_iflag & ICRNL; 16329983Smsmith tcsetattr(0, TCSANOW, &tnew); 16429983Smsmith tsaved = 1; 16529983Smsmith } 16629983Smsmith /* 16729983Smsmith * Wait for something to become available. 16829983Smsmith */ 16929983Smsmith FD_ZERO(&ifds); 17029983Smsmith FD_SET(0, &ifds); 17129983Smsmith status = select(1, &ifds, NULL, NULL, &tv); 17229983Smsmith if (tsaved) 17329983Smsmith tcsetattr(0, TCSANOW, &told); 17429983Smsmith /* 17529983Smsmith * If there's nothing ready, return an error. 17629983Smsmith */ 17729983Smsmith if (status <= 0) 17829983Smsmith return(1); 17929983Smsmith } 18029983Smsmith 1811556Srgrimes status = 0; 182190295Sstefanf startword = 2; 1831556Srgrimes backslash = 0; 1841556Srgrimes STARTSTACKSTR(p); 1851556Srgrimes for (;;) { 18680381Ssheldonh if (read(STDIN_FILENO, &c, 1) != 1) { 1871556Srgrimes status = 1; 1881556Srgrimes break; 1891556Srgrimes } 1901556Srgrimes if (c == '\0') 1911556Srgrimes continue; 1921556Srgrimes if (backslash) { 1931556Srgrimes backslash = 0; 1941556Srgrimes if (c != '\n') 1951556Srgrimes STPUTC(c, p); 1961556Srgrimes continue; 1971556Srgrimes } 19850394Stg if (!rflag && c == '\\') { 1991556Srgrimes backslash++; 2001556Srgrimes continue; 2011556Srgrimes } 2021556Srgrimes if (c == '\n') 2031556Srgrimes break; 204190295Sstefanf if (strchr(ifs, c)) 205190295Sstefanf is_ifs = strchr(" \t\n", c) ? 1 : 2; 206190295Sstefanf else 207190295Sstefanf is_ifs = 0; 208190295Sstefanf 209190295Sstefanf if (startword != 0) { 210190295Sstefanf if (is_ifs == 1) { 211190295Sstefanf /* Ignore leading IFS whitespace */ 212190295Sstefanf if (saveall) 213190295Sstefanf STPUTC(c, p); 214190295Sstefanf continue; 215190295Sstefanf } 216190295Sstefanf if (is_ifs == 2 && startword == 1) { 217190295Sstefanf /* Only one non-whitespace IFS per word */ 218190295Sstefanf startword = 2; 219190295Sstefanf if (saveall) 220190295Sstefanf STPUTC(c, p); 221190295Sstefanf continue; 222190295Sstefanf } 223190295Sstefanf } 224190295Sstefanf 225190295Sstefanf if (is_ifs == 0) { 226190295Sstefanf /* append this character to the current variable */ 227190295Sstefanf startword = 0; 228190295Sstefanf if (saveall) 229190295Sstefanf /* Not just a spare terminator */ 230190295Sstefanf saveall++; 231190295Sstefanf STPUTC(c, p); 2321556Srgrimes continue; 2331556Srgrimes } 234190295Sstefanf 235190295Sstefanf /* end of variable... */ 236190295Sstefanf startword = is_ifs; 237190295Sstefanf 238190295Sstefanf if (ap[1] == NULL) { 239190295Sstefanf /* Last variable needs all IFS chars */ 240190295Sstefanf saveall++; 2411556Srgrimes STPUTC(c, p); 242190295Sstefanf continue; 2431556Srgrimes } 244190295Sstefanf 245190295Sstefanf STACKSTRNUL(p); 246190295Sstefanf setvar(*ap, stackblock(), 0); 247190295Sstefanf ap++; 248190295Sstefanf STARTSTACKSTR(p); 2491556Srgrimes } 2501556Srgrimes STACKSTRNUL(p); 251190295Sstefanf 252190295Sstefanf /* Remove trailing IFS chars */ 253190295Sstefanf for (; stackblock() <= --p; *p = 0) { 254190295Sstefanf if (!strchr(ifs, *p)) 255190295Sstefanf break; 256190295Sstefanf if (strchr(" \t\n", *p)) 257190295Sstefanf /* Always remove whitespace */ 258190295Sstefanf continue; 259190295Sstefanf if (saveall > 1) 260190295Sstefanf /* Don't remove non-whitespace unless it was naked */ 261190295Sstefanf break; 262190295Sstefanf } 2631556Srgrimes setvar(*ap, stackblock(), 0); 264190295Sstefanf 265190295Sstefanf /* Set any remaining args to "" */ 2661556Srgrimes while (*++ap != NULL) 2671556Srgrimes setvar(*ap, nullstr, 0); 2681556Srgrimes return status; 2691556Srgrimes} 2701556Srgrimes 2711556Srgrimes 2721556Srgrimes 27317987Speterint 27490111Simpumaskcmd(int argc __unused, char **argv) 27517987Speter{ 27617987Speter char *ap; 2771556Srgrimes int mask; 2781556Srgrimes int i; 27917987Speter int symbolic_mode = 0; 2801556Srgrimes 28117987Speter while ((i = nextopt("S")) != '\0') { 28217987Speter symbolic_mode = 1; 2831556Srgrimes } 28411571Sjoerg 28517987Speter INTOFF; 28617987Speter mask = umask(0); 28717987Speter umask(mask); 28817987Speter INTON; 28911571Sjoerg 29017987Speter if ((ap = *argptr) == NULL) { 29117987Speter if (symbolic_mode) { 29217987Speter char u[4], g[4], o[4]; 29311571Sjoerg 29417987Speter i = 0; 29517987Speter if ((mask & S_IRUSR) == 0) 29617987Speter u[i++] = 'r'; 29717987Speter if ((mask & S_IWUSR) == 0) 29817987Speter u[i++] = 'w'; 29917987Speter if ((mask & S_IXUSR) == 0) 30017987Speter u[i++] = 'x'; 30117987Speter u[i] = '\0'; 30211571Sjoerg 30317987Speter i = 0; 30417987Speter if ((mask & S_IRGRP) == 0) 30517987Speter g[i++] = 'r'; 30617987Speter if ((mask & S_IWGRP) == 0) 30717987Speter g[i++] = 'w'; 30817987Speter if ((mask & S_IXGRP) == 0) 30917987Speter g[i++] = 'x'; 31017987Speter g[i] = '\0'; 31111571Sjoerg 31217987Speter i = 0; 31317987Speter if ((mask & S_IROTH) == 0) 31417987Speter o[i++] = 'r'; 31517987Speter if ((mask & S_IWOTH) == 0) 31617987Speter o[i++] = 'w'; 31717987Speter if ((mask & S_IXOTH) == 0) 31817987Speter o[i++] = 'x'; 31917987Speter o[i] = '\0'; 32011571Sjoerg 32117987Speter out1fmt("u=%s,g=%s,o=%s\n", u, g, o); 32217987Speter } else { 32317987Speter out1fmt("%.4o\n", mask); 32417987Speter } 32517987Speter } else { 32617987Speter if (isdigit(*ap)) { 32717987Speter mask = 0; 32817987Speter do { 32917987Speter if (*ap >= '8' || *ap < '0') 330149918Sstefanf error("Illegal number: %s", *argptr); 33117987Speter mask = (mask << 3) + (*ap - '0'); 33217987Speter } while (*++ap != '\0'); 33317987Speter umask(mask); 33417987Speter } else { 33520425Ssteve void *set; 336151795Sstefanf INTOFF; 33717987Speter if ((set = setmode (ap)) == 0) 33841844Simp error("Illegal number: %s", ap); 33911571Sjoerg 34017987Speter mask = getmode (set, ~mask & 0777); 34117987Speter umask(~mask & 0777); 34241844Simp free(set); 343151795Sstefanf INTON; 34417987Speter } 34517987Speter } 34611571Sjoerg return 0; 34711571Sjoerg} 34811571Sjoerg 34917987Speter/* 35017987Speter * ulimit builtin 35117987Speter * 35217987Speter * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and 35317987Speter * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with 35417987Speter * ash by J.T. Conklin. 35517987Speter * 35617987Speter * Public domain. 35717987Speter */ 35811571Sjoerg 35917987Speterstruct limits { 36017987Speter const char *name; 36118016Speter const char *units; 36217987Speter int cmd; 36317987Speter int factor; /* multiply by to get rlim_{cur,max} values */ 36417987Speter char option; 36517987Speter}; 36611571Sjoerg 36717987Speterstatic const struct limits limits[] = { 36817987Speter#ifdef RLIMIT_CPU 36918016Speter { "cpu time", "seconds", RLIMIT_CPU, 1, 't' }, 37017987Speter#endif 37117987Speter#ifdef RLIMIT_FSIZE 37218016Speter { "file size", "512-blocks", RLIMIT_FSIZE, 512, 'f' }, 37317987Speter#endif 37417987Speter#ifdef RLIMIT_DATA 37518016Speter { "data seg size", "kbytes", RLIMIT_DATA, 1024, 'd' }, 37617987Speter#endif 37717987Speter#ifdef RLIMIT_STACK 37818016Speter { "stack size", "kbytes", RLIMIT_STACK, 1024, 's' }, 37917987Speter#endif 38017987Speter#ifdef RLIMIT_CORE 38118016Speter { "core file size", "512-blocks", RLIMIT_CORE, 512, 'c' }, 38217987Speter#endif 38317987Speter#ifdef RLIMIT_RSS 38418016Speter { "max memory size", "kbytes", RLIMIT_RSS, 1024, 'm' }, 38517987Speter#endif 38617987Speter#ifdef RLIMIT_MEMLOCK 38718016Speter { "locked memory", "kbytes", RLIMIT_MEMLOCK, 1024, 'l' }, 38817987Speter#endif 38917987Speter#ifdef RLIMIT_NPROC 39018016Speter { "max user processes", (char *)0, RLIMIT_NPROC, 1, 'u' }, 39117987Speter#endif 39217987Speter#ifdef RLIMIT_NOFILE 39318016Speter { "open files", (char *)0, RLIMIT_NOFILE, 1, 'n' }, 39417987Speter#endif 39517987Speter#ifdef RLIMIT_VMEM 39618016Speter { "virtual mem size", "kbytes", RLIMIT_VMEM, 1024, 'v' }, 39717987Speter#endif 39817987Speter#ifdef RLIMIT_SWAP 39918016Speter { "swap limit", "kbytes", RLIMIT_SWAP, 1024, 'w' }, 40017987Speter#endif 40152072Sgreen#ifdef RLIMIT_SBSIZE 40252072Sgreen { "sbsize", "bytes", RLIMIT_SBSIZE, 1, 'b' }, 40352072Sgreen#endif 404181905Sed#ifdef RLIMIT_NPTS 405181905Sed { "pseudo-terminals", (char *)0, RLIMIT_NPTS, 1, 'p' }, 406181905Sed#endif 40718016Speter { (char *) 0, (char *)0, 0, 0, '\0' } 40817987Speter}; 40917987Speter 41017987Speterint 41190111Simpulimitcmd(int argc __unused, char **argv __unused) 41217987Speter{ 41325222Ssteve int c; 414104282Smux rlim_t val = 0; 41517987Speter enum { SOFT = 0x1, HARD = 0x2 } 41617987Speter how = SOFT | HARD; 41717987Speter const struct limits *l; 41817987Speter int set, all = 0; 41917987Speter int optc, what; 42017987Speter struct rlimit limit; 42111571Sjoerg 42217987Speter what = 'f'; 423181905Sed while ((optc = nextopt("HSatfdsmcnuvlbp")) != '\0') 42417987Speter switch (optc) { 42511571Sjoerg case 'H': 42617987Speter how = HARD; 42711571Sjoerg break; 42811571Sjoerg case 'S': 42917987Speter how = SOFT; 43011571Sjoerg break; 43111571Sjoerg case 'a': 43217987Speter all = 1; 43311571Sjoerg break; 43417987Speter default: 43517987Speter what = optc; 43611571Sjoerg } 43711571Sjoerg 43817987Speter for (l = limits; l->name && l->option != what; l++) 43917987Speter ; 44017987Speter if (!l->name) 441104208Stjr error("internal error (%c)", what); 44217987Speter 44317987Speter set = *argptr ? 1 : 0; 44417987Speter if (set) { 44517987Speter char *p = *argptr; 44617987Speter 44717987Speter if (all || argptr[1]) 448104208Stjr error("too many arguments"); 44917987Speter if (strcmp(p, "unlimited") == 0) 45011571Sjoerg val = RLIM_INFINITY; 45111571Sjoerg else { 452104282Smux val = 0; 45317987Speter 45417987Speter while ((c = *p++) >= '0' && c <= '9') 45517987Speter { 45617987Speter val = (val * 10) + (long)(c - '0'); 457104282Smux if (val < 0) 45817987Speter break; 45917987Speter } 46017987Speter if (c) 461104208Stjr error("bad number"); 46217987Speter val *= l->factor; 46311571Sjoerg } 46417987Speter } 46517987Speter if (all) { 466155301Sschweikh for (l = limits; l->name; l++) { 46718016Speter char optbuf[40]; 46818016Speter if (getrlimit(l->cmd, &limit) < 0) 469104208Stjr error("can't get limit: %s", strerror(errno)); 47017987Speter if (how & SOFT) 47117987Speter val = limit.rlim_cur; 47217987Speter else if (how & HARD) 47317987Speter val = limit.rlim_max; 47417987Speter 47518016Speter if (l->units) 47618016Speter snprintf(optbuf, sizeof(optbuf), 47718019Speter "(%s, -%c) ", l->units, l->option); 47818016Speter else 47918016Speter snprintf(optbuf, sizeof(optbuf), 48018019Speter "(-%c) ", l->option); 48118019Speter out1fmt("%-18s %18s ", l->name, optbuf); 48217987Speter if (val == RLIM_INFINITY) 48317987Speter out1fmt("unlimited\n"); 48417987Speter else 48517987Speter { 48617987Speter val /= l->factor; 487104282Smux out1fmt("%jd\n", (intmax_t)val); 48817987Speter } 48911571Sjoerg } 49017987Speter return 0; 49111571Sjoerg } 49217987Speter 49318016Speter if (getrlimit(l->cmd, &limit) < 0) 494104208Stjr error("can't get limit: %s", strerror(errno)); 49517987Speter if (set) { 49617987Speter if (how & SOFT) 49717987Speter limit.rlim_cur = val; 49817987Speter if (how & HARD) 49917987Speter limit.rlim_max = val; 50017987Speter if (setrlimit(l->cmd, &limit) < 0) 501104208Stjr error("bad limit: %s", strerror(errno)); 50217987Speter } else { 50317987Speter if (how & SOFT) 50417987Speter val = limit.rlim_cur; 50517987Speter else if (how & HARD) 50617987Speter val = limit.rlim_max; 50717987Speter 50817987Speter if (val == RLIM_INFINITY) 50917987Speter out1fmt("unlimited\n"); 51017987Speter else 51117987Speter { 51217987Speter val /= l->factor; 513104282Smux out1fmt("%jd\n", (intmax_t)val); 51417987Speter } 51517987Speter } 51611571Sjoerg return 0; 51711571Sjoerg} 518