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