miscbltin.c revision 1.29 1 /* $NetBSD: miscbltin.c,v 1.29 2001/01/04 15:39:51 lukem 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.29 2001/01/04 15:39:51 lukem 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 extern char **argptr; /* argument list for builtin command */
74
75
76 /*
77 * The read builtin. The -e option causes backslashes to escape the
78 * following character.
79 *
80 * This uses unbuffered input, which may be avoidable in some cases.
81 */
82
83 int
84 readcmd(argc, argv)
85 int argc;
86 char **argv;
87 {
88 char **ap;
89 int backslash;
90 char c;
91 int rflag;
92 char *prompt;
93 char *ifs;
94 char *p;
95 int startword;
96 int status;
97 int i;
98
99 rflag = 0;
100 prompt = NULL;
101 while ((i = nextopt("p:r")) != '\0') {
102 if (i == 'p')
103 prompt = optarg;
104 else
105 rflag = 1;
106 }
107 if (prompt && isatty(0)) {
108 out2str(prompt);
109 flushall();
110 }
111 if (*(ap = argptr) == NULL)
112 error("arg count");
113 if ((ifs = bltinlookup("IFS", 1)) == NULL)
114 ifs = nullstr;
115 status = 0;
116 startword = 1;
117 backslash = 0;
118 STARTSTACKSTR(p);
119 for (;;) {
120 if (read(0, &c, 1) != 1) {
121 status = 1;
122 break;
123 }
124 if (c == '\0')
125 continue;
126 if (backslash) {
127 backslash = 0;
128 if (c != '\n')
129 STPUTC(c, p);
130 continue;
131 }
132 if (!rflag && c == '\\') {
133 backslash++;
134 continue;
135 }
136 if (c == '\n')
137 break;
138 if (startword && *ifs == ' ' && strchr(ifs, c)) {
139 continue;
140 }
141 startword = 0;
142 if (backslash && c == '\\') {
143 if (read(0, &c, 1) != 1) {
144 status = 1;
145 break;
146 }
147 STPUTC(c, p);
148 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
149 STACKSTRNUL(p);
150 setvar(*ap, stackblock(), 0);
151 ap++;
152 startword = 1;
153 STARTSTACKSTR(p);
154 } else {
155 STPUTC(c, p);
156 }
157 }
158 STACKSTRNUL(p);
159 /* Remove trailing blanks */
160 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
161 *p = '\0';
162 setvar(*ap, stackblock(), 0);
163 while (*++ap != NULL)
164 setvar(*ap, nullstr, 0);
165 return status;
166 }
167
168
169
170 int
171 umaskcmd(argc, argv)
172 int argc;
173 char **argv;
174 {
175 char *ap;
176 int mask;
177 int i;
178 int symbolic_mode = 0;
179
180 while ((i = nextopt("S")) != '\0') {
181 symbolic_mode = 1;
182 }
183
184 INTOFF;
185 mask = umask(0);
186 umask(mask);
187 INTON;
188
189 if ((ap = *argptr) == NULL) {
190 if (symbolic_mode) {
191 char u[4], g[4], o[4];
192
193 i = 0;
194 if ((mask & S_IRUSR) == 0)
195 u[i++] = 'r';
196 if ((mask & S_IWUSR) == 0)
197 u[i++] = 'w';
198 if ((mask & S_IXUSR) == 0)
199 u[i++] = 'x';
200 u[i] = '\0';
201
202 i = 0;
203 if ((mask & S_IRGRP) == 0)
204 g[i++] = 'r';
205 if ((mask & S_IWGRP) == 0)
206 g[i++] = 'w';
207 if ((mask & S_IXGRP) == 0)
208 g[i++] = 'x';
209 g[i] = '\0';
210
211 i = 0;
212 if ((mask & S_IROTH) == 0)
213 o[i++] = 'r';
214 if ((mask & S_IWOTH) == 0)
215 o[i++] = 'w';
216 if ((mask & S_IXOTH) == 0)
217 o[i++] = 'x';
218 o[i] = '\0';
219
220 out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
221 } else {
222 out1fmt("%.4o\n", mask);
223 }
224 } else {
225 if (isdigit((unsigned char)*ap)) {
226 mask = 0;
227 do {
228 if (*ap >= '8' || *ap < '0')
229 error("Illegal number: %s", argv[1]);
230 mask = (mask << 3) + (*ap - '0');
231 } while (*++ap != '\0');
232 umask(mask);
233 } else {
234 void *set;
235
236 INTOFF;
237 if ((set = setmode(ap)) != 0) {
238 mask = getmode(set, ~mask & 0777);
239 ckfree(set);
240 }
241 INTON;
242 if (!set)
243 error("Illegal mode: %s", ap);
244
245 umask(~mask & 0777);
246 }
247 }
248 return 0;
249 }
250
251 /*
252 * ulimit builtin
253 *
254 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
255 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
256 * ash by J.T. Conklin.
257 *
258 * Public domain.
259 */
260
261 struct limits {
262 const char *name;
263 int cmd;
264 int factor; /* multiply by to get rlim_{cur,max} values */
265 char option;
266 };
267
268 static const struct limits limits[] = {
269 #ifdef RLIMIT_CPU
270 { "time(seconds)", RLIMIT_CPU, 1, 't' },
271 #endif
272 #ifdef RLIMIT_FSIZE
273 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
274 #endif
275 #ifdef RLIMIT_DATA
276 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
277 #endif
278 #ifdef RLIMIT_STACK
279 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
280 #endif
281 #ifdef RLIMIT_CORE
282 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
283 #endif
284 #ifdef RLIMIT_RSS
285 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
286 #endif
287 #ifdef RLIMIT_MEMLOCK
288 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
289 #endif
290 #ifdef RLIMIT_NPROC
291 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
292 #endif
293 #ifdef RLIMIT_NOFILE
294 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
295 #endif
296 #ifdef RLIMIT_VMEM
297 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
298 #endif
299 #ifdef RLIMIT_SWAP
300 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
301 #endif
302 { (char *) 0, 0, 0, '\0' }
303 };
304
305 int
306 ulimitcmd(argc, argv)
307 int argc;
308 char **argv;
309 {
310 int c;
311 rlim_t val = 0;
312 enum { SOFT = 0x1, HARD = 0x2 }
313 how = SOFT | HARD;
314 const struct limits *l;
315 int set, all = 0;
316 int optc, what;
317 struct rlimit limit;
318
319 what = 'f';
320 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
321 switch (optc) {
322 case 'H':
323 how = HARD;
324 break;
325 case 'S':
326 how = SOFT;
327 break;
328 case 'a':
329 all = 1;
330 break;
331 default:
332 what = optc;
333 }
334
335 for (l = limits; l->name && l->option != what; l++)
336 ;
337 if (!l->name)
338 error("internal error (%c)", what);
339
340 set = *argptr ? 1 : 0;
341 if (set) {
342 char *p = *argptr;
343
344 if (all || argptr[1])
345 error("too many arguments");
346 if (strcmp(p, "unlimited") == 0)
347 val = RLIM_INFINITY;
348 else {
349 val = (rlim_t) 0;
350
351 while ((c = *p++) >= '0' && c <= '9')
352 {
353 val = (val * 10) + (long)(c - '0');
354 if (val < (rlim_t) 0)
355 break;
356 }
357 if (c)
358 error("bad number");
359 val *= l->factor;
360 }
361 }
362 if (all) {
363 for (l = limits; l->name; l++) {
364 getrlimit(l->cmd, &limit);
365 if (how & SOFT)
366 val = limit.rlim_cur;
367 else if (how & HARD)
368 val = limit.rlim_max;
369
370 out1fmt("%-20s ", l->name);
371 if (val == RLIM_INFINITY)
372 out1fmt("unlimited\n");
373 else
374 {
375 val /= l->factor;
376 #ifdef BSD4_4
377 out1fmt("%lld\n", (long long) val);
378 #else
379 out1fmt("%ld\n", (long) val);
380 #endif
381 }
382 }
383 return 0;
384 }
385
386 getrlimit(l->cmd, &limit);
387 if (set) {
388 if (how & HARD)
389 limit.rlim_max = val;
390 if (how & SOFT)
391 limit.rlim_cur = val;
392 if (setrlimit(l->cmd, &limit) < 0)
393 error("error setting limit (%s)", strerror(errno));
394 } else {
395 if (how & SOFT)
396 val = limit.rlim_cur;
397 else if (how & HARD)
398 val = limit.rlim_max;
399
400 if (val == RLIM_INFINITY)
401 out1fmt("unlimited\n");
402 else
403 {
404 val /= l->factor;
405 #ifdef BSD4_4
406 out1fmt("%lld\n", (long long) val);
407 #else
408 out1fmt("%ld\n", (long) val);
409 #endif
410 }
411 }
412 return 0;
413 }
414