1/*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 1997-2005 5 * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Kenneth Almquist. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35/* 36 * Miscelaneous builtins. 37 */ 38 39#include <sys/types.h> /* quad_t */ 40#include <sys/param.h> /* BSD4_4 */ 41#include <sys/stat.h> 42#include <sys/time.h> 43#include <unistd.h> 44#include <stdlib.h> 45#include <ctype.h> 46#include <inttypes.h> 47 48#include "shell.h" 49#include "options.h" 50#include "var.h" 51#include "output.h" 52#include "memalloc.h" 53#include "error.h" 54#include "miscbltin.h" 55#include "mystring.h" 56#include "main.h" 57#include "expand.h" 58#include "parser.h" 59#include "trap.h" 60 61#undef rflag 62 63 64/** handle one line of the read command. 65 * more fields than variables -> remainder shall be part of last variable. 66 * less fields than variables -> remaining variables unset. 67 * 68 * @param line complete line of input 69 * @param ac argument count 70 * @param ap argument (variable) list 71 * @param len length of line including trailing '\0' 72 */ 73static void 74readcmd_handle_line(char *s, int ac, char **ap) 75{ 76 struct arglist arglist; 77 struct strlist *sl; 78 79 s = grabstackstr(s); 80 81 arglist.lastp = &arglist.list; 82 83 ifsbreakup(s, ac, &arglist); 84 *arglist.lastp = NULL; 85 ifsfree(); 86 87 sl = arglist.list; 88 89 do { 90 if (!sl) { 91 /* nullify remaining arguments */ 92 do { 93 setvar(*ap, nullstr, 0); 94 } while (*++ap); 95 96 return; 97 } 98 99 /* set variable to field */ 100 rmescapes(sl->text); 101 setvar(*ap, sl->text, 0); 102 sl = sl->next; 103 } while (*++ap); 104} 105 106/* 107 * The read builtin. The -e option causes backslashes to escape the 108 * following character. The -p option followed by an argument prompts 109 * with the argument. 110 * 111 * This uses unbuffered input, which may be avoidable in some cases. 112 */ 113 114int 115readcmd(int argc, char **argv) 116{ 117 char **ap; 118 char c; 119 int rflag; 120 char *prompt; 121 char *p; 122 int startloc; 123 int newloc; 124 int status; 125 int i; 126 127 rflag = 0; 128 prompt = NULL; 129 while ((i = nextopt("p:r")) != '\0') { 130 if (i == 'p') 131 prompt = optionarg; 132 else 133 rflag = 1; 134 } 135 if (prompt && isatty(0)) { 136 out2str(prompt); 137#ifdef FLUSHERR 138 flushall(); 139#endif 140 } 141 if (*(ap = argptr) == NULL) 142 sh_error("arg count"); 143 144 status = 0; 145 STARTSTACKSTR(p); 146 147 goto start; 148 149 for (;;) { 150 switch (read(0, &c, 1)) { 151 case 1: 152 break; 153 default: 154 if (errno == EINTR && !pendingsigs) 155 continue; 156 /* fall through */ 157 case 0: 158 status = 1; 159 goto out; 160 } 161 if (c == '\0') 162 continue; 163 if (newloc >= startloc) { 164 if (c == '\n') 165 goto resetbs; 166 goto put; 167 } 168 if (!rflag && c == '\\') { 169 newloc = p - (char *)stackblock(); 170 continue; 171 } 172 if (c == '\n') 173 break; 174put: 175 CHECKSTRSPACE(2, p); 176 if (strchr(qchars, c)) 177 USTPUTC(CTLESC, p); 178 USTPUTC(c, p); 179 180 if (newloc >= startloc) { 181resetbs: 182 recordregion(startloc, newloc, 0); 183start: 184 startloc = p - (char *)stackblock(); 185 newloc = startloc - 1; 186 } 187 } 188out: 189 recordregion(startloc, p - (char *)stackblock(), 0); 190 STACKSTRNUL(p); 191 readcmd_handle_line(p + 1, argc - (ap - argv), ap); 192 return status; 193} 194 195 196 197/* 198 * umask builtin 199 * 200 * This code was ripped from pdksh 5.2.14 and hacked for use with 201 * dash by Herbert Xu. 202 * 203 * Public domain. 204 */ 205 206int 207umaskcmd(int argc, char **argv) 208{ 209 char *ap; 210 int mask; 211 int i; 212 int symbolic_mode = 0; 213 214 while ((i = nextopt("S")) != '\0') { 215 symbolic_mode = 1; 216 } 217 218 INTOFF; 219 mask = umask(0); 220 umask(mask); 221 INTON; 222 223 if ((ap = *argptr) == NULL) { 224 if (symbolic_mode) { 225 char buf[18]; 226 int j; 227 228 mask = ~mask; 229 ap = buf; 230 for (i = 0; i < 3; i++) { 231 *ap++ = "ugo"[i]; 232 *ap++ = '='; 233 for (j = 0; j < 3; j++) 234 if (mask & (1 << (8 - (3*i + j)))) 235 *ap++ = "rwx"[j]; 236 *ap++ = ','; 237 } 238 ap[-1] = '\0'; 239 out1fmt("%s\n", buf); 240 } else { 241 out1fmt("%.4o\n", mask); 242 } 243 } else { 244 int new_mask; 245 246 if (isdigit((unsigned char) *ap)) { 247 new_mask = 0; 248 do { 249 if (*ap >= '8' || *ap < '0') 250 sh_error(illnum, *argptr); 251 new_mask = (new_mask << 3) + (*ap - '0'); 252 } while (*++ap != '\0'); 253 } else { 254 int positions, new_val; 255 char op; 256 257 mask = ~mask; 258 new_mask = mask; 259 positions = 0; 260 while (*ap) { 261 while (*ap && strchr("augo", *ap)) 262 switch (*ap++) { 263 case 'a': positions |= 0111; break; 264 case 'u': positions |= 0100; break; 265 case 'g': positions |= 0010; break; 266 case 'o': positions |= 0001; break; 267 } 268 if (!positions) 269 positions = 0111; /* default is a */ 270 if (!strchr("=+-", op = *ap)) 271 break; 272 ap++; 273 new_val = 0; 274 while (*ap && strchr("rwxugoXs", *ap)) 275 switch (*ap++) { 276 case 'r': new_val |= 04; break; 277 case 'w': new_val |= 02; break; 278 case 'x': new_val |= 01; break; 279 case 'u': new_val |= mask >> 6; 280 break; 281 case 'g': new_val |= mask >> 3; 282 break; 283 case 'o': new_val |= mask >> 0; 284 break; 285 case 'X': if (mask & 0111) 286 new_val |= 01; 287 break; 288 case 's': /* ignored */ 289 break; 290 } 291 new_val = (new_val & 07) * positions; 292 switch (op) { 293 case '-': 294 new_mask &= ~new_val; 295 break; 296 case '=': 297 new_mask = new_val 298 | (new_mask & ~(positions * 07)); 299 break; 300 case '+': 301 new_mask |= new_val; 302 } 303 if (*ap == ',') { 304 positions = 0; 305 ap++; 306 } else if (!strchr("=+-", *ap)) 307 break; 308 } 309 if (*ap) { 310 sh_error("Illegal mode: %s", *argptr); 311 return 1; 312 } 313 new_mask = ~new_mask; 314 } 315 umask(new_mask); 316 } 317 return 0; 318} 319 320#ifdef HAVE_GETRLIMIT 321/* 322 * ulimit builtin 323 * 324 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and 325 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with 326 * ash by J.T. Conklin. 327 * 328 * Public domain. 329 */ 330 331struct limits { 332 const char *name; 333 int cmd; 334 int factor; /* multiply by to get rlim_{cur,max} values */ 335 char option; 336}; 337 338static const struct limits limits[] = { 339#ifdef RLIMIT_CPU 340 { "time(seconds)", RLIMIT_CPU, 1, 't' }, 341#endif 342#ifdef RLIMIT_FSIZE 343 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' }, 344#endif 345#ifdef RLIMIT_DATA 346 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' }, 347#endif 348#ifdef RLIMIT_STACK 349 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' }, 350#endif 351#ifdef RLIMIT_CORE 352 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' }, 353#endif 354#ifdef RLIMIT_RSS 355 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' }, 356#endif 357#ifdef RLIMIT_MEMLOCK 358 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' }, 359#endif 360#ifdef RLIMIT_NPROC 361 { "process", RLIMIT_NPROC, 1, 'p' }, 362#endif 363#ifdef RLIMIT_NOFILE 364 { "nofiles", RLIMIT_NOFILE, 1, 'n' }, 365#endif 366#ifdef RLIMIT_AS 367 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' }, 368#endif 369#ifdef RLIMIT_LOCKS 370 { "locks", RLIMIT_LOCKS, 1, 'w' }, 371#endif 372#ifdef RLIMIT_RTPRIO 373 { "rtprio", RLIMIT_RTPRIO, 1, 'r' }, 374#endif 375 { (char *) 0, 0, 0, '\0' } 376}; 377 378enum limtype { SOFT = 0x1, HARD = 0x2 }; 379 380static void printlim(enum limtype how, const struct rlimit *limit, 381 const struct limits *l) 382{ 383 rlim_t val; 384 385 val = limit->rlim_max; 386 if (how & SOFT) 387 val = limit->rlim_cur; 388 389 if (val == RLIM_INFINITY) 390 out1fmt("unlimited\n"); 391 else { 392 val /= l->factor; 393 out1fmt("%" PRIdMAX "\n", (intmax_t) val); 394 } 395} 396 397int 398ulimitcmd(int argc, char **argv) 399{ 400 int c; 401 rlim_t val = 0; 402 enum limtype how = SOFT | HARD; 403 const struct limits *l; 404 int set, all = 0; 405 int optc, what; 406 struct rlimit limit; 407 408 what = 'f'; 409 while ((optc = nextopt("HSa" 410#ifdef RLIMIT_CPU 411 "t" 412#endif 413#ifdef RLIMIT_FSIZE 414 "f" 415#endif 416#ifdef RLIMIT_DATA 417 "d" 418#endif 419#ifdef RLIMIT_STACK 420 "s" 421#endif 422#ifdef RLIMIT_CORE 423 "c" 424#endif 425#ifdef RLIMIT_RSS 426 "m" 427#endif 428#ifdef RLIMIT_MEMLOCK 429 "l" 430#endif 431#ifdef RLIMIT_NPROC 432 "p" 433#endif 434#ifdef RLIMIT_NOFILE 435 "n" 436#endif 437#ifdef RLIMIT_AS 438 "v" 439#endif 440#ifdef RLIMIT_LOCKS 441 "w" 442#endif 443 )) != '\0') 444 switch (optc) { 445 case 'H': 446 how = HARD; 447 break; 448 case 'S': 449 how = SOFT; 450 break; 451 case 'a': 452 all = 1; 453 break; 454 default: 455 what = optc; 456 } 457 458 for (l = limits; l->option != what; l++) 459 ; 460 461 set = *argptr ? 1 : 0; 462 if (set) { 463 char *p = *argptr; 464 465 if (all || argptr[1]) 466 sh_error("too many arguments"); 467 if (strcmp(p, "unlimited") == 0) 468 val = RLIM_INFINITY; 469 else { 470 val = (rlim_t) 0; 471 472 while ((c = *p++) >= '0' && c <= '9') 473 { 474 val = (val * 10) + (long)(c - '0'); 475 if (val < (rlim_t) 0) 476 break; 477 } 478 if (c) 479 sh_error("bad number"); 480 val *= l->factor; 481 } 482 } 483 if (all) { 484 for (l = limits; l->name; l++) { 485 getrlimit(l->cmd, &limit); 486 out1fmt("%-20s ", l->name); 487 printlim(how, &limit, l); 488 } 489 return 0; 490 } 491 492 getrlimit(l->cmd, &limit); 493 if (set) { 494 if (how & HARD) 495 limit.rlim_max = val; 496 if (how & SOFT) 497 limit.rlim_cur = val; 498 if (setrlimit(l->cmd, &limit) < 0) 499 sh_error("error setting limit (%s)", strerror(errno)); 500 } else { 501 printlim(how, &limit, l); 502 } 503 return 0; 504} 505#endif 506