Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / bin / sh / miscbltin.c
1 /*-
2  * Copyright (c) 1991, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Kenneth Almquist.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * @(#)miscbltin.c      8.4 (Berkeley) 5/4/95
37  * $FreeBSD: src/bin/sh/miscbltin.c,v 1.22.2.3 2002/07/19 04:38:51 tjr Exp $
38  * $DragonFly: src/bin/sh/miscbltin.c,v 1.2 2003/06/17 04:22:50 dillon Exp $
39  */
40
41 /*
42  * Miscellaneous builtins.
43  */
44
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <sys/time.h>
48 #include <sys/resource.h>
49 #include <unistd.h>
50 #include <ctype.h>
51 #include <errno.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <termios.h>
55
56 #include "shell.h"
57 #include "options.h"
58 #include "var.h"
59 #include "output.h"
60 #include "memalloc.h"
61 #include "error.h"
62 #include "mystring.h"
63
64 #undef eflag
65
66 /*
67  * The read builtin.  The -r option causes backslashes to be treated like
68  * ordinary characters.
69  *
70  * This uses unbuffered input, which may be avoidable in some cases.
71  */
72
73 int
74 readcmd(int argc __unused, char **argv __unused)
75 {
76         char **ap;
77         int backslash;
78         char c;
79         int rflag;
80         char *prompt;
81         char *ifs;
82         char *p;
83         int startword;
84         int status;
85         int i;
86         struct timeval tv;
87         char *tvptr;
88         fd_set ifds;
89         struct termios told, tnew;
90         int tsaved;
91
92         rflag = 0;
93         prompt = NULL;
94         tv.tv_sec = -1;
95         tv.tv_usec = 0;
96         while ((i = nextopt("erp:t:")) != '\0') {
97                 switch(i) {
98                 case 'p':
99                         prompt = shoptarg;
100                         break;
101                 case 'e':
102                         break;
103                 case 'r':
104                         rflag = 1;
105                         break;
106                 case 't':
107                         tv.tv_sec = strtol(shoptarg, &tvptr, 0);
108                         if (tvptr == shoptarg)
109                                 error("timeout value");
110                         switch(*tvptr) {
111                         case 0:
112                         case 's':
113                                 break;
114                         case 'h':
115                                 tv.tv_sec *= 60;
116                                 /* FALLTHROUGH */
117                         case 'm':
118                                 tv.tv_sec *= 60;
119                                 break;
120                         default:
121                                 error("timeout unit");
122                         }
123                         break;
124                 }
125         }
126         if (prompt && isatty(0)) {
127                 out2str(prompt);
128                 flushall();
129         }
130         if (*(ap = argptr) == NULL)
131                 error("arg count");
132         if ((ifs = bltinlookup("IFS", 1)) == NULL)
133                 ifs = nullstr;
134
135         if (tv.tv_sec >= 0) {
136                 /*
137                  * See if we can disable input processing; this will
138                  * not give the desired result if we are in a pipeline
139                  * and someone upstream is still in line-by-line mode.
140                  */
141                 tsaved = 0;
142                 if (tcgetattr(0, &told) == 0) {
143                         memcpy(&tnew, &told, sizeof(told));
144                         cfmakeraw(&tnew);
145                         tcsetattr(0, TCSANOW, &tnew);
146                         tsaved = 1;
147                 }
148                 /*
149                  * Wait for something to become available.
150                  */
151                 FD_ZERO(&ifds);
152                 FD_SET(0, &ifds);
153                 status = select(1, &ifds, NULL, NULL, &tv);
154                 if (tsaved)
155                         tcsetattr(0, TCSANOW, &told);
156                 /*
157                  * If there's nothing ready, return an error.
158                  */
159                 if (status <= 0)
160                         return(1);
161         }
162
163         status = 0;
164         startword = 1;
165         backslash = 0;
166         STARTSTACKSTR(p);
167         for (;;) {
168                 if (read(STDIN_FILENO, &c, 1) != 1) {
169                         status = 1;
170                         break;
171                 }
172                 if (c == '\0')
173                         continue;
174                 if (backslash) {
175                         backslash = 0;
176                         if (c != '\n')
177                                 STPUTC(c, p);
178                         continue;
179                 }
180                 if (!rflag && c == '\\') {
181                         backslash++;
182                         continue;
183                 }
184                 if (c == '\n')
185                         break;
186                 if (startword && *ifs == ' ' && strchr(ifs, c)) {
187                         continue;
188                 }
189                 startword = 0;
190                 if (backslash && c == '\\') {
191                         if (read(STDIN_FILENO, &c, 1) != 1) {
192                                 status = 1;
193                                 break;
194                         }
195                         STPUTC(c, p);
196                 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
197                         STACKSTRNUL(p);
198                         setvar(*ap, stackblock(), 0);
199                         ap++;
200                         startword = 1;
201                         STARTSTACKSTR(p);
202                 } else {
203                         STPUTC(c, p);
204                 }
205         }
206         STACKSTRNUL(p);
207         setvar(*ap, stackblock(), 0);
208         while (*++ap != NULL)
209                 setvar(*ap, nullstr, 0);
210         return status;
211 }
212
213
214
215 int
216 umaskcmd(int argc __unused, char **argv)
217 {
218         char *ap;
219         int mask;
220         int i;
221         int symbolic_mode = 0;
222
223         while ((i = nextopt("S")) != '\0') {
224                 symbolic_mode = 1;
225         }
226
227         INTOFF;
228         mask = umask(0);
229         umask(mask);
230         INTON;
231
232         if ((ap = *argptr) == NULL) {
233                 if (symbolic_mode) {
234                         char u[4], g[4], o[4];
235
236                         i = 0;
237                         if ((mask & S_IRUSR) == 0)
238                                 u[i++] = 'r';
239                         if ((mask & S_IWUSR) == 0)
240                                 u[i++] = 'w';
241                         if ((mask & S_IXUSR) == 0)
242                                 u[i++] = 'x';
243                         u[i] = '\0';
244
245                         i = 0;
246                         if ((mask & S_IRGRP) == 0)
247                                 g[i++] = 'r';
248                         if ((mask & S_IWGRP) == 0)
249                                 g[i++] = 'w';
250                         if ((mask & S_IXGRP) == 0)
251                                 g[i++] = 'x';
252                         g[i] = '\0';
253
254                         i = 0;
255                         if ((mask & S_IROTH) == 0)
256                                 o[i++] = 'r';
257                         if ((mask & S_IWOTH) == 0)
258                                 o[i++] = 'w';
259                         if ((mask & S_IXOTH) == 0)
260                                 o[i++] = 'x';
261                         o[i] = '\0';
262
263                         out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
264                 } else {
265                         out1fmt("%.4o\n", mask);
266                 }
267         } else {
268                 if (isdigit(*ap)) {
269                         mask = 0;
270                         do {
271                                 if (*ap >= '8' || *ap < '0')
272                                         error("Illegal number: %s", argv[1]);
273                                 mask = (mask << 3) + (*ap - '0');
274                         } while (*++ap != '\0');
275                         umask(mask);
276                 } else {
277                         void *set;
278                         if ((set = setmode (ap)) == 0)
279                                 error("Illegal number: %s", ap);
280
281                         mask = getmode (set, ~mask & 0777);
282                         umask(~mask & 0777);
283                         free(set);
284                 }
285         }
286         return 0;
287 }
288
289 /*
290  * ulimit builtin
291  *
292  * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
293  * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
294  * ash by J.T. Conklin.
295  *
296  * Public domain.
297  */
298
299 struct limits {
300         const char *name;
301         const char *units;
302         int     cmd;
303         int     factor; /* multiply by to get rlim_{cur,max} values */
304         char    option;
305 };
306
307 static const struct limits limits[] = {
308 #ifdef RLIMIT_CPU
309         { "cpu time",           "seconds",      RLIMIT_CPU,        1, 't' },
310 #endif
311 #ifdef RLIMIT_FSIZE
312         { "file size",          "512-blocks",   RLIMIT_FSIZE,    512, 'f' },
313 #endif
314 #ifdef RLIMIT_DATA
315         { "data seg size",      "kbytes",       RLIMIT_DATA,    1024, 'd' },
316 #endif
317 #ifdef RLIMIT_STACK
318         { "stack size",         "kbytes",       RLIMIT_STACK,   1024, 's' },
319 #endif
320 #ifdef  RLIMIT_CORE
321         { "core file size",     "512-blocks",   RLIMIT_CORE,     512, 'c' },
322 #endif
323 #ifdef RLIMIT_RSS
324         { "max memory size",    "kbytes",       RLIMIT_RSS,     1024, 'm' },
325 #endif
326 #ifdef RLIMIT_MEMLOCK
327         { "locked memory",      "kbytes",       RLIMIT_MEMLOCK, 1024, 'l' },
328 #endif
329 #ifdef RLIMIT_NPROC
330         { "max user processes", (char *)0,      RLIMIT_NPROC,      1, 'u' },
331 #endif
332 #ifdef RLIMIT_NOFILE
333         { "open files",         (char *)0,      RLIMIT_NOFILE,     1, 'n' },
334 #endif
335 #ifdef RLIMIT_VMEM
336         { "virtual mem size",   "kbytes",       RLIMIT_VMEM,    1024, 'v' },
337 #endif
338 #ifdef RLIMIT_SWAP
339         { "swap limit",         "kbytes",       RLIMIT_SWAP,    1024, 'w' },
340 #endif
341 #ifdef RLIMIT_SBSIZE
342         { "sbsize",             "bytes",        RLIMIT_SBSIZE,     1, 'b' },
343 #endif
344         { (char *) 0,           (char *)0,      0,                 0, '\0' }
345 };
346
347 int
348 ulimitcmd(int argc __unused, char **argv __unused)
349 {
350         int     c;
351         quad_t val = 0;
352         enum { SOFT = 0x1, HARD = 0x2 }
353                         how = SOFT | HARD;
354         const struct limits     *l;
355         int             set, all = 0;
356         int             optc, what;
357         struct rlimit   limit;
358
359         what = 'f';
360         while ((optc = nextopt("HSatfdsmcnuvlb")) != '\0')
361                 switch (optc) {
362                 case 'H':
363                         how = HARD;
364                         break;
365                 case 'S':
366                         how = SOFT;
367                         break;
368                 case 'a':
369                         all = 1;
370                         break;
371                 default:
372                         what = optc;
373                 }
374
375         for (l = limits; l->name && l->option != what; l++)
376                 ;
377         if (!l->name)
378                 error("ulimit: internal error (%c)", what);
379
380         set = *argptr ? 1 : 0;
381         if (set) {
382                 char *p = *argptr;
383
384                 if (all || argptr[1])
385                         error("ulimit: too many arguments");
386                 if (strcmp(p, "unlimited") == 0)
387                         val = RLIM_INFINITY;
388                 else {
389                         val = (quad_t) 0;
390
391                         while ((c = *p++) >= '0' && c <= '9')
392                         {
393                                 val = (val * 10) + (long)(c - '0');
394                                 if (val < (quad_t) 0)
395                                         break;
396                         }
397                         if (c)
398                                 error("ulimit: bad number");
399                         val *= l->factor;
400                 }
401         }
402         if (all) {
403                 for (l = limits; l->name; l++) { 
404                         char optbuf[40];
405                         if (getrlimit(l->cmd, &limit) < 0)
406                                 error("ulimit: can't get limit: %s", strerror(errno));
407                         if (how & SOFT)
408                                 val = limit.rlim_cur;
409                         else if (how & HARD)
410                                 val = limit.rlim_max;
411
412                         if (l->units)
413                                 snprintf(optbuf, sizeof(optbuf),
414                                         "(%s, -%c) ", l->units, l->option);
415                         else
416                                 snprintf(optbuf, sizeof(optbuf),
417                                         "(-%c) ", l->option);
418                         out1fmt("%-18s %18s ", l->name, optbuf);
419                         if (val == RLIM_INFINITY)
420                                 out1fmt("unlimited\n");
421                         else
422                         {
423                                 val /= l->factor;
424                                 out1fmt("%qd\n", (quad_t) val);
425                         }
426                 }
427                 return 0;
428         }
429
430         if (getrlimit(l->cmd, &limit) < 0)
431                 error("ulimit: can't get limit: %s", strerror(errno));
432         if (set) {
433                 if (how & SOFT)
434                         limit.rlim_cur = val;
435                 if (how & HARD)
436                         limit.rlim_max = val;
437                 if (setrlimit(l->cmd, &limit) < 0)
438                         error("ulimit: bad limit: %s", strerror(errno));
439         } else {
440                 if (how & SOFT)
441                         val = limit.rlim_cur;
442                 else if (how & HARD)
443                         val = limit.rlim_max;
444
445                 if (val == RLIM_INFINITY)
446                         out1fmt("unlimited\n");
447                 else
448                 {
449                         val /= l->factor;
450                         out1fmt("%qd\n", (quad_t) val);
451                 }
452         }
453         return 0;
454 }