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