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