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, ¬found[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