1 1.57 kre /* $NetBSD: miscbltin.c,v 1.57 2025/07/03 03:54:40 kre Exp $ */ 2 1.13 cgd 3 1.1 cgd /*- 4 1.7 jtc * Copyright (c) 1991, 1993 5 1.7 jtc * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * This code is derived from software contributed to Berkeley by 8 1.1 cgd * Kenneth Almquist. 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.32 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 cgd * may be used to endorse or promote products derived from this software 20 1.1 cgd * without specific prior written permission. 21 1.1 cgd * 22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 cgd * SUCH DAMAGE. 33 1.1 cgd */ 34 1.1 cgd 35 1.19 christos #include <sys/cdefs.h> 36 1.1 cgd #ifndef lint 37 1.13 cgd #if 0 38 1.14 christos static char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95"; 39 1.13 cgd #else 40 1.57 kre __RCSID("$NetBSD: miscbltin.c,v 1.57 2025/07/03 03:54:40 kre Exp $"); 41 1.13 cgd #endif 42 1.1 cgd #endif /* not lint */ 43 1.1 cgd 44 1.1 cgd /* 45 1.47 andvar * Miscellaneous builtins. 46 1.1 cgd */ 47 1.1 cgd 48 1.23 christos #include <sys/param.h> /* BSD4_4 */ 49 1.55 kre #include <sys/resource.h> 50 1.8 jtc #include <sys/stat.h> 51 1.14 christos #include <sys/time.h> 52 1.55 kre #include <sys/types.h> /* quad_t */ 53 1.55 kre 54 1.9 jtc #include <ctype.h> 55 1.28 christos #include <errno.h> 56 1.55 kre #include <limits.h> 57 1.55 kre #include <stdlib.h> 58 1.55 kre #ifndef SMALL 59 1.55 kre #include <termios.h> 60 1.55 kre #endif 61 1.55 kre #include <unistd.h> 62 1.14 christos 63 1.1 cgd #include "shell.h" 64 1.57 kre #include "syntax.h" 65 1.1 cgd #include "options.h" 66 1.1 cgd #include "var.h" 67 1.55 kre #include "input.h" /* for whichprompt */ 68 1.1 cgd #include "output.h" 69 1.55 kre #include "parser.h" /* for getprompt() */ 70 1.1 cgd #include "memalloc.h" 71 1.1 cgd #include "error.h" 72 1.39 christos #include "builtins.h" 73 1.1 cgd #include "mystring.h" 74 1.45 kre #include "redir.h" /* for user_fd_limit */ 75 1.1 cgd 76 1.1 cgd /* 77 1.35 dsl * The read builtin. 78 1.47 andvar * Backslashes escape the next char unless -r is specified. 79 1.1 cgd * 80 1.1 cgd * This uses unbuffered input, which may be avoidable in some cases. 81 1.35 dsl * 82 1.35 dsl * Note that if IFS=' :' then read x y should work so that: 83 1.35 dsl * 'a b' x='a', y='b' 84 1.35 dsl * ' a b ' x='a', y='b' 85 1.35 dsl * ':b' x='', y='b' 86 1.35 dsl * ':' x='', y='' 87 1.35 dsl * '::' x='', y='' 88 1.35 dsl * ': :' x='', y='' 89 1.35 dsl * ':::' x='', y='::' 90 1.35 dsl * ':b c:' x='', y='b c:' 91 1.1 cgd */ 92 1.1 cgd 93 1.55 kre #ifndef SMALL 94 1.55 kre static int b_flag; 95 1.55 kre 96 1.55 kre static int 97 1.55 kre setrawmode(int fd, int on, int end, struct termios *t) 98 1.55 kre { 99 1.55 kre struct termios n; 100 1.55 kre 101 1.55 kre if (on) { 102 1.55 kre if (tcgetattr(fd, t) != 0) 103 1.55 kre return 0; 104 1.55 kre n = *t; 105 1.55 kre if (on == 1 && b_flag) { 106 1.55 kre n.c_cc[VEOL] = end; 107 1.55 kre } else { 108 1.55 kre cfmakeraw(&n); 109 1.55 kre n.c_iflag |= ICRNL; 110 1.55 kre n.c_oflag = t->c_oflag; 111 1.55 kre n.c_lflag |= ECHO | ISIG; 112 1.55 kre } 113 1.55 kre if (tcsetattr(fd, TCSADRAIN | TCSASOFT, &n) == 0) 114 1.55 kre return 1; 115 1.55 kre } else 116 1.55 kre (void)tcsetattr(fd, TCSADRAIN | TCSASOFT, t); 117 1.55 kre return 0; 118 1.55 kre } 119 1.55 kre 120 1.55 kre static int 121 1.55 kre is_a_pipe(int fd) 122 1.55 kre { 123 1.55 kre if (lseek(fd, 0, SEEK_CUR) == -1 && errno == ESPIPE) { 124 1.55 kre errno = 0; 125 1.55 kre return 1; 126 1.55 kre } 127 1.55 kre return 0; 128 1.55 kre } 129 1.55 kre 130 1.55 kre #define READ_BUFFER_SIZE 512 131 1.55 kre 132 1.55 kre static int 133 1.55 kre next_read_char(int fd, size_t max) 134 1.55 kre { 135 1.55 kre static char buffer[READ_BUFFER_SIZE]; 136 1.55 kre static int pos = 0, len = 0; 137 1.55 kre 138 1.55 kre if (max == 0) { 139 1.55 kre pos = len = 0; 140 1.55 kre return -1; 141 1.55 kre } 142 1.55 kre if (max == (size_t)-1) { 143 1.55 kre /* 144 1.55 kre * If possible, and necessary, rewind the file 145 1.55 kre * so unprocessed data can be read again next time 146 1.55 kre * 147 1.55 kre * If that fails, never mind (-b allows that to happen) 148 1.55 kre */ 149 1.55 kre if (b_flag && pos < len) 150 1.55 kre (void)lseek(fd, (off_t)(pos - len), SEEK_CUR); 151 1.55 kre return -1; 152 1.55 kre } 153 1.55 kre 154 1.55 kre if (b_flag == 0) { 155 1.55 kre char c; 156 1.55 kre 157 1.55 kre (void) max; 158 1.55 kre if (read(fd, &c, 1) != 1) 159 1.55 kre return -1; 160 1.55 kre return (c & 0xFF); 161 1.55 kre } 162 1.55 kre 163 1.55 kre if (pos >= len) { 164 1.55 kre pos = 0; 165 1.55 kre if (max > sizeof buffer) 166 1.55 kre max = sizeof buffer; 167 1.55 kre len = read(fd, buffer, max); 168 1.55 kre if (len <= 0) 169 1.55 kre return -1; 170 1.55 kre } 171 1.55 kre 172 1.55 kre return buffer[pos++] & 0xFF; 173 1.55 kre } 174 1.55 kre 175 1.55 kre #define READ_OPTS "bd:n:p:r" 176 1.55 kre 177 1.55 kre #else 178 1.55 kre 179 1.55 kre static inline int 180 1.55 kre next_read_char(int fd, size_t max) 181 1.55 kre { 182 1.55 kre char c; 183 1.55 kre 184 1.55 kre if (max == 0 || max == (size_t)-1) 185 1.55 kre return 0; 186 1.55 kre 187 1.55 kre if (read(fd, &c, 1) != 1) 188 1.55 kre return -1; 189 1.55 kre return (c & 0xFF); 190 1.55 kre } 191 1.55 kre 192 1.55 kre #define n_flag 0 193 1.55 kre #define maxlen 0 194 1.55 kre 195 1.55 kre #define READ_OPTS "d:p:r" 196 1.55 kre 197 1.55 kre #endif 198 1.55 kre 199 1.12 cgd int 200 1.31 christos readcmd(int argc, char **argv) 201 1.12 cgd { 202 1.1 cgd char **ap; 203 1.55 kre int c; 204 1.53 kre char end; 205 1.55 kre int r_flag; 206 1.1 cgd char *prompt; 207 1.35 dsl const char *ifs; 208 1.1 cgd char *p; 209 1.1 cgd int startword; 210 1.1 cgd int status; 211 1.1 cgd int i; 212 1.35 dsl int is_ifs; 213 1.35 dsl int saveall = 0; 214 1.55 kre int read_tty = 0; 215 1.51 kre ptrdiff_t wordlen = 0; 216 1.54 kre char *newifs = NULL; 217 1.54 kre struct stackmark mk; 218 1.1 cgd 219 1.55 kre #ifndef SMALL 220 1.55 kre struct termios ttystate; 221 1.55 kre int n_flag, maxlen; 222 1.55 kre int setraw = 0; 223 1.55 kre 224 1.55 kre b_flag = 0; 225 1.55 kre n_flag = 0; 226 1.55 kre maxlen = READ_BUFFER_SIZE - 1; 227 1.55 kre #endif 228 1.55 kre 229 1.53 kre end = '\n'; /* record delimiter */ 230 1.55 kre r_flag = 0; 231 1.1 cgd prompt = NULL; 232 1.55 kre whichprompt = 2; /* for continuation lines */ 233 1.55 kre 234 1.55 kre while ((i = nextopt(READ_OPTS)) != '\0') { 235 1.53 kre switch (i) { 236 1.53 kre case 'd': 237 1.53 kre end = *optionarg; /* even if '\0' */ 238 1.53 kre break; 239 1.53 kre case 'p': 240 1.30 christos prompt = optionarg; 241 1.53 kre break; 242 1.53 kre case 'r': 243 1.55 kre r_flag = 1; 244 1.53 kre break; 245 1.55 kre #ifndef SMALL 246 1.55 kre case 'n': 247 1.55 kre maxlen = number(optionarg); 248 1.55 kre if (maxlen > (INT_MAX >> 8) + 1) /* sanity */ 249 1.55 kre error("-n %s too large", optionarg); 250 1.55 kre n_flag = 1; 251 1.55 kre break; 252 1.55 kre case 'b': 253 1.55 kre if (!is_a_pipe(0)) 254 1.55 kre b_flag = 1; 255 1.55 kre break; 256 1.55 kre #endif 257 1.53 kre } 258 1.1 cgd } 259 1.35 dsl 260 1.52 kre if (*(ap = argptr) == NULL) 261 1.52 kre error("variable name required\n" 262 1.55 kre #ifdef SMALL 263 1.55 kre "Usage: read [-r] [-d C] [-p prompt] var..."); 264 1.55 kre #else 265 1.55 kre "Usage: read [-br] [-d C] [-n len] [-p prompt] var..."); 266 1.52 kre 267 1.57 kre while (*ap != NULL) { 268 1.57 kre if (!validname(*ap, '\0', NULL)) 269 1.57 kre error("'%s': invalid variable name", *ap); 270 1.57 kre ap++; 271 1.57 kre } 272 1.57 kre ap = argptr; 273 1.57 kre 274 1.55 kre (void)next_read_char(0, 0); /* make sure the buffer is empty */ 275 1.55 kre #endif 276 1.55 kre 277 1.55 kre if (isatty(0)) { 278 1.55 kre read_tty = 1; 279 1.55 kre if (prompt) { 280 1.55 kre out2str(prompt); 281 1.55 kre flushall(); 282 1.55 kre } 283 1.55 kre #ifndef SMALL 284 1.55 kre b_flag = 1; /* always buffer reads from ttys */ 285 1.55 kre 286 1.55 kre if (n_flag || end != '\n') 287 1.55 kre setraw = setrawmode(0, 1 + n_flag, end, &ttystate); 288 1.55 kre #endif 289 1.1 cgd } 290 1.35 dsl 291 1.1 cgd if ((ifs = bltinlookup("IFS", 1)) == NULL) 292 1.35 dsl ifs = " \t\n"; 293 1.35 dsl 294 1.54 kre setstackmark(&mk); 295 1.1 cgd status = 0; 296 1.35 dsl startword = 2; 297 1.1 cgd STARTSTACKSTR(p); 298 1.55 kre 299 1.55 kre #ifdef SMALL 300 1.55 kre for ( ; ; ) { 301 1.55 kre #else 302 1.55 kre for ( ; !n_flag || --maxlen >= 0 ; ) { 303 1.55 kre #endif 304 1.55 kre if ((c = next_read_char(0, maxlen + 1)) < 0) { 305 1.1 cgd status = 1; 306 1.1 cgd break; 307 1.1 cgd } 308 1.55 kre if (c == '\\' && c != end && !r_flag) { 309 1.55 kre #ifndef SMALL 310 1.55 kre if (n_flag && --maxlen < 0) 311 1.55 kre break; 312 1.55 kre #endif 313 1.55 kre if ((c = next_read_char(0, maxlen + 1)) < 0) { 314 1.35 dsl status = 1; 315 1.35 dsl break; 316 1.35 dsl } 317 1.53 kre if (c != '\n') /* \ \n is always just removed */ 318 1.51 kre goto wdch; 319 1.55 kre if (read_tty) 320 1.55 kre out2str(getprompt(NULL)); 321 1.1 cgd continue; 322 1.1 cgd } 323 1.53 kre if (c == end) 324 1.1 cgd break; 325 1.53 kre if (c == '\0') 326 1.53 kre continue; 327 1.35 dsl if (strchr(ifs, c)) 328 1.35 dsl is_ifs = strchr(" \t\n", c) ? 1 : 2; 329 1.35 dsl else 330 1.35 dsl is_ifs = 0; 331 1.35 dsl 332 1.35 dsl if (startword != 0) { 333 1.35 dsl if (is_ifs == 1) { 334 1.35 dsl /* Ignore leading IFS whitespace */ 335 1.35 dsl if (saveall) 336 1.35 dsl STPUTC(c, p); 337 1.35 dsl continue; 338 1.35 dsl } 339 1.35 dsl if (is_ifs == 2 && startword == 1) { 340 1.35 dsl /* Only one non-whitespace IFS per word */ 341 1.35 dsl startword = 2; 342 1.35 dsl if (saveall) 343 1.35 dsl STPUTC(c, p); 344 1.35 dsl continue; 345 1.35 dsl } 346 1.35 dsl } 347 1.35 dsl 348 1.35 dsl if (is_ifs == 0) { 349 1.51 kre wdch:; 350 1.55 kre if (c == '\0') /* always ignore attempts to input \0 */ 351 1.53 kre continue; 352 1.35 dsl /* append this character to the current variable */ 353 1.35 dsl startword = 0; 354 1.35 dsl if (saveall) 355 1.35 dsl /* Not just a spare terminator */ 356 1.35 dsl saveall++; 357 1.35 dsl STPUTC(c, p); 358 1.51 kre wordlen = p - stackblock(); 359 1.1 cgd continue; 360 1.1 cgd } 361 1.35 dsl 362 1.35 dsl /* end of variable... */ 363 1.35 dsl startword = is_ifs; 364 1.35 dsl 365 1.35 dsl if (ap[1] == NULL) { 366 1.35 dsl /* Last variable needs all IFS chars */ 367 1.35 dsl saveall++; 368 1.1 cgd STPUTC(c, p); 369 1.35 dsl continue; 370 1.1 cgd } 371 1.35 dsl 372 1.54 kre if (equal(*ap, "IFS")) { 373 1.54 kre /* 374 1.54 kre * we must not alter the value of IFS, as our 375 1.54 kre * local "ifs" var is (perhaps) pointing at it, 376 1.54 kre * at best we would be using data after free() 377 1.54 kre * the next time we reference ifs - but that mem 378 1.54 kre * may have been reused for something different. 379 1.54 kre * 380 1.54 kre * note that this might occur several times 381 1.54 kre */ 382 1.54 kre STPUTC('\0', p); 383 1.54 kre newifs = grabstackstr(p); 384 1.54 kre } else { 385 1.54 kre STACKSTRNUL(p); 386 1.54 kre setvar(*ap, stackblock(), 0); 387 1.54 kre } 388 1.35 dsl ap++; 389 1.35 dsl STARTSTACKSTR(p); 390 1.51 kre wordlen = 0; 391 1.1 cgd } 392 1.1 cgd STACKSTRNUL(p); 393 1.35 dsl 394 1.55 kre #ifndef SMALL 395 1.55 kre (void)next_read_char(0, (size_t)-1); /* attempt to seek back */ 396 1.55 kre if (setraw) 397 1.55 kre setrawmode(0, 0, end, &ttystate); 398 1.55 kre #endif 399 1.55 kre 400 1.55 kre 401 1.35 dsl /* Remove trailing IFS chars */ 402 1.51 kre for (; stackblock() + wordlen <= --p; *p = 0) { 403 1.35 dsl if (!strchr(ifs, *p)) 404 1.35 dsl break; 405 1.35 dsl if (strchr(" \t\n", *p)) 406 1.35 dsl /* Always remove whitespace */ 407 1.35 dsl continue; 408 1.35 dsl if (saveall > 1) 409 1.35 dsl /* Don't remove non-whitespace unless it was naked */ 410 1.35 dsl break; 411 1.35 dsl } 412 1.54 kre 413 1.54 kre /* 414 1.54 kre * If IFS was one of the variables named, we can finally set it now 415 1.54 kre * (no further references to ifs will be made) 416 1.54 kre */ 417 1.54 kre if (newifs != NULL) 418 1.54 kre setvar("IFS", newifs, 0); 419 1.54 kre 420 1.54 kre /* 421 1.54 kre * Now we can assign to the final variable (which might 422 1.54 kre * also be IFS, hence the ordering here) 423 1.54 kre */ 424 1.1 cgd setvar(*ap, stackblock(), 0); 425 1.35 dsl 426 1.35 dsl /* Set any remaining args to "" */ 427 1.1 cgd while (*++ap != NULL) 428 1.1 cgd setvar(*ap, nullstr, 0); 429 1.54 kre 430 1.54 kre popstackmark(&mk); 431 1.1 cgd return status; 432 1.1 cgd } 433 1.1 cgd 434 1.1 cgd 435 1.1 cgd 436 1.12 cgd int 437 1.31 christos umaskcmd(int argc, char **argv) 438 1.12 cgd { 439 1.8 jtc char *ap; 440 1.49 kre mode_t mask; 441 1.1 cgd int i; 442 1.8 jtc int symbolic_mode = 0; 443 1.8 jtc 444 1.8 jtc while ((i = nextopt("S")) != '\0') { 445 1.8 jtc symbolic_mode = 1; 446 1.8 jtc } 447 1.1 cgd 448 1.8 jtc INTOFF; 449 1.8 jtc mask = umask(0); 450 1.8 jtc umask(mask); 451 1.8 jtc INTON; 452 1.8 jtc 453 1.8 jtc if ((ap = *argptr) == NULL) { 454 1.8 jtc if (symbolic_mode) { 455 1.8 jtc char u[4], g[4], o[4]; 456 1.8 jtc 457 1.8 jtc i = 0; 458 1.8 jtc if ((mask & S_IRUSR) == 0) 459 1.8 jtc u[i++] = 'r'; 460 1.8 jtc if ((mask & S_IWUSR) == 0) 461 1.8 jtc u[i++] = 'w'; 462 1.8 jtc if ((mask & S_IXUSR) == 0) 463 1.8 jtc u[i++] = 'x'; 464 1.8 jtc u[i] = '\0'; 465 1.8 jtc 466 1.8 jtc i = 0; 467 1.8 jtc if ((mask & S_IRGRP) == 0) 468 1.8 jtc g[i++] = 'r'; 469 1.8 jtc if ((mask & S_IWGRP) == 0) 470 1.8 jtc g[i++] = 'w'; 471 1.8 jtc if ((mask & S_IXGRP) == 0) 472 1.8 jtc g[i++] = 'x'; 473 1.8 jtc g[i] = '\0'; 474 1.8 jtc 475 1.8 jtc i = 0; 476 1.8 jtc if ((mask & S_IROTH) == 0) 477 1.8 jtc o[i++] = 'r'; 478 1.8 jtc if ((mask & S_IWOTH) == 0) 479 1.8 jtc o[i++] = 'w'; 480 1.8 jtc if ((mask & S_IXOTH) == 0) 481 1.8 jtc o[i++] = 'x'; 482 1.8 jtc o[i] = '\0'; 483 1.8 jtc 484 1.8 jtc out1fmt("u=%s,g=%s,o=%s\n", u, g, o); 485 1.8 jtc } else { 486 1.8 jtc out1fmt("%.4o\n", mask); 487 1.8 jtc } 488 1.1 cgd } else { 489 1.57 kre if (is_digit(*ap)) { 490 1.49 kre int range = 0; 491 1.49 kre 492 1.8 jtc mask = 0; 493 1.8 jtc do { 494 1.8 jtc if (*ap >= '8' || *ap < '0') 495 1.48 kre error("Not a valid octal number: '%s'", 496 1.49 kre *argptr); 497 1.8 jtc mask = (mask << 3) + (*ap - '0'); 498 1.49 kre if (mask & ~07777) 499 1.49 kre range = 1; 500 1.8 jtc } while (*++ap != '\0'); 501 1.49 kre if (range) 502 1.49 kre error("Mask constant '%s' out of range", *argptr); 503 1.8 jtc umask(mask); 504 1.8 jtc } else { 505 1.16 christos void *set; 506 1.8 jtc 507 1.26 itohy INTOFF; 508 1.26 itohy if ((set = setmode(ap)) != 0) { 509 1.26 itohy mask = getmode(set, ~mask & 0777); 510 1.26 itohy ckfree(set); 511 1.26 itohy } 512 1.26 itohy INTON; 513 1.26 itohy if (!set) 514 1.36 christos error("Cannot set mode `%s' (%s)", ap, 515 1.36 christos strerror(errno)); 516 1.26 itohy 517 1.8 jtc umask(~mask & 0777); 518 1.14 christos } 519 1.14 christos } 520 1.46 kre flushout(out1); 521 1.46 kre if (io_err(out1)) { 522 1.46 kre out2str("umask: I/O error\n"); 523 1.46 kre return 1; 524 1.46 kre } 525 1.14 christos return 0; 526 1.14 christos } 527 1.14 christos 528 1.14 christos /* 529 1.14 christos * ulimit builtin 530 1.14 christos * 531 1.14 christos * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and 532 1.14 christos * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with 533 1.14 christos * ash by J.T. Conklin. 534 1.14 christos * 535 1.14 christos * Public domain. 536 1.14 christos */ 537 1.14 christos 538 1.14 christos struct limits { 539 1.14 christos const char *name; 540 1.40 christos const char *unit; 541 1.14 christos char option; 542 1.50 kre int8_t cmd; /* all RLIMIT_xxx are <= 127 */ 543 1.50 kre unsigned short factor; /* multiply by to get rlim_{cur,max} values */ 544 1.14 christos }; 545 1.14 christos 546 1.50 kre #define OPTSTRING_BASE "HSa" 547 1.50 kre 548 1.14 christos static const struct limits limits[] = { 549 1.14 christos #ifdef RLIMIT_CPU 550 1.50 kre { "time", "seconds", 't', RLIMIT_CPU, 1 }, 551 1.50 kre #define OPTSTRING_t OPTSTRING_BASE "t" 552 1.50 kre #else 553 1.50 kre #define OPTSTRING_t OPTSTRING_BASE 554 1.14 christos #endif 555 1.14 christos #ifdef RLIMIT_FSIZE 556 1.50 kre { "file", "blocks", 'f', RLIMIT_FSIZE, 512 }, 557 1.50 kre #define OPTSTRING_f OPTSTRING_t "f" 558 1.50 kre #else 559 1.50 kre #define OPTSTRING_f OPTSTRING_t 560 1.14 christos #endif 561 1.14 christos #ifdef RLIMIT_DATA 562 1.50 kre { "data", "kbytes", 'd', RLIMIT_DATA, 1024 }, 563 1.50 kre #define OPTSTRING_d OPTSTRING_f "d" 564 1.50 kre #else 565 1.50 kre #define OPTSTRING_d OPTSTRING_f 566 1.14 christos #endif 567 1.14 christos #ifdef RLIMIT_STACK 568 1.50 kre { "stack", "kbytes", 's', RLIMIT_STACK, 1024 }, 569 1.50 kre #define OPTSTRING_s OPTSTRING_d "s" 570 1.50 kre #else 571 1.50 kre #define OPTSTRING_s OPTSTRING_d 572 1.14 christos #endif 573 1.44 gson #ifdef RLIMIT_CORE 574 1.50 kre { "coredump", "blocks", 'c', RLIMIT_CORE, 512 }, 575 1.50 kre #define OPTSTRING_c OPTSTRING_s "c" 576 1.50 kre #else 577 1.50 kre #define OPTSTRING_c OPTSTRING_s 578 1.14 christos #endif 579 1.14 christos #ifdef RLIMIT_RSS 580 1.50 kre { "memory", "kbytes", 'm', RLIMIT_RSS, 1024 }, 581 1.50 kre #define OPTSTRING_m OPTSTRING_c "m" 582 1.50 kre #else 583 1.50 kre #define OPTSTRING_m OPTSTRING_c 584 1.14 christos #endif 585 1.14 christos #ifdef RLIMIT_MEMLOCK 586 1.50 kre { "locked memory","kbytes", 'l', RLIMIT_MEMLOCK, 1024 }, 587 1.50 kre #define OPTSTRING_l OPTSTRING_m "l" 588 1.50 kre #else 589 1.50 kre #define OPTSTRING_l OPTSTRING_m 590 1.14 christos #endif 591 1.41 christos #ifdef RLIMIT_NTHR 592 1.50 kre { "thread", "threads", 'r', RLIMIT_NTHR, 1 }, 593 1.50 kre #define OPTSTRING_r OPTSTRING_l "r" 594 1.50 kre #else 595 1.50 kre #define OPTSTRING_r OPTSTRING_l 596 1.41 christos #endif 597 1.14 christos #ifdef RLIMIT_NPROC 598 1.50 kre { "process", "processes", 'p', RLIMIT_NPROC, 1 }, 599 1.50 kre #define OPTSTRING_p OPTSTRING_r "p" 600 1.50 kre #else 601 1.50 kre #define OPTSTRING_p OPTSTRING_r 602 1.14 christos #endif 603 1.14 christos #ifdef RLIMIT_NOFILE 604 1.50 kre { "nofiles", "descriptors", 'n', RLIMIT_NOFILE, 1 }, 605 1.50 kre #define OPTSTRING_n OPTSTRING_p "n" 606 1.50 kre #else 607 1.50 kre #define OPTSTRING_n OPTSTRING_p 608 1.14 christos #endif 609 1.14 christos #ifdef RLIMIT_VMEM 610 1.50 kre { "vmemory", "kbytes", 'v', RLIMIT_VMEM, 1024 }, 611 1.50 kre #define OPTSTRING_v OPTSTRING_n "v" 612 1.50 kre #else 613 1.50 kre #define OPTSTRING_v OPTSTRING_n 614 1.14 christos #endif 615 1.14 christos #ifdef RLIMIT_SWAP 616 1.50 kre { "swap", "kbytes", 'w', RLIMIT_SWAP, 1024 }, 617 1.50 kre #define OPTSTRING_w OPTSTRING_v "w" 618 1.50 kre #else 619 1.50 kre #define OPTSTRING_w OPTSTRING_v 620 1.14 christos #endif 621 1.33 christos #ifdef RLIMIT_SBSIZE 622 1.50 kre { "sbsize", "bytes", 'b', RLIMIT_SBSIZE, 1 }, 623 1.50 kre #define OPTSTRING_b OPTSTRING_w "b" 624 1.50 kre #else 625 1.50 kre #define OPTSTRING_b OPTSTRING_w 626 1.33 christos #endif 627 1.50 kre { NULL, NULL, '\0', 0, 0 } 628 1.14 christos }; 629 1.50 kre #define OPTSTRING OPTSTRING_b 630 1.14 christos 631 1.14 christos int 632 1.31 christos ulimitcmd(int argc, char **argv) 633 1.14 christos { 634 1.17 tls int c; 635 1.19 christos rlim_t val = 0; 636 1.14 christos enum { SOFT = 0x1, HARD = 0x2 } 637 1.45 kre how = 0, which; 638 1.14 christos const struct limits *l; 639 1.14 christos int set, all = 0; 640 1.14 christos int optc, what; 641 1.14 christos struct rlimit limit; 642 1.14 christos 643 1.14 christos what = 'f'; 644 1.50 kre while ((optc = nextopt(OPTSTRING)) != '\0') 645 1.14 christos switch (optc) { 646 1.14 christos case 'H': 647 1.45 kre how |= HARD; 648 1.14 christos break; 649 1.14 christos case 'S': 650 1.45 kre how |= SOFT; 651 1.14 christos break; 652 1.14 christos case 'a': 653 1.14 christos all = 1; 654 1.14 christos break; 655 1.14 christos default: 656 1.14 christos what = optc; 657 1.14 christos } 658 1.14 christos 659 1.14 christos for (l = limits; l->name && l->option != what; l++) 660 1.14 christos ; 661 1.14 christos if (!l->name) 662 1.28 christos error("internal error (%c)", what); 663 1.14 christos 664 1.14 christos set = *argptr ? 1 : 0; 665 1.14 christos if (set) { 666 1.14 christos char *p = *argptr; 667 1.14 christos 668 1.14 christos if (all || argptr[1]) 669 1.28 christos error("too many arguments"); 670 1.45 kre if (how == 0) 671 1.45 kre how = HARD | SOFT; 672 1.45 kre 673 1.14 christos if (strcmp(p, "unlimited") == 0) 674 1.14 christos val = RLIM_INFINITY; 675 1.14 christos else { 676 1.15 jtc val = (rlim_t) 0; 677 1.14 christos 678 1.45 kre while ((c = *p++) >= '0' && c <= '9') { 679 1.45 kre if (val >= RLIM_INFINITY/10) 680 1.50 kre error("%s: value overflow", *argptr); 681 1.45 kre val = (val * 10); 682 1.45 kre if (val >= RLIM_INFINITY - (long)(c - '0')) 683 1.50 kre error("%s: value overflow", *argptr); 684 1.45 kre val += (long)(c - '0'); 685 1.45 kre } 686 1.14 christos if (c) 687 1.50 kre error("%s: bad number", *argptr); 688 1.45 kre if (val > RLIM_INFINITY / l->factor) 689 1.50 kre error("%s: value overflow", *argptr); 690 1.14 christos val *= l->factor; 691 1.14 christos } 692 1.45 kre } else if (how == 0) 693 1.45 kre how = SOFT; 694 1.45 kre 695 1.14 christos if (all) { 696 1.14 christos for (l = limits; l->name; l++) { 697 1.14 christos getrlimit(l->cmd, &limit); 698 1.45 kre out1fmt("%-13s (-%c %-11s) ", l->name, l->option, 699 1.45 kre l->unit); 700 1.14 christos 701 1.45 kre which = how; 702 1.45 kre while (which != 0) { 703 1.45 kre if (which & SOFT) { 704 1.45 kre val = limit.rlim_cur; 705 1.45 kre which &= ~SOFT; 706 1.45 kre } else if (which & HARD) { 707 1.45 kre val = limit.rlim_max; 708 1.45 kre which &= ~HARD; 709 1.45 kre } 710 1.45 kre 711 1.45 kre if (val == RLIM_INFINITY) 712 1.45 kre out1fmt("unlimited"); 713 1.45 kre else { 714 1.45 kre val /= l->factor; 715 1.18 christos #ifdef BSD4_4 716 1.45 kre out1fmt("%9lld", (long long) val); 717 1.18 christos #else 718 1.45 kre out1fmt("%9ld", (long) val); 719 1.18 christos #endif 720 1.45 kre } 721 1.45 kre out1fmt("%c", which ? '\t' : '\n'); 722 1.14 christos } 723 1.14 christos } 724 1.46 kre goto done; 725 1.14 christos } 726 1.14 christos 727 1.43 christos if (getrlimit(l->cmd, &limit) == -1) 728 1.43 christos error("error getting limit (%s)", strerror(errno)); 729 1.14 christos if (set) { 730 1.28 christos if (how & HARD) 731 1.28 christos limit.rlim_max = val; 732 1.14 christos if (how & SOFT) 733 1.14 christos limit.rlim_cur = val; 734 1.14 christos if (setrlimit(l->cmd, &limit) < 0) 735 1.28 christos error("error setting limit (%s)", strerror(errno)); 736 1.45 kre if (l->cmd == RLIMIT_NOFILE) 737 1.45 kre user_fd_limit = sysconf(_SC_OPEN_MAX); 738 1.14 christos } else { 739 1.14 christos if (how & SOFT) 740 1.14 christos val = limit.rlim_cur; 741 1.14 christos else if (how & HARD) 742 1.14 christos val = limit.rlim_max; 743 1.14 christos 744 1.14 christos if (val == RLIM_INFINITY) 745 1.14 christos out1fmt("unlimited\n"); 746 1.14 christos else 747 1.14 christos { 748 1.14 christos val /= l->factor; 749 1.18 christos #ifdef BSD4_4 750 1.29 lukem out1fmt("%lld\n", (long long) val); 751 1.18 christos #else 752 1.18 christos out1fmt("%ld\n", (long) val); 753 1.18 christos #endif 754 1.8 jtc } 755 1.1 cgd } 756 1.46 kre done:; 757 1.46 kre flushout(out1); 758 1.46 kre if (io_err(out1)) { 759 1.46 kre out2str("ulimit: I/O error (stdout)\n"); 760 1.46 kre return 1; 761 1.46 kre } 762 1.1 cgd return 0; 763 1.1 cgd } 764