1 /* @(#)evops.c 1.38 17/07/17 Copyright 1984-2017 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)evops.c 1.38 17/07/17 Copyright 1984-2017 J. Schilling";
6 #endif
7 /*
8 * bsh environment section
9 *
10 * Copyright (c) 1984-2017 J. Schilling
11 */
12 /*
13 * The contents of this file are subject to the terms of the
14 * Common Development and Distribution License, Version 1.0 only
15 * (the "License"). You may not use this file except in compliance
16 * with the License.
17 *
18 * See the file CDDL.Schily.txt in this distribution for details.
19 * A copy of the CDDL is also available via the Internet at
20 * http://www.opensource.org/licenses/cddl1.txt
21 *
22 * When distributing Covered Code, include this CDDL HEADER in each
23 * file and include the License file CDDL.Schily.txt from this distribution.
24 */
25
26 #include <schily/stdio.h>
27 #include <schily/param.h> /* Include various defs needed with some OS */
28 #include <schily/unistd.h>
29 #include <schily/stdlib.h>
30 #include <schily/string.h>
31 #include <schily/limits.h>
32 #include <schily/systeminfo.h>
33 #include <schily/hostname.h>
34 #include <schily/utsname.h>
35 #include <schily/locale.h>
36 #include "bsh.h"
37 #include "str.h"
38 #include "strsubs.h"
39
40
41 #define EVAINC 5
42
43 extern char **evarray;
44 extern unsigned evasize;
45 extern int evaent;
46 extern BOOL noslash;
47 extern char *user;
48 extern char *hostname;
49
50 EXPORT char *getcurenv __PR((char *name));
51 LOCAL char *getval __PR((char *name, char *ev));
52 EXPORT void ev_init __PR((char **evp));
53 EXPORT void ev_insert __PR((char *val));
54 EXPORT void ev_ins __PR((char *val));
55 EXPORT void ev_delete __PR((char *name));
56 EXPORT void ev_inc __PR((void));
57 EXPORT void ev_list __PR((FILE * fp));
58 EXPORT BOOL ev_eql __PR((char *name, char *tval));
59 EXPORT void inituser __PR((void));
60 EXPORT void inithostname __PR((void));
61 EXPORT void initprompt __PR((void));
62 LOCAL void setprompt __PR((char *p, int nr));
63 LOCAL void set_noslash __PR((char *s));
64 EXPORT BOOL ev_set_locked __PR((char *val));
65 LOCAL BOOL ev_is_locked __PR((char *s));
66 LOCAL void ev_check __PR((char *what));
67 #ifdef USE_LOCALE
68 LOCAL BOOL ev_neql __PR((char *name, char *ev));
69 #endif
70 LOCAL void ev_locale __PR((char *name));
71
72 /*
73 * Get the value for a enrivonment variable name.
74 * Check against current environment and not against
75 * the global default 'environ'.
76 */
77 EXPORT char *
getcurenv(name)78 getcurenv(name)
79 char *name;
80 {
81 register char **p = evarray;
82 register char *p2;
83
84 while (*p != NULL) {
85 if ((p2 = getval(name, *p)) != NULL)
86 return (p2);
87 p++;
88 }
89 return (NULL);
90 }
91
92 /*
93 * Check a name against a specific environment array entry.
94 * If name matches, return value, else return NULL.
95 */
96 LOCAL char *
getval(name,ev)97 getval(name, ev)
98 register char *name;
99 register char *ev;
100 {
101 for (;;) {
102 if (*name != *ev) {
103 if (*ev == '=' && *name == '\0')
104 return (++ev);
105 return (NULL);
106 }
107 if (*name == '\0') /* *name == *ev == '\0' */
108 return (NULL);
109 name++;
110 ev++;
111 }
112 }
113
114 /*
115 * Initialize the current environment from the global 'environ'.
116 */
117 EXPORT void
ev_init(evp)118 ev_init(evp)
119 register char *evp[];
120 {
121 register int i;
122
123 ev_inc(); /* ev_insert() benutzt evarray */
124
125 for (i = 0; evp[i] != NULL; i++) {
126 if (strchr(evp[i], '=') == NULL) {
127 error("WARNING: ev_init() Missing '=' in env[%d] '%s'\n",
128 i, evp[i]);
129 }
130 ev_insert(makestr(evp[i]));
131 }
132 }
133
134 /*
135 * Insert a new entry into the current environment.
136 * Check for permission before doing the actual insert.
137 */
138 EXPORT void
ev_insert(val)139 ev_insert(val)
140 char *val;
141 {
142 #ifdef DEBUG
143 printf("ev_insert('%s')\n", val);
144 #endif /* DEBUG */
145 if (ev_set_locked(val)) {
146 free(val);
147 ex_status = 1;
148 return;
149 }
150 ev_ins(val);
151 }
152
153 /*
154 * Insert a new entry into the current environment.
155 * Don't check for permission before doing the actual insert.
156 * Handle variables with special meaning.
157 */
158 EXPORT void
ev_ins(val)159 ev_ins(val)
160 register char *val;
161 {
162 int i;
163 char *p;
164
165 if (!(p = strchr(val, '='))) {
166 free(val);
167 ex_status = 1;
168 return;
169 }
170 p++;
171 #ifdef DEBUG
172 printf("value = '%s'\n", p);
173 #endif /* DEBUG */
174 if (getval(slashname, val))
175 set_noslash(p);
176 #ifdef INTERACTIVE
177 if (getval(histname, val))
178 chghistory(p);
179 #else
180 if (getval(histname, val))
181 if (!sethistory(p))
182 return;
183 #endif
184 if (getval(promptname, val))
185 setprompt(p, 0);
186 if (getval(prompt2name, val))
187 setprompt(p, 1);
188 if (getval(mchkname, val)) {
189 if (!toint(gstd, p, &i))
190 return;
191 if (i < 0) {
192 berror("Bad number '%s'.", p);
193 }
194 mailcheck = i;
195 }
196
197 for (i = 0; i < evaent; i++) {
198 if (streqln(val, evarray[i], p-val)) {
199 free(evarray[i]);
200 evarray[i] = val;
201 ev_locale(val);
202 return;
203 }
204 }
205 if ((evaent+1) >= evasize)
206 ev_inc();
207 if ((evaent+1) >= evasize) { /* ev_inc() did not work */
208 free(val);
209 ex_status = 1;
210 return;
211 }
212 evarray[evaent++] = val;
213 evarray[evaent] = NULL;
214 ev_check("ev_ins()");
215 ev_locale(val);
216 }
217
218 /*
219 * Delete an entry from the current environment.
220 * Don't check for permission before doing the actual insert.
221 * Handle variables with special meaning.
222 */
223 EXPORT void
ev_delete(name)224 ev_delete(name)
225 register char *name;
226 {
227 register int i;
228
229 for (i = 0; i < evaent; i++) {
230 if (getval(name, evarray[i])) {
231 if (ev_is_locked(name)) {
232 berror("Can't delete '%s'. Variable is locked.", name);
233 ex_status = 1;
234 return;
235 }
236 if (streql(name, slashname))
237 set_noslash(nullstr);
238 #ifdef INTERACTIVE
239 if (streql(name, histname))
240 chghistory("0");
241 #else
242 if (streql(name, histname))
243 sethistory("0");
244 #endif
245 if (streql(name, mchkname))
246 mailcheck = 600;
247
248 free(evarray[i]);
249 for (; i < evaent; i++)
250 evarray[i] = evarray[i+1];
251 evarray[i] = NULL;
252 --evaent;
253
254 ev_check("ev_idelete()");
255 ev_locale(name);
256
257 return;
258 }
259 }
260 berror("Can't delete '%s' Variable does not exist.", name);
261 ex_status = 1;
262 }
263
264 /*
265 * Enhance the size of the current environment array.
266 */
267 EXPORT void
ev_inc()268 ev_inc()
269 {
270 char **nevarray;
271
272 if (evarray == (char **)NULL) {
273 nevarray = (char **)malloc(EVAINC*sizeof (char *));
274 } else {
275 nevarray = (char **)realloc(evarray,
276 (evasize+EVAINC)*sizeof (char *));
277 }
278 if (nevarray == (char **)NULL) {
279 berror("%s", sn_no_mem);
280 return;
281 }
282 nevarray[evasize] = NULL;
283 evarray = nevarray;
284 evasize += EVAINC;
285 }
286
287 /*
288 * Print the content of the complete current environment array
289 * on File Pointer 'fp' to allow stdout redirection.
290 */
291 EXPORT void
ev_list(fp)292 ev_list(fp)
293 register FILE *fp;
294 {
295 register int i;
296
297 for (i = 0; i < evaent; i++)
298 fprintf(fp, "%s\n", evarray[i]);
299
300 ev_check("ev_list()");
301 }
302
303 /*
304 * Check the current environment array against name and tval.
305 */
306 EXPORT BOOL
ev_eql(name,tval)307 ev_eql(name, tval)
308 char *name;
309 char *tval;
310 {
311 char *val;
312
313 if ((val = getcurenv(name)) != NULL)
314 return (streql(val, tval));
315 return (FALSE);
316 }
317
318 EXPORT void
inituser()319 inituser()
320 {
321 char *un;
322
323 if (!getcurenv(username)) {
324 if (getcurenv(Elogname)) {
325 ev_insert(concat(username, eql, getcurenv(Elogname), (char *)NULL));
326 } else {
327 un = getuname(geteuid());
328 ev_insert(concat(username, eql, un, (char *)NULL));
329 free(un);
330 }
331 }
332 user = makestr(getcurenv(username));
333 if (!getcurenv(Elogname))
334 ev_insert(concat(Elogname, eql, user, (char *)NULL));
335 }
336
337 EXPORT void
inithostname()338 inithostname()
339 {
340 #if defined(HAVE_SYS_SYSTEMINFO_H) && defined(SI_HOSTNAME)
341
342 #ifndef SYS_NMLN /* SYS_NMLN is in limits.h, missing on MiNT */
343 #define SYS_NMLN 257
344 #endif
345 char host[SYS_NMLN];
346 int ret;
347
348 ret = sysinfo(SI_HOSTNAME, host, sizeof (host));
349 if (ret < 0 || ret > sizeof (host))
350 hostname = makestr(nullstr);
351 else
352 hostname = makestr(host);
353 #else
354 # if defined(HAVE_GETHOSTNAME)
355 #if !defined(MAXHOSTNAMELEN) && defined(MAXGETHOSTNAME)
356 #define MAXHOSTNAMELEN MAXGETHOSTNAME /* XXX DJGPP -> libport ??? */
357 #endif
358 char host[MAXHOSTNAMELEN];
359
360 if (gethostname(host, sizeof (host)) < 0)
361 hostname = makestr(nullstr);
362 else
363 hostname = makestr(host);
364 # else
365 struct utsname unm;
366
367 if (uname(&unm) < 0)
368 hostname = makestr(nullstr);
369 else
370 hostname = makestr(unm.nodename);
371 # endif
372 #endif
373 }
374
375 /*
376 * Set prompt according to uid
377 */
378 EXPORT void
initprompt()379 initprompt()
380 {
381 ev_insert(concat(promptname, eql, hostname, hostname[0] ? " " : nullstr,
382 geteuid() ? user : "admin", "> ", (char *)NULL));
383 #ifdef INTERACTIVE
384 ev_insert(concat(prompt2name, eql, MOREPROMPT, (char *)NULL));
385 #else /* INTERACTIVE */
386 ev_insert(concat(prompt2name, eql, EDITPROMPT, (char *)NULL));
387 #endif /* INTERACTIVE */
388 }
389
390 /*
391 * Set prompt to value of p
392 */
393 LOCAL void
setprompt(p,nr)394 setprompt(p, nr)
395 char *p;
396 int nr;
397 {
398 if (prompts[nr])
399 free(prompts[nr]);
400 prompts[nr] = makestr(p);
401 }
402
403 LOCAL void
set_noslash(s)404 set_noslash(s)
405 char *s;
406 {
407 noslash = streql(s, off);
408 }
409
410 EXPORT BOOL
ev_set_locked(val)411 ev_set_locked(val)
412 char *val;
413 {
414 if (ev_is_locked(val)) {
415 berror("Can't set environment '%s'. Variable is locked.", val);
416 return (TRUE);
417 }
418 return (FALSE);
419 }
420
421 /*
422 * Check if environment variable is in locklist.
423 */
424 LOCAL BOOL
ev_is_locked(s)425 ev_is_locked(s)
426 register char *s;
427 {
428 register char *lockstr;
429 register char *c;
430 register int len;
431
432 if (!(lockstr = getcurenv(evlockname)))
433 return (FALSE);
434 if (streql(lockstr, on))
435 return (TRUE);
436 c = strchr(s, '=');
437 if (!c)
438 len = strlen(s);
439 else
440 len = c - s;
441 while (*lockstr) {
442 if ((c = strchr(lockstr, ':')) == NULL)
443 return (strlen(lockstr) == len && streqln(s, lockstr, len));
444 if ((c - lockstr) == len && streqln(s, lockstr, len))
445 return (TRUE);
446 lockstr = ++c;
447 }
448 return (FALSE);
449 }
450
451 LOCAL void
ev_check(what)452 ev_check(what)
453 char *what;
454 {
455 int i;
456
457 for (i = 0; evarray[i] != NULL; i++) {
458 if (i >= evaent)
459 error("WARNING: %s No NULL in env[%d] '%s'\n", what, i, evarray[i]);
460 if (strchr(evarray[i], '=') == NULL)
461 error("WARNING: %s Missing '=' in env[%d] '%s'\n", what, i, evarray[i]);
462 }
463 if (i != evaent)
464 error("WARNING: %s i %d evaent %d\n", what, i, evaent);
465 }
466
467 #ifdef USE_LOCALE
468 LOCAL BOOL
ev_neql(name,ev)469 ev_neql(name, ev)
470 register char *name;
471 register char *ev;
472 {
473 for (;;) {
474 if (*name != *ev) {
475 if (*ev == '=' && *name == '\0')
476 return (TRUE);
477 return (FALSE);
478 }
479 if (*name == '\0') /* *name == *ev == '\0' */
480 return (TRUE);
481 name++;
482 ev++;
483 }
484 }
485 #endif
486
487 LOCAL void
ev_locale(name)488 ev_locale(name)
489 char *name;
490 {
491 #ifdef USE_LOCALE
492
493 char **esav;
494 extern char **environ;
495
496 if (name[0] != 'L')
497 return;
498
499 if (!(ev_neql("LC_ALL", name) ||
500 ev_neql("LC_CTYPE", name) ||
501 ev_neql("LC_COLLATE", name) ||
502 ev_neql("LC_NUMERIC", name) ||
503 ev_neql("LC_MESSAGES", name) ||
504 ev_neql("LC_MONETARY", name) ||
505 ev_neql("LC_TIME", name) ||
506 ev_neql("LANG", name)))
507 return;
508
509 /*
510 * Do not call setlocale() before inituser() was called which is an
511 * indication that our local environment was initialized.
512 */
513 if (user == NULL)
514 return;
515
516 /*
517 * Let getenv() simulate the behaviour of getcurenv().
518 * This allows us to use the libc setlocale() for bsh.
519 */
520 esav = environ;
521 environ = evarray;
522
523 if (setlocale(LC_ALL, "") == NULL)
524 error("Bad locale '%s'.\n", name);
525
526 environ = esav;
527 #endif
528 }
529