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