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 extern char **argptr; /* argument list for builtin command */ 71 72 73 /* 74 * The read builtin. The -r option causes backslashes to be treated like 75 * ordinary characters. 76 * 77 * This uses unbuffered input, which may be avoidable in some cases. 78 */ 79 80 int 81 readcmd(argc, argv) 82 int argc __unused; 83 char **argv __unused; 84 { 85 char **ap; 86 int backslash; 87 char c; 88 int rflag; 89 char *prompt; 90 char *ifs; 91 char *p; 92 int startword; 93 int status; 94 int i; 95 struct timeval tv; 96 char *tvptr; 97 fd_set ifds; 98 struct termios told, tnew; 99 int tsaved; 100 101 rflag = 0; 102 prompt = NULL; 103 tv.tv_sec = -1; 104 tv.tv_usec = 0; 105 while ((i = nextopt("erp:t:")) != '\0') { 106 switch(i) { 107 case 'p': 108 prompt = optarg; 109 break; 110 case 'e': 111 break; 112 case 'r': 113 rflag = 1; 114 break; 115 case 't': 116 tv.tv_sec = strtol(optarg, &tvptr, 0); 117 if (tvptr == optarg) 118 error("timeout value"); 119 switch(*tvptr) { 120 case 0: 121 case 's': 122 break; 123 case 'h': 124 tv.tv_sec *= 60; 125 /* FALLTHROUGH */ 126 case 'm': 127 tv.tv_sec *= 60; 128 break; 129 default: 130 error("timeout unit"); 131 } 132 break; 133 } 134 } 135 if (prompt && isatty(0)) { 136 out2str(prompt); 137 flushall(); 138 } 139 if (*(ap = argptr) == NULL) 140 error("arg count"); 141 if ((ifs = bltinlookup("IFS", 1)) == NULL) 142 ifs = nullstr; 143 144 if (tv.tv_sec >= 0) { 145 /* 146 * See if we can disable input processing; this will 147 * not give the desired result if we are in a pipeline 148 * and someone upstream is still in line-by-line mode. 149 */ 150 tsaved = 0; 151 if (tcgetattr(0, &told) == 0) { 152 memcpy(&tnew, &told, sizeof(told)); 153 cfmakeraw(&tnew); 154 tcsetattr(0, TCSANOW, &tnew); 155 tsaved = 1; 156 } 157 /* 158 * Wait for something to become available. 159 */ 160 FD_ZERO(&ifds); 161 FD_SET(0, &ifds); 162 status = select(1, &ifds, NULL, NULL, &tv); 163 if (tsaved) 164 tcsetattr(0, TCSANOW, &told); 165 /* 166 * If there's nothing ready, return an error. 167 */ 168 if (status <= 0) 169 return(1); 170 } 171 172 status = 0; 173 startword = 1; 174 backslash = 0; 175 STARTSTACKSTR(p); 176 for (;;) { 177 if (read(0, &c, 1) != 1) { 178 status = 1; 179 break; 180 } 181 if (c == '\0') 182 continue; 183 if (backslash) { 184 backslash = 0; 185 if (c != '\n') 186 STPUTC(c, p); 187 continue; 188 } 189 if (!rflag && c == '\\') { 190 backslash++; 191 continue; 192 } 193 if (c == '\n') 194 break; 195 if (startword && *ifs == ' ' && strchr(ifs, c)) { 196 continue; 197 } 198 startword = 0; 199 if (backslash && c == '\\') { 200 if (read(0, &c, 1) != 1) { 201 status = 1; 202 break; 203 } 204 STPUTC(c, p); 205 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) { 206 STACKSTRNUL(p); 207 setvar(*ap, stackblock(), 0); 208 ap++; 209 startword = 1; 210 STARTSTACKSTR(p); 211 } else { 212 STPUTC(c, p); 213 } 214 } 215 STACKSTRNUL(p); 216 setvar(*ap, stackblock(), 0); 217 while (*++ap != NULL) 218 setvar(*ap, nullstr, 0); 219 return status; 220 } 221 222 223 224 int 225 umaskcmd(argc, argv) 226 int argc __unused; 227 char **argv; 228 { 229 char *ap; 230 int mask; 231 int i; 232 int symbolic_mode = 0; 233 234 while ((i = nextopt("S")) != '\0') { 235 symbolic_mode = 1; 236 } 237 238 INTOFF; 239 mask = umask(0); 240 umask(mask); 241 INTON; 242 243 if ((ap = *argptr) == NULL) { 244 if (symbolic_mode) { 245 char u[4], g[4], o[4]; 246 247 i = 0; 248 if ((mask & S_IRUSR) == 0) 249 u[i++] = 'r'; 250 if ((mask & S_IWUSR) == 0) 251 u[i++] = 'w'; 252 if ((mask & S_IXUSR) == 0) 253 u[i++] = 'x'; 254 u[i] = '\0'; 255 256 i = 0; 257 if ((mask & S_IRGRP) == 0) 258 g[i++] = 'r'; 259 if ((mask & S_IWGRP) == 0) 260 g[i++] = 'w'; 261 if ((mask & S_IXGRP) == 0) 262 g[i++] = 'x'; 263 g[i] = '\0'; 264 265 i = 0; 266 if ((mask & S_IROTH) == 0) 267 o[i++] = 'r'; 268 if ((mask & S_IWOTH) == 0) 269 o[i++] = 'w'; 270 if ((mask & S_IXOTH) == 0) 271 o[i++] = 'x'; 272 o[i] = '\0'; 273 274 out1fmt("u=%s,g=%s,o=%s\n", u, g, o); 275 } else { 276 out1fmt("%.4o\n", mask); 277 } 278 } else { 279 if (isdigit(*ap)) { 280 mask = 0; 281 do { 282 if (*ap >= '8' || *ap < '0') 283 error("Illegal number: %s", argv[1]); 284 mask = (mask << 3) + (*ap - '0'); 285 } while (*++ap != '\0'); 286 umask(mask); 287 } else { 288 void *set; 289 if ((set = setmode (ap)) == 0) 290 error("Illegal number: %s", ap); 291 292 mask = getmode (set, ~mask & 0777); 293 umask(~mask & 0777); 294 free(set); 295 } 296 } 297 return 0; 298 } 299 300 /* 301 * ulimit builtin 302 * 303 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and 304 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with 305 * ash by J.T. Conklin. 306 * 307 * Public domain. 308 */ 309 310 struct limits { 311 const char *name; 312 const char *units; 313 int cmd; 314 int factor; /* multiply by to get rlim_{cur,max} values */ 315 char option; 316 }; 317 318 static const struct limits limits[] = { 319 #ifdef RLIMIT_CPU 320 { "cpu time", "seconds", RLIMIT_CPU, 1, 't' }, 321 #endif 322 #ifdef RLIMIT_FSIZE 323 { "file size", "512-blocks", RLIMIT_FSIZE, 512, 'f' }, 324 #endif 325 #ifdef RLIMIT_DATA 326 { "data seg size", "kbytes", RLIMIT_DATA, 1024, 'd' }, 327 #endif 328 #ifdef RLIMIT_STACK 329 { "stack size", "kbytes", RLIMIT_STACK, 1024, 's' }, 330 #endif 331 #ifdef RLIMIT_CORE 332 { "core file size", "512-blocks", RLIMIT_CORE, 512, 'c' }, 333 #endif 334 #ifdef RLIMIT_RSS 335 { "max memory size", "kbytes", RLIMIT_RSS, 1024, 'm' }, 336 #endif 337 #ifdef RLIMIT_MEMLOCK 338 { "locked memory", "kbytes", RLIMIT_MEMLOCK, 1024, 'l' }, 339 #endif 340 #ifdef RLIMIT_NPROC 341 { "max user processes", (char *)0, RLIMIT_NPROC, 1, 'u' }, 342 #endif 343 #ifdef RLIMIT_NOFILE 344 { "open files", (char *)0, RLIMIT_NOFILE, 1, 'n' }, 345 #endif 346 #ifdef RLIMIT_VMEM 347 { "virtual mem size", "kbytes", RLIMIT_VMEM, 1024, 'v' }, 348 #endif 349 #ifdef RLIMIT_SWAP 350 { "swap limit", "kbytes", RLIMIT_SWAP, 1024, 'w' }, 351 #endif 352 #ifdef RLIMIT_SBSIZE 353 { "sbsize", "bytes", RLIMIT_SBSIZE, 1, 'b' }, 354 #endif 355 { (char *) 0, (char *)0, 0, 0, '\0' } 356 }; 357 358 int 359 ulimitcmd(argc, argv) 360 int argc __unused; 361 char **argv __unused; 362 { 363 int c; 364 quad_t val = 0; 365 enum { SOFT = 0x1, HARD = 0x2 } 366 how = SOFT | HARD; 367 const struct limits *l; 368 int set, all = 0; 369 int optc, what; 370 struct rlimit limit; 371 372 what = 'f'; 373 while ((optc = nextopt("HSatfdsmcnulb")) != '\0') 374 switch (optc) { 375 case 'H': 376 how = HARD; 377 break; 378 case 'S': 379 how = SOFT; 380 break; 381 case 'a': 382 all = 1; 383 break; 384 default: 385 what = optc; 386 } 387 388 for (l = limits; l->name && l->option != what; l++) 389 ; 390 if (!l->name) 391 error("ulimit: internal error (%c)", what); 392 393 set = *argptr ? 1 : 0; 394 if (set) { 395 char *p = *argptr; 396 397 if (all || argptr[1]) 398 error("ulimit: too many arguments"); 399 if (strcmp(p, "unlimited") == 0) 400 val = RLIM_INFINITY; 401 else { 402 val = (quad_t) 0; 403 404 while ((c = *p++) >= '0' && c <= '9') 405 { 406 val = (val * 10) + (long)(c - '0'); 407 if (val < (quad_t) 0) 408 break; 409 } 410 if (c) 411 error("ulimit: bad number"); 412 val *= l->factor; 413 } 414 } 415 if (all) { 416 for (l = limits; l->name; l++) { 417 char optbuf[40]; 418 if (getrlimit(l->cmd, &limit) < 0) 419 error("ulimit: can't get limit: %s", strerror(errno)); 420 if (how & SOFT) 421 val = limit.rlim_cur; 422 else if (how & HARD) 423 val = limit.rlim_max; 424 425 if (l->units) 426 snprintf(optbuf, sizeof(optbuf), 427 "(%s, -%c) ", l->units, l->option); 428 else 429 snprintf(optbuf, sizeof(optbuf), 430 "(-%c) ", l->option); 431 out1fmt("%-18s %18s ", l->name, optbuf); 432 if (val == RLIM_INFINITY) 433 out1fmt("unlimited\n"); 434 else 435 { 436 val /= l->factor; 437 out1fmt("%qd\n", (quad_t) val); 438 } 439 } 440 return 0; 441 } 442 443 if (getrlimit(l->cmd, &limit) < 0) 444 error("ulimit: can't get limit: %s", strerror(errno)); 445 if (set) { 446 if (how & SOFT) 447 limit.rlim_cur = val; 448 if (how & HARD) 449 limit.rlim_max = val; 450 if (setrlimit(l->cmd, &limit) < 0) 451 error("ulimit: bad limit: %s", strerror(errno)); 452 } else { 453 if (how & SOFT) 454 val = limit.rlim_cur; 455 else if (how & HARD) 456 val = limit.rlim_max; 457 458 if (val == RLIM_INFINITY) 459 out1fmt("unlimited\n"); 460 else 461 { 462 val /= l->factor; 463 out1fmt("%qd\n", (quad_t) val); 464 } 465 } 466 return 0; 467 } 468