miscbltin.c revision 99110
10SN/A/*- 21410Sihse * Copyright (c) 1991, 1993 30SN/A * The Regents of the University of California. All rights reserved. 40SN/A * 50SN/A * This code is derived from software contributed to Berkeley by 60SN/A * Kenneth Almquist. 7180SN/A * 80SN/A * Redistribution and use in source and binary forms, with or without 9180SN/A * modification, are permitted provided that the following conditions 100SN/A * are met: 110SN/A * 1. Redistributions of source code must retain the above copyright 120SN/A * notice, this list of conditions and the following disclaimer. 130SN/A * 2. Redistributions in binary form must reproduce the above copyright 140SN/A * notice, this list of conditions and the following disclaimer in the 150SN/A * documentation and/or other materials provided with the distribution. 160SN/A * 3. All advertising materials mentioning features or use of this software 170SN/A * must display the following acknowledgement: 180SN/A * This product includes software developed by the University of 190SN/A * California, Berkeley and its contributors. 200SN/A * 4. Neither the name of the University nor the names of its contributors 21180SN/A * may be used to endorse or promote products derived from this software 22180SN/A * without specific prior written permission. 23180SN/A * 240SN/A * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 250SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261410Sihse * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271410Sihse * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281410Sihse * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291410Sihse * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301410Sihse * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311410Sihse * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32910SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33910SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341410Sihse * SUCH DAMAGE. 355SN/A */ 36910SN/A 371410Sihse#ifndef lint 38910SN/A#if 0 39338SN/Astatic char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95"; 401426Sihse#endif 411410Sihse#endif /* not lint */ 421426Sihse#include <sys/cdefs.h> 431410Sihse__FBSDID("$FreeBSD: head/bin/sh/miscbltin.c 99110 2002-06-30 05:15:05Z obrien $"); 441410Sihse 451426Sihse/* 461426Sihse * Miscellaneous builtins. 47311SN/A */ 481426Sihse 491426Sihse#include <sys/types.h> 501426Sihse#include <sys/stat.h> 511410Sihse#include <sys/time.h> 521426Sihse#include <sys/resource.h> 531651Sihse#include <unistd.h> 541651Sihse#include <ctype.h> 551120SN/A#include <errno.h> 561410Sihse#include <stdio.h> 571410Sihse#include <stdlib.h> 581410Sihse#include <termios.h> 591426Sihse 601426Sihse#include "shell.h" 611426Sihse#include "options.h" 621426Sihse#include "var.h" 631426Sihse#include "output.h" 641426Sihse#include "memalloc.h" 651426Sihse#include "error.h" 661426Sihse#include "mystring.h" 671426Sihse 681426Sihse#undef eflag 691426Sihse 701426Sihse/* 711426Sihse * The read builtin. The -r option causes backslashes to be treated like 721426Sihse * ordinary characters. 731426Sihse * 741426Sihse * This uses unbuffered input, which may be avoidable in some cases. 751426Sihse */ 761426Sihse 771426Sihseint 781426Sihsereadcmd(int argc __unused, char **argv __unused) 791426Sihse{ 801426Sihse char **ap; 811426Sihse int backslash; 821426Sihse char c; 831426Sihse int rflag; 841426Sihse char *prompt; 851426Sihse char *ifs; 861426Sihse char *p; 871426Sihse int startword; 881426Sihse int status; 891426Sihse int i; 901426Sihse struct timeval tv; 911426Sihse char *tvptr; 921426Sihse fd_set ifds; 931426Sihse struct termios told, tnew; 941426Sihse int tsaved; 951426Sihse 961426Sihse rflag = 0; 971426Sihse prompt = NULL; 981426Sihse tv.tv_sec = -1; 991426Sihse tv.tv_usec = 0; 1001426Sihse while ((i = nextopt("erp:t:")) != '\0') { 1011426Sihse switch(i) { 1021426Sihse case 'p': 1031426Sihse prompt = shoptarg; 1041426Sihse break; 1051426Sihse case 'e': 1061426Sihse break; 1071426Sihse case 'r': 1081426Sihse rflag = 1; 1091426Sihse break; 1101426Sihse case 't': 1111426Sihse tv.tv_sec = strtol(shoptarg, &tvptr, 0); 1121426Sihse if (tvptr == shoptarg) 1131426Sihse error("timeout value"); 1141426Sihse switch(*tvptr) { 1151426Sihse case 0: 1161426Sihse case 's': 1171426Sihse break; 1181426Sihse case 'h': 1191426Sihse tv.tv_sec *= 60; 1201426Sihse /* FALLTHROUGH */ 1211426Sihse case 'm': 1221426Sihse tv.tv_sec *= 60; 1231426Sihse break; 1241410Sihse default: 1251120SN/A error("timeout unit"); 1261426Sihse } 1271426Sihse break; 1281426Sihse } 1291426Sihse } 1301426Sihse if (prompt && isatty(0)) { 1311426Sihse out2str(prompt); 1321426Sihse flushall(); 1331410Sihse } 1341426Sihse if (*(ap = argptr) == NULL) 1351426Sihse error("arg count"); 1361426Sihse if ((ifs = bltinlookup("IFS", 1)) == NULL) 13727SN/A ifs = nullstr; 1381410Sihse 1391410Sihse if (tv.tv_sec >= 0) { 1401701Sihse /* 1411701Sihse * See if we can disable input processing; this will 1421701Sihse * not give the desired result if we are in a pipeline 1431410Sihse * and someone upstream is still in line-by-line mode. 1441410Sihse */ 1451410Sihse tsaved = 0; 1461410Sihse if (tcgetattr(0, &told) == 0) { 1471410Sihse memcpy(&tnew, &told, sizeof(told)); 1481410Sihse cfmakeraw(&tnew); 1491410Sihse tcsetattr(0, TCSANOW, &tnew); 1501426Sihse tsaved = 1; 1511426Sihse } 1521410Sihse /* 1531410Sihse * Wait for something to become available. 1541410Sihse */ 1551156SN/A FD_ZERO(&ifds); 1561120SN/A FD_SET(0, &ifds); 1571936Sihse status = select(1, &ifds, NULL, NULL, &tv); 1581936Sihse if (tsaved) 1591936Sihse tcsetattr(0, TCSANOW, &told); 1601426Sihse /* 1611426Sihse * If there's nothing ready, return an error. 1621426Sihse */ 1631426Sihse if (status <= 0) 1641410Sihse return(1); 16527SN/A } 1661426Sihse 1671426Sihse status = 0; 1681426Sihse startword = 1; 1691426Sihse backslash = 0; 1701426Sihse STARTSTACKSTR(p); 1711426Sihse for (;;) { 1721651Sihse if (read(STDIN_FILENO, &c, 1) != 1) { 1731651Sihse status = 1; 1741915Sihse break; 1751651Sihse } 1761651Sihse if (c == '\0') 1771651Sihse continue; 1781651Sihse if (backslash) { 1791426Sihse backslash = 0; 1801426Sihse if (c != '\n') 1811426Sihse STPUTC(c, p); 1821426Sihse continue; 1831651Sihse } 1841426Sihse if (!rflag && c == '\\') { 1851410Sihse backslash++; 1861410Sihse continue; 1871410Sihse } 1881651Sihse if (c == '\n') 1891410Sihse break; 1901426Sihse if (startword && *ifs == ' ' && strchr(ifs, c)) { 1911651Sihse continue; 1921651Sihse } 1931651Sihse startword = 0; 1941651Sihse if (backslash && c == '\\') { 1951651Sihse if (read(STDIN_FILENO, &c, 1) != 1) { 1961651Sihse status = 1; 1971651Sihse break; 1981651Sihse } 1991651Sihse STPUTC(c, p); 2001651Sihse } else if (ap[1] != NULL && strchr(ifs, c) != NULL) { 2011651Sihse STACKSTRNUL(p); 2021651Sihse setvar(*ap, stackblock(), 0); 2031651Sihse ap++; 2041651Sihse startword = 1; 2051410Sihse STARTSTACKSTR(p); 2061410Sihse } else { 2071410Sihse STPUTC(c, p); 2081410Sihse } 2090SN/A } 2101426Sihse STACKSTRNUL(p); 2111410Sihse setvar(*ap, stackblock(), 0); 2121410Sihse while (*++ap != NULL) 2131410Sihse setvar(*ap, nullstr, 0); 2141410Sihse return status; 2151410Sihse} 2161410Sihse 2171410Sihse 2181410Sihse 2191410Sihseint 2201426Sihseumaskcmd(int argc __unused, char **argv) 2211426Sihse{ 2221426Sihse char *ap; 2231426Sihse int mask; 2241426Sihse int i; 2251426Sihse int symbolic_mode = 0; 2261426Sihse 2271426Sihse while ((i = nextopt("S")) != '\0') { 2281651Sihse symbolic_mode = 1; 2291651Sihse } 2301651Sihse 2311410Sihse INTOFF; 2321862Serikj mask = umask(0); 2331862Serikj umask(mask); 2341410Sihse INTON; 2351410Sihse 2361410Sihse if ((ap = *argptr) == NULL) { 2371410Sihse if (symbolic_mode) { 2381410Sihse char u[4], g[4], o[4]; 2391410Sihse 2401426Sihse i = 0; 2411426Sihse if ((mask & S_IRUSR) == 0) 2421426Sihse u[i++] = 'r'; 2431426Sihse if ((mask & S_IWUSR) == 0) 2441426Sihse u[i++] = 'w'; 2451426Sihse if ((mask & S_IXUSR) == 0) 2461426Sihse u[i++] = 'x'; 2471426Sihse u[i] = '\0'; 2481426Sihse 2491426Sihse i = 0; 2501426Sihse if ((mask & S_IRGRP) == 0) 2511426Sihse g[i++] = 'r'; 2521426Sihse if ((mask & S_IWGRP) == 0) 2531327SN/A g[i++] = 'w'; 2541628Sihse if ((mask & S_IXGRP) == 0) 2551628Sihse g[i++] = 'x'; 2561628Sihse g[i] = '\0'; 2571410Sihse 2581410Sihse i = 0; 2591410Sihse if ((mask & S_IROTH) == 0) 2601410Sihse o[i++] = 'r'; 2611410Sihse if ((mask & S_IWOTH) == 0) 2621410Sihse o[i++] = 'w'; 2631410Sihse if ((mask & S_IXOTH) == 0) 2641410Sihse o[i++] = 'x'; 2651410Sihse o[i] = '\0'; 2661426Sihse 2671426Sihse out1fmt("u=%s,g=%s,o=%s\n", u, g, o); 2681426Sihse } else { 2691410Sihse out1fmt("%.4o\n", mask); 2701651Sihse } 2711426Sihse } else { 2721426Sihse if (isdigit(*ap)) { 2731410Sihse mask = 0; 2741410Sihse do { 2751410Sihse if (*ap >= '8' || *ap < '0') 2761410Sihse error("Illegal number: %s", argv[1]); 2771410Sihse mask = (mask << 3) + (*ap - '0'); 2780SN/A } while (*++ap != '\0'); 2791426Sihse umask(mask); 2801426Sihse } else { 2811426Sihse void *set; 2821623Sihse if ((set = setmode (ap)) == 0) 2831862Serikj error("Illegal number: %s", ap); 2841426Sihse 2851426Sihse mask = getmode (set, ~mask & 0777); 2861862Serikj umask(~mask & 0777); 2871426Sihse free(set); 2881426Sihse } 2891426Sihse } 2901426Sihse return 0; 2911426Sihse} 2921426Sihse 2931426Sihse/* 2941426Sihse * ulimit builtin 2951862Serikj * 2961623Sihse * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and 2971862Serikj * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with 2981862Serikj * ash by J.T. Conklin. 2991862Serikj * 3001862Serikj * Public domain. 3011623Sihse */ 3021623Sihse 3031623Sihsestruct limits { 3041426Sihse const char *name; 3051426Sihse const char *units; 3061426Sihse int cmd; 3071426Sihse int factor; /* multiply by to get rlim_{cur,max} values */ 3081862Serikj char option; 3091410Sihse}; 3101410Sihse 3111623Sihsestatic const struct limits limits[] = { 3121745Sihse#ifdef RLIMIT_CPU 3131745Sihse { "cpu time", "seconds", RLIMIT_CPU, 1, 't' }, 3141745Sihse#endif 3151745Sihse#ifdef RLIMIT_FSIZE 3161745Sihse { "file size", "512-blocks", RLIMIT_FSIZE, 512, 'f' }, 3171623Sihse#endif 3181623Sihse#ifdef RLIMIT_DATA 3191651Sihse { "data seg size", "kbytes", RLIMIT_DATA, 1024, 'd' }, 3201651Sihse#endif 3211900Sihse#ifdef RLIMIT_STACK 3221745Sihse { "stack size", "kbytes", RLIMIT_STACK, 1024, 's' }, 3231651Sihse#endif 3241651Sihse#ifdef RLIMIT_CORE 3251926Serikj { "core file size", "512-blocks", RLIMIT_CORE, 512, 'c' }, 3261745Sihse#endif 3271745Sihse#ifdef RLIMIT_RSS 3281651Sihse { "max memory size", "kbytes", RLIMIT_RSS, 1024, 'm' }, 3291623Sihse#endif 3301410Sihse#ifdef RLIMIT_MEMLOCK 331 { "locked memory", "kbytes", RLIMIT_MEMLOCK, 1024, 'l' }, 332#endif 333#ifdef RLIMIT_NPROC 334 { "max user processes", (char *)0, RLIMIT_NPROC, 1, 'u' }, 335#endif 336#ifdef RLIMIT_NOFILE 337 { "open files", (char *)0, RLIMIT_NOFILE, 1, 'n' }, 338#endif 339#ifdef RLIMIT_VMEM 340 { "virtual mem size", "kbytes", RLIMIT_VMEM, 1024, 'v' }, 341#endif 342#ifdef RLIMIT_SWAP 343 { "swap limit", "kbytes", RLIMIT_SWAP, 1024, 'w' }, 344#endif 345#ifdef RLIMIT_SBSIZE 346 { "sbsize", "bytes", RLIMIT_SBSIZE, 1, 'b' }, 347#endif 348 { (char *) 0, (char *)0, 0, 0, '\0' } 349}; 350 351int 352ulimitcmd(int argc __unused, char **argv __unused) 353{ 354 int c; 355 quad_t val = 0; 356 enum { SOFT = 0x1, HARD = 0x2 } 357 how = SOFT | HARD; 358 const struct limits *l; 359 int set, all = 0; 360 int optc, what; 361 struct rlimit limit; 362 363 what = 'f'; 364 while ((optc = nextopt("HSatfdsmcnuvlb")) != '\0') 365 switch (optc) { 366 case 'H': 367 how = HARD; 368 break; 369 case 'S': 370 how = SOFT; 371 break; 372 case 'a': 373 all = 1; 374 break; 375 default: 376 what = optc; 377 } 378 379 for (l = limits; l->name && l->option != what; l++) 380 ; 381 if (!l->name) 382 error("ulimit: internal error (%c)", what); 383 384 set = *argptr ? 1 : 0; 385 if (set) { 386 char *p = *argptr; 387 388 if (all || argptr[1]) 389 error("ulimit: too many arguments"); 390 if (strcmp(p, "unlimited") == 0) 391 val = RLIM_INFINITY; 392 else { 393 val = (quad_t) 0; 394 395 while ((c = *p++) >= '0' && c <= '9') 396 { 397 val = (val * 10) + (long)(c - '0'); 398 if (val < (quad_t) 0) 399 break; 400 } 401 if (c) 402 error("ulimit: bad number"); 403 val *= l->factor; 404 } 405 } 406 if (all) { 407 for (l = limits; l->name; l++) { 408 char optbuf[40]; 409 if (getrlimit(l->cmd, &limit) < 0) 410 error("ulimit: can't get limit: %s", strerror(errno)); 411 if (how & SOFT) 412 val = limit.rlim_cur; 413 else if (how & HARD) 414 val = limit.rlim_max; 415 416 if (l->units) 417 snprintf(optbuf, sizeof(optbuf), 418 "(%s, -%c) ", l->units, l->option); 419 else 420 snprintf(optbuf, sizeof(optbuf), 421 "(-%c) ", l->option); 422 out1fmt("%-18s %18s ", l->name, optbuf); 423 if (val == RLIM_INFINITY) 424 out1fmt("unlimited\n"); 425 else 426 { 427 val /= l->factor; 428 out1fmt("%qd\n", (quad_t) val); 429 } 430 } 431 return 0; 432 } 433 434 if (getrlimit(l->cmd, &limit) < 0) 435 error("ulimit: can't get limit: %s", strerror(errno)); 436 if (set) { 437 if (how & SOFT) 438 limit.rlim_cur = val; 439 if (how & HARD) 440 limit.rlim_max = val; 441 if (setrlimit(l->cmd, &limit) < 0) 442 error("ulimit: bad limit: %s", strerror(errno)); 443 } else { 444 if (how & SOFT) 445 val = limit.rlim_cur; 446 else if (how & HARD) 447 val = limit.rlim_max; 448 449 if (val == RLIM_INFINITY) 450 out1fmt("unlimited\n"); 451 else 452 { 453 val /= l->factor; 454 out1fmt("%qd\n", (quad_t) val); 455 } 456 } 457 return 0; 458} 459