1 /* @(#)builtin.c	1.13 19/01/13 Copyright 2015-2019 J. Schilling */
2 #include <schily/mconfig.h>
3 static	UConst char sccsid[] =
4 	"@(#)builtin.c	1.13 19/01/13 Copyright 2015-2019 J. Schilling";
5 #ifdef DO_SYSBUILTIN
6 /*
7  *	builtlin builtin
8  *
9  *	Copyright (c) 2015-2019 J. Schilling
10  */
11 /*
12  * The contents of this file are subject to the terms of the
13  * Common Development and Distribution License, Version 1.0 only
14  * (the "License").  You may not use this file except in compliance
15  * with the License.
16  *
17  * See the file CDDL.Schily.txt in this distribution for details.
18  * A copy of the CDDL is also available via the Internet at
19  * http://www.opensource.org/licenses/cddl1.txt
20  *
21  * When distributing Covered Code, include this CDDL HEADER in each
22  * file and include the License file CDDL.Schily.txt from this distribution.
23  */
24 
25 #include "defs.h"
26 #include <schily/dlfcn.h>
27 
28 #define	LOCAL	static
29 
30 struct libs {
31 	void		*lib;
32 	struct libs	*next;
33 };
34 
35 	struct sysnod2 *sh_findbuiltin	__PR((Uchar *name));
36 LOCAL	int		sh_addbuiltin	__PR((Uchar *name, bftype func));
37 LOCAL	void		sh_rmbuiltin	__PR((Uchar *name));
38 
39 LOCAL	struct sysnod2	*bltins;	/* List of active builtins */
40 LOCAL	void		*libs;		/* List of active libraries */
41 
42 void
sysbuiltin(argc,argv)43 sysbuiltin(argc, argv)
44 	int	argc;
45 	unsigned char	**argv;
46 {
47 	struct optv optv;
48 	int del;
49 	UInt16_t	mask;
50 	int c;
51 	char *farg;
52 	const struct sysnod	*sp = commands;
53 	int		i;
54 
55 	optinit(&optv);
56 	del = 0;
57 	mask = 0;
58 	farg = NULL;
59 
60 	while ((c = optget(argc, argv, &optv, "df:is")) != -1) {
61 		switch (c) {
62 		case 'd':
63 			del++;
64 			continue;
65 		case 'f':
66 			farg = optv.optarg;
67 			continue;
68 		case 'i':
69 			mask |= BLT_INT;
70 			continue;
71 		case 's':
72 			mask |= BLT_SPC;
73 			continue;
74 
75 		default:
76 			break;
77 
78 		case '?':
79 			gfailure((unsigned char *)usage, builtinuse);
80 			return;
81 		}
82 	}
83 
84 	/*
85 	 * If no arguments, just print the builtin commands
86 	 */
87 	if (optv.optind == argc && !del && !farg) {
88 		for (i = 0; i < no_commands; i++) {
89 			if (sp[i].sysflg & BLT_DEL)
90 				continue;
91 			if (mask && (sp[i].sysflg & mask) == 0)
92 				continue;
93 			prs_buff(UC sp[i].sysnam);
94 			prc_buff(NL);
95 		}
96 	} else if (flags & rshflg) {	/* Managing builtins is restricted */
97 		/*
98 		 * For security reasons, abort scripts that try to use
99 		 * restricted features in a restricted shell.
100 		 */
101 		failed(argv[0], restricted);
102 	} else if (farg) {		/* Add shared library */
103 #ifdef	HAVE_LOADABLE_LIBS
104 		void		*lh;
105 		struct libs	*lp;
106 
107 		lh = dlopen(farg, RTLD_LAZY);
108 		if (lh == NULL) {
109 			failure(argv[0], dlerror());
110 			return;
111 		}
112 		lp = alloc(sizeof (*lp));
113 		if (lp == NULL)
114 			return;
115 		lp->lib = lh;
116 		lp->next = libs;
117 		libs = lp;
118 #else
119 		failure(argv[0], "-f not supported on this platform");
120 		return;
121 #endif
122 	}
123 	/*
124 	 * Add or delete builtin
125 	 */
126 #ifdef	HAVE_LOADABLE_LIBS
127 	if (libs == NULL && optv.optind < argc) {
128 		failure(argv[0], "no libraries");
129 		return;
130 	}
131 	for (; optv.optind < argc; optv.optind++) {
132 		struct libs	*lp = libs;
133 		void		*func;
134 		unsigned char	*name = argv[optv.optind];
135 
136 #ifdef	BUILTIN_DEBUG				/* Optional until ready */
137 		/* XXX avoid printf */
138 		printf("arg[%d] '%s'\n", optv.optind, argv[optv.optind]);
139 #endif
140 		do {
141 			func = dlsym(lp->lib, C name);
142 			lp = lp->next;
143 		} while (func == NULL && lp);
144 		if (func == NULL) {
145 			failure(name, notfound);
146 			continue;
147 		}
148 		if (del) {
149 			sh_rmbuiltin(name);
150 		} else {
151 			if (sh_findbuiltin(name))
152 				failure(name, &notfound[4]);
153 			sh_addbuiltin(name, (bftype) func);
154 		}
155 	}
156 #endif
157 }
158 
159 /*
160  * Return sysnod2 ptr for active loadable builtin.
161  */
162 struct sysnod2 *
sh_findbuiltin(name)163 sh_findbuiltin(name)
164 	unsigned char	*name;
165 {
166 	struct sysnod2	*bp;
167 
168 	for (bp = bltins; bp; bp = bp->snext) {
169 		if (eq(name, bp->sysnam))
170 			return (bp);
171 	}
172 	return (0);
173 }
174 
175 /*
176  * Add new loadable builtin function with command name to active list.
177  */
178 LOCAL int
sh_addbuiltin(name,func)179 sh_addbuiltin(name, func)
180 	unsigned char	*name;
181 	bftype		func;
182 {
183 	struct sysnod2  *bp = alloc(sizeof (struct sysnod2));
184 
185 	if (bp == NULL)
186 		return (1);
187 
188 	bp->sysnam = C make(name);
189 	bp->sysval = 0;
190 	bp->sysflg = 0;
191 	bp->sysptr = func;
192 	bp->snext = bltins;
193 	bltins = bp;
194 	return (0);
195 }
196 
197 /*
198  * Remove loadable builtin function from active list.
199  */
200 LOCAL void
sh_rmbuiltin(name)201 sh_rmbuiltin(name)
202 	unsigned char	*name;
203 {
204 	struct sysnod2  *bp;
205 	struct sysnod2  *obp;
206 
207 	for (obp = bp = bltins; bp; obp = bp, bp = bp->snext) {
208 		if (!eq(name, bp->sysnam))
209 			continue;
210 
211 		if (bp == bltins)
212 			bltins = bp->snext;
213 		else
214 			obp->snext = bp->snext;
215 		free(bp->sysnam);
216 		free(bp);		/* invalidates use of bp->snext */
217 		/*
218 		 * We only allow one element with the same name and we
219 		 * would need a different method than using obp.
220 		 */
221 		break;
222 	}
223 }
224 
225 #endif /* DO_SYSBUILTIN */
226