1 /*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Kenneth Almquist. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95"; 40 #endif 41 static const char rcsid[] = 42 "$FreeBSD$"; 43 #endif /* not lint */ 44 45 /* 46 * Miscellaneous builtins. 47 */ 48 49 #include <sys/types.h> 50 #include <sys/stat.h> 51 #include <sys/time.h> 52 #include <sys/resource.h> 53 #include <unistd.h> 54 #include <ctype.h> 55 #include <errno.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <termios.h> 59 60 #include "shell.h" 61 #include "options.h" 62 #include "var.h" 63 #include "output.h" 64 #include "memalloc.h" 65 #include "error.h" 66 #include "mystring.h" 67 68 #undef eflag 69 70 /* 71 * The read builtin. The -r option causes backslashes to be treated like 72 * ordinary characters. 73 * 74 * This uses unbuffered input, which may be avoidable in some cases. 75 */ 76 77 int 78 readcmd(argc, argv) 79 int argc __unused; 80 char **argv __unused; 81 { 82 char **ap; 83 int backslash; 84 char c; 85 int rflag; 86 char *prompt; 87 char *ifs; 88 char *p; 89 int startword; 90 int status; 91 int i; 92 struct timeval tv; 93 char *tvptr; 94 fd_set ifds; 95 struct termios told, tnew; 96 int tsaved; 97 98 rflag = 0; 99 prompt = NULL; 100 tv.tv_sec = -1; 101 tv.tv_usec = 0; 102 while ((i = nextopt("erp:t:")) != '\0') { 103 switch(i) { 104 case 'p': 105 prompt = shoptarg; 106 break; 107 case 'e': 108 break; 109 case 'r': 110 rflag = 1; 111 break; 112 case 't': 113 tv.tv_sec = strtol(shoptarg, &tvptr, 0); 114 if (tvptr == shoptarg) 115 error("timeout value"); 116 switch(*tvptr) { 117 case 0: 118 case 's': 119 break; 120 case 'h': 121 tv.tv_sec *= 60; 122 /* FALLTHROUGH */ 123 case 'm': 124 tv.tv_sec *= 60; 125 break; 126 default: 127 error("timeout unit"); 128 } 129 break; 130 } 131 } 132 if (prompt && isatty(0)) { 133 out2str(prompt); 134 flushall(); 135 } 136 if (*(ap = argptr) == NULL) 137 error("arg count"); 138 if ((ifs = bltinlookup("IFS", 1)) == NULL) 139 ifs = nullstr; 140 141 if (tv.tv_sec >= 0) { 142 /* 143 * See if we can disable input processing; this will 144 * not give the desired result if we are in a pipeline 145 * and someone upstream is still in line-by-line mode. 146 */ 147 tsaved = 0; 148 if (tcgetattr(0, &told) == 0) { 149 memcpy(&tnew, &told, sizeof(told)); 150 cfmakeraw(&tnew); 151 tcsetattr(0, TCSANOW, &tnew); 152 tsaved = 1; 153 } 154 /* 155 * Wait for something to become available. 156 */ 157 FD_ZERO(&ifds); 158 FD_SET(0, &ifds); 159 status = select(1, &ifds, NULL, NULL, &tv); 160 if (tsaved) 161 tcsetattr(0, TCSANOW, &told); 162 /* 163 * If there's nothing ready, return an error. 164 */ 165 if (status <= 0) 166 return(1); 167 } 168 169 status = 0; 170 startword = 1; 171 backslash = 0; 172 STARTSTACKSTR(p); 173 for (;;) { 174 if (read(STDIN_FILENO, &c, 1) != 1) { 175 status = 1; 176 break; 177 } 178 if (c == '\0') 179 continue; 180 if (backslash) { 181 backslash = 0; 182 if (c != '\n') 183 STPUTC(c, p); 184 continue; 185 } 186 if (!rflag && c == '\\') { 187 backslash++; 188 continue; 189 } 190 if (c == '\n') 191 break; 192 if (startword && *ifs == ' ' && strchr(ifs, c)) { 193 continue; 194 } 195 startword = 0; 196 if (backslash && c == '\\') { 197 if (read(STDIN_FILENO, &c, 1) != 1) { 198 status = 1; 199 break; 200 } 201 STPUTC(c, p); 202 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) { 203 STACKSTRNUL(p); 204 setvar(*ap, stackblock(), 0); 205 ap++; 206 startword = 1; 207 STARTSTACKSTR(p); 208 } else { 209 STPUTC(c, p); 210 } 211 } 212 STACKSTRNUL(p); 213 setvar(*ap, stackblock(), 0); 214 while (*++ap != NULL) 215 setvar(*ap, nullstr, 0); 216 return status; 217 } 218 219 220 221 int 222 umaskcmd(argc, argv) 223 int argc __unused; 224 char **argv; 225 { 226 char *ap; 227 int mask; 228 int i; 229 int symbolic_mode = 0; 230 231 while ((i = nextopt("S")) != '\0') { 232 symbolic_mode = 1; 233 } 234 235 INTOFF; 236 mask = umask(0); 237 umask(mask); 238 INTON; 239 240 if ((ap = *argptr) == NULL) { 241 if (symbolic_mode) { 242 char u[4], g[4], o[4]; 243 244 i = 0; 245 if ((mask & S_IRUSR) == 0) 246 u[i++] = 'r'; 247 if ((mask & S_IWUSR) == 0) 248 u[i++] = 'w'; 249 if ((mask & S_IXUSR) == 0) 250 u[i++] = 'x'; 251 u[i] = '\0'; 252 253 i = 0; 254 if ((mask & S_IRGRP) == 0) 255 g[i++] = 'r'; 256 if ((mask & S_IWGRP) == 0) 257 g[i++] = 'w'; 258 if ((mask & S_IXGRP) == 0) 259 g[i++] = 'x'; 260 g[i] = '\0'; 261 262 i = 0; 263 if ((mask & S_IROTH) == 0) 264 o[i++] = 'r'; 265 if ((mask & S_IWOTH) == 0) 266 o[i++] = 'w'; 267 if ((mask & S_IXOTH) == 0) 268 o[i++] = 'x'; 269 o[i] = '\0'; 270 271 out1fmt("u=%s,g=%s,o=%s\n", u, g, o); 272 } else { 273 out1fmt("%.4o\n", mask); 274 } 275 } else { 276 if (isdigit(*ap)) { 277 mask = 0; 278 do { 279 if (*ap >= '8' || *ap < '0') 280 error("Illegal number: %s", argv[1]); 281 mask = (mask << 3) + (*ap - '0'); 282 } while (*++ap != '\0'); 283 umask(mask); 284 } else { 285 void *set; 286 if ((set = setmode (ap)) == 0) 287 error("Illegal number: %s", ap); 288 289 mask = getmode (set, ~mask & 0777); 290 umask(~mask & 0777); 291 free(set); 292 } 293 } 294 return 0; 295 } 296 297 /* 298 * ulimit builtin 299 * 300 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and 301 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with 302 * ash by J.T. Conklin. 303 * 304 * Public domain. 305 */ 306 307 struct limits { 308 const char *name; 309 const char *units; 310 int cmd; 311 int factor; /* multiply by to get rlim_{cur,max} values */ 312 char option; 313 }; 314 315 static const struct limits limits[] = { 316 #ifdef RLIMIT_CPU 317 { "cpu time", "seconds", RLIMIT_CPU, 1, 't' }, 318 #endif 319 #ifdef RLIMIT_FSIZE 320 { "file size", "512-blocks", RLIMIT_FSIZE, 512, 'f' }, 321 #endif 322 #ifdef RLIMIT_DATA 323 { "data seg size", "kbytes", RLIMIT_DATA, 1024, 'd' }, 324 #endif 325 #ifdef RLIMIT_STACK 326 { "stack size", "kbytes", RLIMIT_STACK, 1024, 's' }, 327 #endif 328 #ifdef RLIMIT_CORE 329 { "core file size", "512-blocks", RLIMIT_CORE, 512, 'c' }, 330 #endif 331 #ifdef RLIMIT_RSS 332 { "max memory size", "kbytes", RLIMIT_RSS, 1024, 'm' }, 333 #endif 334 #ifdef RLIMIT_MEMLOCK 335 { "locked memory", "kbytes", RLIMIT_MEMLOCK, 1024, 'l' }, 336 #endif 337 #ifdef RLIMIT_NPROC 338 { "max user processes", (char *)0, RLIMIT_NPROC, 1, 'u' }, 339 #endif 340 #ifdef RLIMIT_NOFILE 341 { "open files", (char *)0, RLIMIT_NOFILE, 1, 'n' }, 342 #endif 343 #ifdef RLIMIT_VMEM 344 { "virtual mem size", "kbytes", RLIMIT_VMEM, 1024, 'v' }, 345 #endif 346 #ifdef RLIMIT_SWAP 347 { "swap limit", "kbytes", RLIMIT_SWAP, 1024, 'w' }, 348 #endif 349 #ifdef RLIMIT_SBSIZE 350 { "sbsize", "bytes", RLIMIT_SBSIZE, 1, 'b' }, 351 #endif 352 { (char *) 0, (char *)0, 0, 0, '\0' } 353 }; 354 355 int 356 ulimitcmd(argc, argv) 357 int argc __unused; 358 char **argv __unused; 359 { 360 int c; 361 quad_t val = 0; 362 enum { SOFT = 0x1, HARD = 0x2 } 363 how = SOFT | HARD; 364 const struct limits *l; 365 int set, all = 0; 366 int optc, what; 367 struct rlimit limit; 368 369 what = 'f'; 370 while ((optc = nextopt("HSatfdsmcnulb")) != '\0') 371 switch (optc) { 372 case 'H': 373 how = HARD; 374 break; 375 case 'S': 376 how = SOFT; 377 break; 378 case 'a': 379 all = 1; 380 break; 381 default: 382 what = optc; 383 } 384 385 for (l = limits; l->name && l->option != what; l++) 386 ; 387 if (!l->name) 388 error("ulimit: internal error (%c)", what); 389 390 set = *argptr ? 1 : 0; 391 if (set) { 392 char *p = *argptr; 393 394 if (all || argptr[1]) 395 error("ulimit: too many arguments"); 396 if (strcmp(p, "unlimited") == 0) 397 val = RLIM_INFINITY; 398 else { 399 val = (quad_t) 0; 400 401 while ((c = *p++) >= '0' && c <= '9') 402 { 403 val = (val * 10) + (long)(c - '0'); 404 if (val < (quad_t) 0) 405 break; 406 } 407 if (c) 408 error("ulimit: bad number"); 409 val *= l->factor; 410 } 411 } 412 if (all) { 413 for (l = limits; l->name; l++) { 414 char optbuf[40]; 415 if (getrlimit(l->cmd, &limit) < 0) 416 error("ulimit: can't get limit: %s", strerror(errno)); 417 if (how & SOFT) 418 val = limit.rlim_cur; 419 else if (how & HARD) 420 val = limit.rlim_max; 421 422 if (l->units) 423 snprintf(optbuf, sizeof(optbuf), 424 "(%s, -%c) ", l->units, l->option); 425 else 426 snprintf(optbuf, sizeof(optbuf), 427 "(-%c) ", l->option); 428 out1fmt("%-18s %18s ", l->name, optbuf); 429 if (val == RLIM_INFINITY) 430 out1fmt("unlimited\n"); 431 else 432 { 433 val /= l->factor; 434 out1fmt("%qd\n", (quad_t) val); 435 } 436 } 437 return 0; 438 } 439 440 if (getrlimit(l->cmd, &limit) < 0) 441 error("ulimit: can't get limit: %s", strerror(errno)); 442 if (set) { 443 if (how & SOFT) 444 limit.rlim_cur = val; 445 if (how & HARD) 446 limit.rlim_max = val; 447 if (setrlimit(l->cmd, &limit) < 0) 448 error("ulimit: bad limit: %s", strerror(errno)); 449 } else { 450 if (how & SOFT) 451 val = limit.rlim_cur; 452 else if (how & HARD) 453 val = limit.rlim_max; 454 455 if (val == RLIM_INFINITY) 456 out1fmt("unlimited\n"); 457 else 458 { 459 val /= l->factor; 460 out1fmt("%qd\n", (quad_t) val); 461 } 462 } 463 return 0; 464 } 465