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