1*6b10aaf3Skre /* $NetBSD: miscbltin.c,v 1.56 2024/10/12 23:34:56 kre Exp $ */ 249f0ad86Scgd 361f28255Scgd /*- 437ed7877Sjtc * Copyright (c) 1991, 1993 537ed7877Sjtc * The Regents of the University of California. All rights reserved. 661f28255Scgd * 761f28255Scgd * This code is derived from software contributed to Berkeley by 861f28255Scgd * Kenneth Almquist. 961f28255Scgd * 1061f28255Scgd * Redistribution and use in source and binary forms, with or without 1161f28255Scgd * modification, are permitted provided that the following conditions 1261f28255Scgd * are met: 1361f28255Scgd * 1. Redistributions of source code must retain the above copyright 1461f28255Scgd * notice, this list of conditions and the following disclaimer. 1561f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright 1661f28255Scgd * notice, this list of conditions and the following disclaimer in the 1761f28255Scgd * documentation and/or other materials provided with the distribution. 18b5b29542Sagc * 3. Neither the name of the University nor the names of its contributors 1961f28255Scgd * may be used to endorse or promote products derived from this software 2061f28255Scgd * without specific prior written permission. 2161f28255Scgd * 2261f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2361f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2461f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2561f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2661f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2761f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2861f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2961f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3061f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3161f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3261f28255Scgd * SUCH DAMAGE. 3361f28255Scgd */ 3461f28255Scgd 35cd799663Schristos #include <sys/cdefs.h> 3661f28255Scgd #ifndef lint 3749f0ad86Scgd #if 0 3807bae7edSchristos static char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95"; 3949f0ad86Scgd #else 40*6b10aaf3Skre __RCSID("$NetBSD: miscbltin.c,v 1.56 2024/10/12 23:34:56 kre Exp $"); 4149f0ad86Scgd #endif 4261f28255Scgd #endif /* not lint */ 4361f28255Scgd 4461f28255Scgd /* 45b5a5957fSandvar * Miscellaneous builtins. 4661f28255Scgd */ 4761f28255Scgd 48e3f5fb92Schristos #include <sys/param.h> /* BSD4_4 */ 494899054aSkre #include <sys/resource.h> 50759eadefSjtc #include <sys/stat.h> 5107bae7edSchristos #include <sys/time.h> 524899054aSkre #include <sys/types.h> /* quad_t */ 534899054aSkre 54a81e4124Sjtc #include <ctype.h> 551d9dab3eSchristos #include <errno.h> 564899054aSkre #include <limits.h> 574899054aSkre #include <stdlib.h> 584899054aSkre #ifndef SMALL 594899054aSkre #include <termios.h> 604899054aSkre #endif 614899054aSkre #include <unistd.h> 6207bae7edSchristos 6361f28255Scgd #include "shell.h" 6461f28255Scgd #include "options.h" 6561f28255Scgd #include "var.h" 664899054aSkre #include "input.h" /* for whichprompt */ 6761f28255Scgd #include "output.h" 684899054aSkre #include "parser.h" /* for getprompt() */ 6961f28255Scgd #include "memalloc.h" 7061f28255Scgd #include "error.h" 714fc4fe2eSchristos #include "builtins.h" 7261f28255Scgd #include "mystring.h" 73c15b76c2Skre #include "redir.h" /* for user_fd_limit */ 7461f28255Scgd 7561f28255Scgd /* 764803d37fSdsl * The read builtin. 77b5a5957fSandvar * Backslashes escape the next char unless -r is specified. 7861f28255Scgd * 7961f28255Scgd * This uses unbuffered input, which may be avoidable in some cases. 804803d37fSdsl * 814803d37fSdsl * Note that if IFS=' :' then read x y should work so that: 824803d37fSdsl * 'a b' x='a', y='b' 834803d37fSdsl * ' a b ' x='a', y='b' 844803d37fSdsl * ':b' x='', y='b' 854803d37fSdsl * ':' x='', y='' 864803d37fSdsl * '::' x='', y='' 874803d37fSdsl * ': :' x='', y='' 884803d37fSdsl * ':::' x='', y='::' 894803d37fSdsl * ':b c:' x='', y='b c:' 9061f28255Scgd */ 9161f28255Scgd 924899054aSkre #ifndef SMALL 934899054aSkre static int b_flag; 944899054aSkre 954899054aSkre static int 964899054aSkre setrawmode(int fd, int on, int end, struct termios *t) 974899054aSkre { 984899054aSkre struct termios n; 994899054aSkre 1004899054aSkre if (on) { 1014899054aSkre if (tcgetattr(fd, t) != 0) 1024899054aSkre return 0; 1034899054aSkre n = *t; 1044899054aSkre if (on == 1 && b_flag) { 1054899054aSkre n.c_cc[VEOL] = end; 1064899054aSkre } else { 1074899054aSkre cfmakeraw(&n); 1084899054aSkre n.c_iflag |= ICRNL; 1094899054aSkre n.c_oflag = t->c_oflag; 1104899054aSkre n.c_lflag |= ECHO | ISIG; 1114899054aSkre } 1124899054aSkre if (tcsetattr(fd, TCSADRAIN | TCSASOFT, &n) == 0) 1134899054aSkre return 1; 1144899054aSkre } else 1154899054aSkre (void)tcsetattr(fd, TCSADRAIN | TCSASOFT, t); 1164899054aSkre return 0; 1174899054aSkre } 1184899054aSkre 1194899054aSkre static int 1204899054aSkre is_a_pipe(int fd) 1214899054aSkre { 1224899054aSkre if (lseek(fd, 0, SEEK_CUR) == -1 && errno == ESPIPE) { 1234899054aSkre errno = 0; 1244899054aSkre return 1; 1254899054aSkre } 1264899054aSkre return 0; 1274899054aSkre } 1284899054aSkre 1294899054aSkre #define READ_BUFFER_SIZE 512 1304899054aSkre 1314899054aSkre static int 1324899054aSkre next_read_char(int fd, size_t max) 1334899054aSkre { 1344899054aSkre static char buffer[READ_BUFFER_SIZE]; 1354899054aSkre static int pos = 0, len = 0; 1364899054aSkre 1374899054aSkre if (max == 0) { 1384899054aSkre pos = len = 0; 1394899054aSkre return -1; 1404899054aSkre } 1414899054aSkre if (max == (size_t)-1) { 1424899054aSkre /* 1434899054aSkre * If possible, and necessary, rewind the file 1444899054aSkre * so unprocessed data can be read again next time 1454899054aSkre * 1464899054aSkre * If that fails, never mind (-b allows that to happen) 1474899054aSkre */ 1484899054aSkre if (b_flag && pos < len) 1494899054aSkre (void)lseek(fd, (off_t)(pos - len), SEEK_CUR); 1504899054aSkre return -1; 1514899054aSkre } 1524899054aSkre 1534899054aSkre if (b_flag == 0) { 1544899054aSkre char c; 1554899054aSkre 1564899054aSkre (void) max; 1574899054aSkre if (read(fd, &c, 1) != 1) 1584899054aSkre return -1; 1594899054aSkre return (c & 0xFF); 1604899054aSkre } 1614899054aSkre 1624899054aSkre if (pos >= len) { 1634899054aSkre pos = 0; 1644899054aSkre if (max > sizeof buffer) 1654899054aSkre max = sizeof buffer; 1664899054aSkre len = read(fd, buffer, max); 1674899054aSkre if (len <= 0) 1684899054aSkre return -1; 1694899054aSkre } 1704899054aSkre 1714899054aSkre return buffer[pos++] & 0xFF; 1724899054aSkre } 1734899054aSkre 1744899054aSkre #define READ_OPTS "bd:n:p:r" 1754899054aSkre 1764899054aSkre #else 1774899054aSkre 1784899054aSkre static inline int 1794899054aSkre next_read_char(int fd, size_t max) 1804899054aSkre { 1814899054aSkre char c; 1824899054aSkre 1834899054aSkre if (max == 0 || max == (size_t)-1) 1844899054aSkre return 0; 1854899054aSkre 1864899054aSkre if (read(fd, &c, 1) != 1) 1874899054aSkre return -1; 1884899054aSkre return (c & 0xFF); 1894899054aSkre } 1904899054aSkre 1914899054aSkre #define n_flag 0 1924899054aSkre #define maxlen 0 1934899054aSkre 1944899054aSkre #define READ_OPTS "d:p:r" 1954899054aSkre 1964899054aSkre #endif 1974899054aSkre 1984ce0d34aScgd int 199c02b3bbdSchristos readcmd(int argc, char **argv) 2004ce0d34aScgd { 20161f28255Scgd char **ap; 2024899054aSkre int c; 203e2731928Skre char end; 2044899054aSkre int r_flag; 20561f28255Scgd char *prompt; 2064803d37fSdsl const char *ifs; 20761f28255Scgd char *p; 20861f28255Scgd int startword; 20961f28255Scgd int status; 21061f28255Scgd int i; 2114803d37fSdsl int is_ifs; 2124803d37fSdsl int saveall = 0; 2134899054aSkre int read_tty = 0; 214143e8d55Skre ptrdiff_t wordlen = 0; 21528b2f4e3Skre char *newifs = NULL; 21628b2f4e3Skre struct stackmark mk; 21761f28255Scgd 2184899054aSkre #ifndef SMALL 2194899054aSkre struct termios ttystate; 2204899054aSkre int n_flag, maxlen; 2214899054aSkre int setraw = 0; 2224899054aSkre 2234899054aSkre b_flag = 0; 2244899054aSkre n_flag = 0; 2254899054aSkre maxlen = READ_BUFFER_SIZE - 1; 2264899054aSkre #endif 2274899054aSkre 228e2731928Skre end = '\n'; /* record delimiter */ 2294899054aSkre r_flag = 0; 23061f28255Scgd prompt = NULL; 2314899054aSkre whichprompt = 2; /* for continuation lines */ 2324899054aSkre 2334899054aSkre while ((i = nextopt(READ_OPTS)) != '\0') { 234e2731928Skre switch (i) { 235e2731928Skre case 'd': 236e2731928Skre end = *optionarg; /* even if '\0' */ 237e2731928Skre break; 238e2731928Skre case 'p': 23933809804Schristos prompt = optionarg; 240e2731928Skre break; 241e2731928Skre case 'r': 2424899054aSkre r_flag = 1; 243e2731928Skre break; 2444899054aSkre #ifndef SMALL 2454899054aSkre case 'n': 2464899054aSkre maxlen = number(optionarg); 2474899054aSkre if (maxlen > (INT_MAX >> 8) + 1) /* sanity */ 2484899054aSkre error("-n %s too large", optionarg); 2494899054aSkre n_flag = 1; 2504899054aSkre break; 2514899054aSkre case 'b': 2524899054aSkre if (!is_a_pipe(0)) 2534899054aSkre b_flag = 1; 2544899054aSkre break; 2554899054aSkre #endif 256e2731928Skre } 25761f28255Scgd } 2584803d37fSdsl 259a1f66056Skre if (*(ap = argptr) == NULL) 260a1f66056Skre error("variable name required\n" 2614899054aSkre #ifdef SMALL 2624899054aSkre "Usage: read [-r] [-d C] [-p prompt] var..."); 2634899054aSkre #else 2644899054aSkre "Usage: read [-br] [-d C] [-n len] [-p prompt] var..."); 265a1f66056Skre 2664899054aSkre (void)next_read_char(0, 0); /* make sure the buffer is empty */ 2674899054aSkre #endif 2684899054aSkre 2694899054aSkre if (isatty(0)) { 2704899054aSkre read_tty = 1; 2714899054aSkre if (prompt) { 27261f28255Scgd out2str(prompt); 27361f28255Scgd flushall(); 27461f28255Scgd } 2754899054aSkre #ifndef SMALL 2764899054aSkre b_flag = 1; /* always buffer reads from ttys */ 2774803d37fSdsl 2784899054aSkre if (n_flag || end != '\n') 2794899054aSkre setraw = setrawmode(0, 1 + n_flag, end, &ttystate); 2804899054aSkre #endif 2814899054aSkre } 2824899054aSkre 28361f28255Scgd if ((ifs = bltinlookup("IFS", 1)) == NULL) 2844803d37fSdsl ifs = " \t\n"; 2854803d37fSdsl 28628b2f4e3Skre setstackmark(&mk); 28761f28255Scgd status = 0; 2884803d37fSdsl startword = 2; 28961f28255Scgd STARTSTACKSTR(p); 2904899054aSkre 2914899054aSkre #ifdef SMALL 29261f28255Scgd for ( ; ; ) { 2934899054aSkre #else 2944899054aSkre for ( ; !n_flag || --maxlen >= 0 ; ) { 2954899054aSkre #endif 2964899054aSkre if ((c = next_read_char(0, maxlen + 1)) < 0) { 29761f28255Scgd status = 1; 29861f28255Scgd break; 29961f28255Scgd } 3004899054aSkre if (c == '\\' && c != end && !r_flag) { 3014899054aSkre #ifndef SMALL 3024899054aSkre if (n_flag && --maxlen < 0) 3034899054aSkre break; 3044899054aSkre #endif 3054899054aSkre if ((c = next_read_char(0, maxlen + 1)) < 0) { 30661f28255Scgd status = 1; 30761f28255Scgd break; 30861f28255Scgd } 309e2731928Skre if (c != '\n') /* \ \n is always just removed */ 310143e8d55Skre goto wdch; 3114899054aSkre if (read_tty) 3124899054aSkre out2str(getprompt(NULL)); 3134803d37fSdsl continue; 3144803d37fSdsl } 315e2731928Skre if (c == end) 3164803d37fSdsl break; 317e2731928Skre if (c == '\0') 318e2731928Skre continue; 3194803d37fSdsl if (strchr(ifs, c)) 3204803d37fSdsl is_ifs = strchr(" \t\n", c) ? 1 : 2; 3214803d37fSdsl else 3224803d37fSdsl is_ifs = 0; 3234803d37fSdsl 3244803d37fSdsl if (startword != 0) { 3254803d37fSdsl if (is_ifs == 1) { 3264803d37fSdsl /* Ignore leading IFS whitespace */ 3274803d37fSdsl if (saveall) 3284803d37fSdsl STPUTC(c, p); 3294803d37fSdsl continue; 3304803d37fSdsl } 3314803d37fSdsl if (is_ifs == 2 && startword == 1) { 3324803d37fSdsl /* Only one non-whitespace IFS per word */ 3334803d37fSdsl startword = 2; 3344803d37fSdsl if (saveall) 3354803d37fSdsl STPUTC(c, p); 3364803d37fSdsl continue; 3374803d37fSdsl } 3384803d37fSdsl } 3394803d37fSdsl 3404803d37fSdsl if (is_ifs == 0) { 341143e8d55Skre wdch:; 342e2731928Skre if (c == '\0') /* always ignore attempts to input \0 */ 343e2731928Skre continue; 3444803d37fSdsl /* append this character to the current variable */ 3454803d37fSdsl startword = 0; 3464803d37fSdsl if (saveall) 3474803d37fSdsl /* Not just a spare terminator */ 3484803d37fSdsl saveall++; 3494803d37fSdsl STPUTC(c, p); 350143e8d55Skre wordlen = p - stackblock(); 3514803d37fSdsl continue; 3524803d37fSdsl } 3534803d37fSdsl 3544803d37fSdsl /* end of variable... */ 3554803d37fSdsl startword = is_ifs; 3564803d37fSdsl 3574803d37fSdsl if (ap[1] == NULL) { 3584803d37fSdsl /* Last variable needs all IFS chars */ 3594803d37fSdsl saveall++; 3604803d37fSdsl STPUTC(c, p); 3614803d37fSdsl continue; 3624803d37fSdsl } 3634803d37fSdsl 36428b2f4e3Skre if (equal(*ap, "IFS")) { 36528b2f4e3Skre /* 36628b2f4e3Skre * we must not alter the value of IFS, as our 36728b2f4e3Skre * local "ifs" var is (perhaps) pointing at it, 36828b2f4e3Skre * at best we would be using data after free() 36928b2f4e3Skre * the next time we reference ifs - but that mem 37028b2f4e3Skre * may have been reused for something different. 37128b2f4e3Skre * 37228b2f4e3Skre * note that this might occur several times 37328b2f4e3Skre */ 37428b2f4e3Skre STPUTC('\0', p); 37528b2f4e3Skre newifs = grabstackstr(p); 37628b2f4e3Skre } else { 37761f28255Scgd STACKSTRNUL(p); 37861f28255Scgd setvar(*ap, stackblock(), 0); 37928b2f4e3Skre } 38061f28255Scgd ap++; 38161f28255Scgd STARTSTACKSTR(p); 382143e8d55Skre wordlen = 0; 38361f28255Scgd } 38461f28255Scgd STACKSTRNUL(p); 3854803d37fSdsl 3864899054aSkre #ifndef SMALL 3874899054aSkre (void)next_read_char(0, (size_t)-1); /* attempt to seek back */ 3884899054aSkre if (setraw) 3894899054aSkre setrawmode(0, 0, end, &ttystate); 3904899054aSkre #endif 3914899054aSkre 3924899054aSkre 3934803d37fSdsl /* Remove trailing IFS chars */ 394143e8d55Skre for (; stackblock() + wordlen <= --p; *p = 0) { 3954803d37fSdsl if (!strchr(ifs, *p)) 3964803d37fSdsl break; 3974803d37fSdsl if (strchr(" \t\n", *p)) 3984803d37fSdsl /* Always remove whitespace */ 3994803d37fSdsl continue; 4004803d37fSdsl if (saveall > 1) 4014803d37fSdsl /* Don't remove non-whitespace unless it was naked */ 4024803d37fSdsl break; 4034803d37fSdsl } 40428b2f4e3Skre 40528b2f4e3Skre /* 40628b2f4e3Skre * If IFS was one of the variables named, we can finally set it now 40728b2f4e3Skre * (no further references to ifs will be made) 40828b2f4e3Skre */ 40928b2f4e3Skre if (newifs != NULL) 41028b2f4e3Skre setvar("IFS", newifs, 0); 41128b2f4e3Skre 41228b2f4e3Skre /* 41328b2f4e3Skre * Now we can assign to the final variable (which might 41428b2f4e3Skre * also be IFS, hence the ordering here) 41528b2f4e3Skre */ 41661f28255Scgd setvar(*ap, stackblock(), 0); 4174803d37fSdsl 4184803d37fSdsl /* Set any remaining args to "" */ 41961f28255Scgd while (*++ap != NULL) 42061f28255Scgd setvar(*ap, nullstr, 0); 42128b2f4e3Skre 42228b2f4e3Skre popstackmark(&mk); 42361f28255Scgd return status; 42461f28255Scgd } 42561f28255Scgd 42661f28255Scgd 42761f28255Scgd 4284ce0d34aScgd int 429c02b3bbdSchristos umaskcmd(int argc, char **argv) 4304ce0d34aScgd { 431759eadefSjtc char *ap; 432d17e063cSkre mode_t mask; 43361f28255Scgd int i; 434759eadefSjtc int symbolic_mode = 0; 43561f28255Scgd 436759eadefSjtc while ((i = nextopt("S")) != '\0') { 437759eadefSjtc symbolic_mode = 1; 438759eadefSjtc } 439759eadefSjtc 44061f28255Scgd INTOFF; 44161f28255Scgd mask = umask(0); 44261f28255Scgd umask(mask); 44361f28255Scgd INTON; 444759eadefSjtc 445759eadefSjtc if ((ap = *argptr) == NULL) { 446759eadefSjtc if (symbolic_mode) { 447759eadefSjtc char u[4], g[4], o[4]; 448759eadefSjtc 449759eadefSjtc i = 0; 450759eadefSjtc if ((mask & S_IRUSR) == 0) 451759eadefSjtc u[i++] = 'r'; 452759eadefSjtc if ((mask & S_IWUSR) == 0) 453759eadefSjtc u[i++] = 'w'; 454759eadefSjtc if ((mask & S_IXUSR) == 0) 455759eadefSjtc u[i++] = 'x'; 456759eadefSjtc u[i] = '\0'; 457759eadefSjtc 458759eadefSjtc i = 0; 459759eadefSjtc if ((mask & S_IRGRP) == 0) 460759eadefSjtc g[i++] = 'r'; 461759eadefSjtc if ((mask & S_IWGRP) == 0) 462759eadefSjtc g[i++] = 'w'; 463759eadefSjtc if ((mask & S_IXGRP) == 0) 464759eadefSjtc g[i++] = 'x'; 465759eadefSjtc g[i] = '\0'; 466759eadefSjtc 467759eadefSjtc i = 0; 468759eadefSjtc if ((mask & S_IROTH) == 0) 469759eadefSjtc o[i++] = 'r'; 470759eadefSjtc if ((mask & S_IWOTH) == 0) 471759eadefSjtc o[i++] = 'w'; 472759eadefSjtc if ((mask & S_IXOTH) == 0) 473759eadefSjtc o[i++] = 'x'; 474759eadefSjtc o[i] = '\0'; 475759eadefSjtc 476759eadefSjtc out1fmt("u=%s,g=%s,o=%s\n", u, g, o); 47761f28255Scgd } else { 478759eadefSjtc out1fmt("%.4o\n", mask); 479759eadefSjtc } 480759eadefSjtc } else { 481f792cdd7Schristos if (isdigit((unsigned char)*ap)) { 482d17e063cSkre int range = 0; 483d17e063cSkre 48461f28255Scgd mask = 0; 48561f28255Scgd do { 486759eadefSjtc if (*ap >= '8' || *ap < '0') 48794d6cf1cSkre error("Not a valid octal number: '%s'", 488d17e063cSkre *argptr); 489759eadefSjtc mask = (mask << 3) + (*ap - '0'); 490d17e063cSkre if (mask & ~07777) 491d17e063cSkre range = 1; 492759eadefSjtc } while (*++ap != '\0'); 493d17e063cSkre if (range) 494d17e063cSkre error("Mask constant '%s' out of range", *argptr); 49561f28255Scgd umask(mask); 496759eadefSjtc } else { 497759eadefSjtc void *set; 498759eadefSjtc 499cc484b78Sitohy INTOFF; 500cc484b78Sitohy if ((set = setmode(ap)) != 0) { 501759eadefSjtc mask = getmode(set, ~mask & 0777); 502cc484b78Sitohy ckfree(set); 503cc484b78Sitohy } 504cc484b78Sitohy INTON; 505cc484b78Sitohy if (!set) 506c05266afSchristos error("Cannot set mode `%s' (%s)", ap, 507c05266afSchristos strerror(errno)); 508cc484b78Sitohy 509759eadefSjtc umask(~mask & 0777); 510759eadefSjtc } 51161f28255Scgd } 512b65a5b90Skre flushout(out1); 513b65a5b90Skre if (io_err(out1)) { 514b65a5b90Skre out2str("umask: I/O error\n"); 515b65a5b90Skre return 1; 516b65a5b90Skre } 51761f28255Scgd return 0; 51861f28255Scgd } 51907bae7edSchristos 52007bae7edSchristos /* 52107bae7edSchristos * ulimit builtin 52207bae7edSchristos * 52307bae7edSchristos * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and 52407bae7edSchristos * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with 52507bae7edSchristos * ash by J.T. Conklin. 52607bae7edSchristos * 52707bae7edSchristos * Public domain. 52807bae7edSchristos */ 52907bae7edSchristos 53007bae7edSchristos struct limits { 53107bae7edSchristos const char *name; 53213d04b59Schristos const char *unit; 53307bae7edSchristos char option; 534f378cfe5Skre int8_t cmd; /* all RLIMIT_xxx are <= 127 */ 535f378cfe5Skre unsigned short factor; /* multiply by to get rlim_{cur,max} values */ 53607bae7edSchristos }; 53707bae7edSchristos 538f378cfe5Skre #define OPTSTRING_BASE "HSa" 539f378cfe5Skre 54007bae7edSchristos static const struct limits limits[] = { 54107bae7edSchristos #ifdef RLIMIT_CPU 542f378cfe5Skre { "time", "seconds", 't', RLIMIT_CPU, 1 }, 543f378cfe5Skre #define OPTSTRING_t OPTSTRING_BASE "t" 544f378cfe5Skre #else 545f378cfe5Skre #define OPTSTRING_t OPTSTRING_BASE 54607bae7edSchristos #endif 54707bae7edSchristos #ifdef RLIMIT_FSIZE 548f378cfe5Skre { "file", "blocks", 'f', RLIMIT_FSIZE, 512 }, 549f378cfe5Skre #define OPTSTRING_f OPTSTRING_t "f" 550f378cfe5Skre #else 551f378cfe5Skre #define OPTSTRING_f OPTSTRING_t 55207bae7edSchristos #endif 55307bae7edSchristos #ifdef RLIMIT_DATA 554f378cfe5Skre { "data", "kbytes", 'd', RLIMIT_DATA, 1024 }, 555f378cfe5Skre #define OPTSTRING_d OPTSTRING_f "d" 556f378cfe5Skre #else 557f378cfe5Skre #define OPTSTRING_d OPTSTRING_f 55807bae7edSchristos #endif 55907bae7edSchristos #ifdef RLIMIT_STACK 560f378cfe5Skre { "stack", "kbytes", 's', RLIMIT_STACK, 1024 }, 561f378cfe5Skre #define OPTSTRING_s OPTSTRING_d "s" 562f378cfe5Skre #else 563f378cfe5Skre #define OPTSTRING_s OPTSTRING_d 56407bae7edSchristos #endif 56507bae7edSchristos #ifdef RLIMIT_CORE 566f378cfe5Skre { "coredump", "blocks", 'c', RLIMIT_CORE, 512 }, 567f378cfe5Skre #define OPTSTRING_c OPTSTRING_s "c" 568f378cfe5Skre #else 569f378cfe5Skre #define OPTSTRING_c OPTSTRING_s 57007bae7edSchristos #endif 57107bae7edSchristos #ifdef RLIMIT_RSS 572f378cfe5Skre { "memory", "kbytes", 'm', RLIMIT_RSS, 1024 }, 573f378cfe5Skre #define OPTSTRING_m OPTSTRING_c "m" 574f378cfe5Skre #else 575f378cfe5Skre #define OPTSTRING_m OPTSTRING_c 57607bae7edSchristos #endif 57707bae7edSchristos #ifdef RLIMIT_MEMLOCK 578f378cfe5Skre { "locked memory","kbytes", 'l', RLIMIT_MEMLOCK, 1024 }, 579f378cfe5Skre #define OPTSTRING_l OPTSTRING_m "l" 580f378cfe5Skre #else 581f378cfe5Skre #define OPTSTRING_l OPTSTRING_m 58207bae7edSchristos #endif 583426530ccSchristos #ifdef RLIMIT_NTHR 584f378cfe5Skre { "thread", "threads", 'r', RLIMIT_NTHR, 1 }, 585f378cfe5Skre #define OPTSTRING_r OPTSTRING_l "r" 586f378cfe5Skre #else 587f378cfe5Skre #define OPTSTRING_r OPTSTRING_l 588426530ccSchristos #endif 58907bae7edSchristos #ifdef RLIMIT_NPROC 590f378cfe5Skre { "process", "processes", 'p', RLIMIT_NPROC, 1 }, 591f378cfe5Skre #define OPTSTRING_p OPTSTRING_r "p" 592f378cfe5Skre #else 593f378cfe5Skre #define OPTSTRING_p OPTSTRING_r 59407bae7edSchristos #endif 59507bae7edSchristos #ifdef RLIMIT_NOFILE 596f378cfe5Skre { "nofiles", "descriptors", 'n', RLIMIT_NOFILE, 1 }, 597f378cfe5Skre #define OPTSTRING_n OPTSTRING_p "n" 598f378cfe5Skre #else 599f378cfe5Skre #define OPTSTRING_n OPTSTRING_p 60007bae7edSchristos #endif 60107bae7edSchristos #ifdef RLIMIT_VMEM 602f378cfe5Skre { "vmemory", "kbytes", 'v', RLIMIT_VMEM, 1024 }, 603f378cfe5Skre #define OPTSTRING_v OPTSTRING_n "v" 604f378cfe5Skre #else 605f378cfe5Skre #define OPTSTRING_v OPTSTRING_n 60607bae7edSchristos #endif 60707bae7edSchristos #ifdef RLIMIT_SWAP 608f378cfe5Skre { "swap", "kbytes", 'w', RLIMIT_SWAP, 1024 }, 609f378cfe5Skre #define OPTSTRING_w OPTSTRING_v "w" 610f378cfe5Skre #else 611f378cfe5Skre #define OPTSTRING_w OPTSTRING_v 61207bae7edSchristos #endif 6136acf809eSchristos #ifdef RLIMIT_SBSIZE 614f378cfe5Skre { "sbsize", "bytes", 'b', RLIMIT_SBSIZE, 1 }, 615f378cfe5Skre #define OPTSTRING_b OPTSTRING_w "b" 616f378cfe5Skre #else 617f378cfe5Skre #define OPTSTRING_b OPTSTRING_w 6186acf809eSchristos #endif 619f378cfe5Skre { NULL, NULL, '\0', 0, 0 } 62007bae7edSchristos }; 621f378cfe5Skre #define OPTSTRING OPTSTRING_b 62207bae7edSchristos 62307bae7edSchristos int 624c02b3bbdSchristos ulimitcmd(int argc, char **argv) 62507bae7edSchristos { 62648250187Stls int c; 627cd799663Schristos rlim_t val = 0; 62807bae7edSchristos enum { SOFT = 0x1, HARD = 0x2 } 629c15b76c2Skre how = 0, which; 63007bae7edSchristos const struct limits *l; 63107bae7edSchristos int set, all = 0; 63207bae7edSchristos int optc, what; 63307bae7edSchristos struct rlimit limit; 63407bae7edSchristos 63507bae7edSchristos what = 'f'; 636f378cfe5Skre while ((optc = nextopt(OPTSTRING)) != '\0') 63707bae7edSchristos switch (optc) { 63807bae7edSchristos case 'H': 639c15b76c2Skre how |= HARD; 64007bae7edSchristos break; 64107bae7edSchristos case 'S': 642c15b76c2Skre how |= SOFT; 64307bae7edSchristos break; 64407bae7edSchristos case 'a': 64507bae7edSchristos all = 1; 64607bae7edSchristos break; 64707bae7edSchristos default: 64807bae7edSchristos what = optc; 64907bae7edSchristos } 65007bae7edSchristos 65107bae7edSchristos for (l = limits; l->name && l->option != what; l++) 65207bae7edSchristos ; 65307bae7edSchristos if (!l->name) 6541d9dab3eSchristos error("internal error (%c)", what); 65507bae7edSchristos 65607bae7edSchristos set = *argptr ? 1 : 0; 65707bae7edSchristos if (set) { 65807bae7edSchristos char *p = *argptr; 65907bae7edSchristos 66007bae7edSchristos if (all || argptr[1]) 6611d9dab3eSchristos error("too many arguments"); 662c15b76c2Skre if (how == 0) 663c15b76c2Skre how = HARD | SOFT; 664c15b76c2Skre 66507bae7edSchristos if (strcmp(p, "unlimited") == 0) 66607bae7edSchristos val = RLIM_INFINITY; 66707bae7edSchristos else { 66888fc62feSjtc val = (rlim_t) 0; 66907bae7edSchristos 670c15b76c2Skre while ((c = *p++) >= '0' && c <= '9') { 671c15b76c2Skre if (val >= RLIM_INFINITY/10) 672f378cfe5Skre error("%s: value overflow", *argptr); 673c15b76c2Skre val = (val * 10); 674c15b76c2Skre if (val >= RLIM_INFINITY - (long)(c - '0')) 675f378cfe5Skre error("%s: value overflow", *argptr); 676c15b76c2Skre val += (long)(c - '0'); 677c15b76c2Skre } 67807bae7edSchristos if (c) 679f378cfe5Skre error("%s: bad number", *argptr); 680c15b76c2Skre if (val > RLIM_INFINITY / l->factor) 681f378cfe5Skre error("%s: value overflow", *argptr); 68207bae7edSchristos val *= l->factor; 68307bae7edSchristos } 684c15b76c2Skre } else if (how == 0) 685c15b76c2Skre how = SOFT; 686c15b76c2Skre 68707bae7edSchristos if (all) { 68807bae7edSchristos for (l = limits; l->name; l++) { 68907bae7edSchristos getrlimit(l->cmd, &limit); 69013d04b59Schristos out1fmt("%-13s (-%c %-11s) ", l->name, l->option, 69113d04b59Schristos l->unit); 692c15b76c2Skre 693c15b76c2Skre which = how; 694c15b76c2Skre while (which != 0) { 695c15b76c2Skre if (which & SOFT) { 696c15b76c2Skre val = limit.rlim_cur; 697c15b76c2Skre which &= ~SOFT; 698c15b76c2Skre } else if (which & HARD) { 699c15b76c2Skre val = limit.rlim_max; 700c15b76c2Skre which &= ~HARD; 701c15b76c2Skre } 702c15b76c2Skre 70307bae7edSchristos if (val == RLIM_INFINITY) 704c15b76c2Skre out1fmt("unlimited"); 705c15b76c2Skre else { 70607bae7edSchristos val /= l->factor; 707360e930dSchristos #ifdef BSD4_4 708c15b76c2Skre out1fmt("%9lld", (long long) val); 709360e930dSchristos #else 710c15b76c2Skre out1fmt("%9ld", (long) val); 711360e930dSchristos #endif 71207bae7edSchristos } 713c15b76c2Skre out1fmt("%c", which ? '\t' : '\n'); 714c15b76c2Skre } 71507bae7edSchristos } 716b65a5b90Skre goto done; 71707bae7edSchristos } 71807bae7edSchristos 7199c27fd2aSchristos if (getrlimit(l->cmd, &limit) == -1) 7209c27fd2aSchristos error("error getting limit (%s)", strerror(errno)); 72107bae7edSchristos if (set) { 72207bae7edSchristos if (how & HARD) 72307bae7edSchristos limit.rlim_max = val; 7241d9dab3eSchristos if (how & SOFT) 7251d9dab3eSchristos limit.rlim_cur = val; 72607bae7edSchristos if (setrlimit(l->cmd, &limit) < 0) 7271d9dab3eSchristos error("error setting limit (%s)", strerror(errno)); 728c15b76c2Skre if (l->cmd == RLIMIT_NOFILE) 729c15b76c2Skre user_fd_limit = sysconf(_SC_OPEN_MAX); 73007bae7edSchristos } else { 73107bae7edSchristos if (how & SOFT) 73207bae7edSchristos val = limit.rlim_cur; 73307bae7edSchristos else if (how & HARD) 73407bae7edSchristos val = limit.rlim_max; 73507bae7edSchristos 73607bae7edSchristos if (val == RLIM_INFINITY) 73707bae7edSchristos out1fmt("unlimited\n"); 73807bae7edSchristos else 73907bae7edSchristos { 74007bae7edSchristos val /= l->factor; 741360e930dSchristos #ifdef BSD4_4 742f819878cSlukem out1fmt("%lld\n", (long long) val); 743360e930dSchristos #else 744360e930dSchristos out1fmt("%ld\n", (long) val); 745360e930dSchristos #endif 74607bae7edSchristos } 74707bae7edSchristos } 748b65a5b90Skre done:; 749b65a5b90Skre flushout(out1); 750b65a5b90Skre if (io_err(out1)) { 751b65a5b90Skre out2str("ulimit: I/O error (stdout)\n"); 752b65a5b90Skre return 1; 753b65a5b90Skre } 75407bae7edSchristos return 0; 75507bae7edSchristos } 756