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