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