miscbltin.c revision 1.32 1 /* $NetBSD: miscbltin.c,v 1.32 2003/08/07 09:05:35 agc 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.32 2003/08/07 09:05:35 agc 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 { (char *) 0, 0, 0, '\0' }
294 };
295
296 int
297 ulimitcmd(int argc, char **argv)
298 {
299 int c;
300 rlim_t val = 0;
301 enum { SOFT = 0x1, HARD = 0x2 }
302 how = SOFT | HARD;
303 const struct limits *l;
304 int set, all = 0;
305 int optc, what;
306 struct rlimit limit;
307
308 what = 'f';
309 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
310 switch (optc) {
311 case 'H':
312 how = HARD;
313 break;
314 case 'S':
315 how = SOFT;
316 break;
317 case 'a':
318 all = 1;
319 break;
320 default:
321 what = optc;
322 }
323
324 for (l = limits; l->name && l->option != what; l++)
325 ;
326 if (!l->name)
327 error("internal error (%c)", what);
328
329 set = *argptr ? 1 : 0;
330 if (set) {
331 char *p = *argptr;
332
333 if (all || argptr[1])
334 error("too many arguments");
335 if (strcmp(p, "unlimited") == 0)
336 val = RLIM_INFINITY;
337 else {
338 val = (rlim_t) 0;
339
340 while ((c = *p++) >= '0' && c <= '9')
341 {
342 val = (val * 10) + (long)(c - '0');
343 if (val < (rlim_t) 0)
344 break;
345 }
346 if (c)
347 error("bad number");
348 val *= l->factor;
349 }
350 }
351 if (all) {
352 for (l = limits; l->name; l++) {
353 getrlimit(l->cmd, &limit);
354 if (how & SOFT)
355 val = limit.rlim_cur;
356 else if (how & HARD)
357 val = limit.rlim_max;
358
359 out1fmt("%-20s ", l->name);
360 if (val == RLIM_INFINITY)
361 out1fmt("unlimited\n");
362 else
363 {
364 val /= l->factor;
365 #ifdef BSD4_4
366 out1fmt("%lld\n", (long long) val);
367 #else
368 out1fmt("%ld\n", (long) val);
369 #endif
370 }
371 }
372 return 0;
373 }
374
375 getrlimit(l->cmd, &limit);
376 if (set) {
377 if (how & HARD)
378 limit.rlim_max = val;
379 if (how & SOFT)
380 limit.rlim_cur = val;
381 if (setrlimit(l->cmd, &limit) < 0)
382 error("error setting limit (%s)", strerror(errno));
383 } else {
384 if (how & SOFT)
385 val = limit.rlim_cur;
386 else if (how & HARD)
387 val = limit.rlim_max;
388
389 if (val == RLIM_INFINITY)
390 out1fmt("unlimited\n");
391 else
392 {
393 val /= l->factor;
394 #ifdef BSD4_4
395 out1fmt("%lld\n", (long long) val);
396 #else
397 out1fmt("%ld\n", (long) val);
398 #endif
399 }
400 }
401 return 0;
402 }
403