xref: /illumos-gate/usr/src/cmd/sh/bltin.c (revision 4bc0a2ef)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 1996 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29 /*	  All Rights Reserved  	*/
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 /*
33  *
34  * UNIX shell
35  *
36  */
37 
38 
39 #include	"defs.h"
40 #include	<errno.h>
41 #include	"sym.h"
42 #include	"hash.h"
43 #include	<sys/types.h>
44 #include	<sys/times.h>
45 
46 void
47 builtin(int type, int argc, unsigned char **argv, struct trenod *t)
48 {
49 	short index = initio(t->treio, (type != SYSEXEC));
50 	unsigned char *a1 = argv[1];
51 
52 	switch (type)
53 	{
54 
55 	case SYSSUSP:
56 		syssusp(argc,argv);
57 		break;
58 
59 	case SYSSTOP:
60 		sysstop(argc,argv);
61 		break;
62 
63 	case SYSKILL:
64 		syskill(argc,argv);
65 		break;
66 
67 	case SYSFGBG:
68 		sysfgbg(argc,argv);
69 		break;
70 
71 	case SYSJOBS:
72 		sysjobs(argc,argv);
73 		break;
74 
75 	case SYSDOT:
76 		if (a1)
77 		{
78 			int	f;
79 
80 			if ((f = pathopen(getpath(a1), a1)) < 0)
81 				failed(a1, notfound);
82 			else
83 				execexp(0, f);
84 		}
85 		break;
86 
87 	case SYSTIMES:
88 		{
89 			struct tms tms;
90 
91 			times(&tms);
92 			prt(tms.tms_cutime);
93 			prc_buff(SPACE);
94 			prt(tms.tms_cstime);
95 			prc_buff(NL);
96 		}
97 		break;
98 
99 	case SYSEXIT:
100 		if ( tried_to_exit++ || endjobs(JOB_STOPPED) ){
101 			flags |= forcexit;	/* force exit */
102 			exitsh(a1 ? stoi(a1) : retval);
103 		}
104 		break;
105 
106 	case SYSNULL:
107 		t->treio = 0;
108 		break;
109 
110 	case SYSCONT:
111 		if (loopcnt)
112 		{
113 			execbrk = breakcnt = 1;
114 			if (a1)
115 				breakcnt = stoi(a1);
116 			if (breakcnt > loopcnt)
117 				breakcnt = loopcnt;
118 			else
119 				breakcnt = -breakcnt;
120 		}
121 		break;
122 
123 	case SYSBREAK:
124 		if (loopcnt)
125 		{
126 			execbrk = breakcnt = 1;
127 			if (a1)
128 				breakcnt = stoi(a1);
129 			if (breakcnt > loopcnt)
130 				breakcnt = loopcnt;
131 		}
132 		break;
133 
134 	case SYSTRAP:
135 		systrap(argc,argv);
136 		break;
137 
138 	case SYSEXEC:
139 		argv++;
140 		ioset = 0;
141 		if (a1 == 0) {
142 			setmode(0);
143 			break;
144 		}
145 		/* FALLTHROUGH */
146 
147 #ifdef RES	/* Research includes login as part of the shell */
148 
149 	case SYSLOGIN:
150 		if (!endjobs(JOB_STOPPED|JOB_RUNNING))
151 			break;
152 		oldsigs();
153 		execa(argv, -1);
154 		done(0);
155 #else
156 
157 	case SYSNEWGRP:
158 		if (flags & rshflg)
159 			failed(argv[0], restricted);
160 		else if (!endjobs(JOB_STOPPED|JOB_RUNNING))
161 			break;
162 		else
163 		{
164 			flags |= forcexit; /* bad exec will terminate shell */
165 			oldsigs();
166 			rmtemp(0);
167 			rmfunctmp();
168 #ifdef ACCT
169 			doacct();
170 #endif
171 			execa(argv, -1);
172 			done(0);
173 		}
174 
175 #endif
176 
177 	case SYSCD:
178 		if (flags & rshflg)
179 			failed(argv[0], restricted);
180 		else if ((a1 && *a1) || (a1 == 0 && (a1 = homenod.namval)))
181 		{
182 			unsigned char *cdpath;
183 			unsigned char *dir;
184 			int f;
185 
186 			if ((cdpath = cdpnod.namval) == 0 ||
187 			     *a1 == '/' ||
188 			     cf(a1, ".") == 0 ||
189 			     cf(a1, "..") == 0 ||
190 			     (*a1 == '.' && (*(a1+1) == '/' || *(a1+1) == '.' && *(a1+2) == '/')))
191 				cdpath = (unsigned char *)nullstr;
192 
193 			do
194 			{
195 				dir = cdpath;
196 				cdpath = catpath(cdpath,a1);
197 			}
198 			while ((f = (chdir((const char *) curstak()) < 0)) &&
199 			    cdpath);
200 
201 			if (f) {
202 				switch(errno) {
203 						case EMULTIHOP:
204 							failed(a1, emultihop);
205 							break;
206 						case ENOTDIR:
207 							failed(a1, enotdir);
208 							break;
209 						case ENOENT:
210 							failed(a1, enoent);
211 							break;
212 						case EACCES:
213 							failed(a1, eacces);
214 							break;
215 						case ENOLINK:
216 							failed(a1, enolink);
217 							break;
218 						default:
219 						failed(a1, baddir);
220 						break;
221 						}
222 			}
223 			else
224 			{
225 				cwd(curstak());
226 				if (cf(nullstr, dir) &&
227 				    *dir != ':' &&
228 					any('/', curstak()) &&
229 					flags & prompt)
230 				{
231 					prs_buff(cwdget());
232 					prc_buff(NL);
233 				}
234 			}
235 			zapcd();
236 		}
237 		else
238 		{
239 			if (a1)
240 				error(nulldir);
241 			else
242 				error(nohome);
243 		}
244 
245 		break;
246 
247 	case SYSSHFT:
248 		{
249 			int places;
250 
251 			places = a1 ? stoi(a1) : 1;
252 
253 			if ((dolc -= places) < 0)
254 			{
255 				dolc = 0;
256 				error(badshift);
257 			}
258 			else
259 				dolv += places;
260 		}
261 
262 		break;
263 
264 	case SYSWAIT:
265 		syswait(argc,argv);
266 		break;
267 
268 	case SYSREAD:
269 		if(argc < 2)
270 			failed(argv[0],mssgargn);
271 		rwait = 1;
272 		exitval = readvar(&argv[1]);
273 		rwait = 0;
274 		break;
275 
276 	case SYSSET:
277 		if (a1)
278 		{
279 			int	cnt;
280 
281 			cnt = options(argc, argv);
282 			if (cnt > 1)
283 				setargs(argv + argc - cnt);
284 		}
285 		else if (comptr(t)->comset == 0)
286 		{
287 			/*
288 			 * scan name chain and print
289 			 */
290 			namscan(printnam);
291 		}
292 		break;
293 
294 	case SYSRDONLY:
295 		exitval = 0;
296 		if (a1)
297 		{
298 			while (*++argv)
299 				attrib(lookup(*argv), N_RDONLY);
300 		}
301 		else
302 			namscan(printro);
303 
304 		break;
305 
306 	case SYSXPORT:
307 		{
308 			struct namnod 	*n;
309 
310 			exitval = 0;
311 			if (a1)
312 			{
313 				while (*++argv)
314 				{
315 					n = lookup(*argv);
316 					if (n->namflg & N_FUNCTN)
317 						error(badexport);
318 					else
319 						attrib(n, N_EXPORT);
320 				}
321 			}
322 			else
323 				namscan(printexp);
324 		}
325 		break;
326 
327 	case SYSEVAL:
328 		if (a1)
329 			execexp(a1, &argv[2]);
330 		break;
331 
332 #ifndef RES
333 	case SYSULIMIT:
334 		sysulimit(argc, argv);
335 		break;
336 
337 	case SYSUMASK:
338 		if (a1)
339 		{
340 			int c;
341 			mode_t i;
342 
343 			i = 0;
344 			while ((c = *a1++) >= '0' && c <= '7')
345 				i = (i << 3) + c - '0';
346 			umask(i);
347 		}
348 		else
349 		{
350 			mode_t i;
351 			int j;
352 
353 			umask(i = umask(0));
354 			prc_buff('0');
355 			for (j = 6; j >= 0; j -= 3)
356 				prc_buff(((i >> j) & 07) +'0');
357 			prc_buff(NL);
358 		}
359 		break;
360 
361 #endif
362 
363 	case SYSTST:
364 		exitval = test(argc, argv);
365 		break;
366 
367 	case SYSECHO:
368 		exitval = echo(argc, argv);
369 		break;
370 
371 	case SYSHASH:
372 		exitval = 0;
373 
374 		if (a1)
375 		{
376 			if (a1[0] == '-')
377 			{
378 				if (a1[1] == 'r')
379 					zaphash();
380 				else
381 					error(badopt);
382 			}
383 			else
384 			{
385 				while (*++argv)
386 				{
387 					if (hashtype(hash_cmd(*argv)) == NOTFOUND)
388 						failed(*argv, notfound);
389 				}
390 			}
391 		}
392 		else
393 			hashpr();
394 
395 		break;
396 
397 	case SYSPWD:
398 		{
399 			exitval = 0;
400 			cwdprint();
401 		}
402 		break;
403 
404 	case SYSRETURN:
405 		if (funcnt == 0)
406 			error(badreturn);
407 
408 		execbrk = 1;
409 		exitval = (a1 ? stoi(a1) : retval);
410 		break;
411 
412 	case SYSTYPE:
413 		exitval = 0;
414 		if (a1)
415 		{
416 			/* return success only if all names are found */
417 			while (*++argv)
418 				exitval |= what_is_path(*argv);
419 		}
420 		break;
421 
422 	case SYSUNS:
423 		exitval = 0;
424 		if (a1)
425 		{
426 			while (*++argv)
427 				unset_name(*argv);
428 		}
429 		break;
430 
431 	case SYSGETOPT: {
432 		int getoptval;
433 		struct namnod *n;
434 		extern unsigned char numbuf[];
435 		unsigned char *varnam = argv[2];
436 		unsigned char c[2];
437 		if(argc < 3) {
438 			failure(argv[0],mssgargn);
439 			break;
440 		}
441 		exitval = 0;
442 		n = lookup("OPTIND");
443 		optind = stoi(n->namval);
444 		if(argc > 3) {
445 			argv[2] = dolv[0];
446 			getoptval = getopt(argc-2, (char **)&argv[2], (char *)argv[1]);
447 		}
448 		else
449 			getoptval = getopt(dolc+1, (char **)dolv, (char *)argv[1]);
450 		if(getoptval == -1) {
451 			itos(optind);
452 			assign(n, numbuf);
453 			n = lookup(varnam);
454 			assign(n, (unsigned char *)nullstr);
455 			exitval = 1;
456 			break;
457 		}
458 		argv[2] = varnam;
459 		itos(optind);
460 		assign(n, numbuf);
461 		c[0] = getoptval;
462 		c[1] = 0;
463 		n = lookup(varnam);
464 		assign(n, c);
465 		n = lookup("OPTARG");
466 		assign(n, (unsigned char *)optarg);
467 		}
468 		break;
469 
470 	default:
471 		prs_buff("unknown builtin\n");
472 	}
473 
474 
475 	flushb();
476 	restore(index);
477 	chktrap();
478 }
479