Blame main.c

Packit Service 95ac19
/*	$OpenBSD: main.c,v 1.57 2015/09/10 22:48:58 nicm Exp $	*/
Packit Service 95ac19
/*	$OpenBSD: tty.c,v 1.10 2014/08/10 02:44:26 guenther Exp $	*/
Packit Service 95ac19
/*	$OpenBSD: io.c,v 1.26 2015/09/11 08:00:27 guenther Exp $	*/
Packit Service 95ac19
/*	$OpenBSD: table.c,v 1.16 2015/09/01 13:12:31 tedu Exp $	*/
Packit Service 95ac19
Packit Service 95ac19
/*-
Packit Service 95ac19
 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
Packit Service 95ac19
 *		 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
Packit Service 95ac19
 *	mirabilos <m@mirbsd.org>
Packit Service 95ac19
 *
Packit Service 95ac19
 * Provided that these terms and disclaimer and all copyright notices
Packit Service 95ac19
 * are retained or reproduced in an accompanying document, permission
Packit Service 95ac19
 * is granted to deal in this work without restriction, including un-
Packit Service 95ac19
 * limited rights to use, publicly perform, distribute, sell, modify,
Packit Service 95ac19
 * merge, give away, or sublicence.
Packit Service 95ac19
 *
Packit Service 95ac19
 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
Packit Service 95ac19
 * the utmost extent permitted by applicable law, neither express nor
Packit Service 95ac19
 * implied; without malicious intent or gross negligence. In no event
Packit Service 95ac19
 * may a licensor, author or contributor be held liable for indirect,
Packit Service 95ac19
 * direct, other damage, loss, or other issues arising in any way out
Packit Service 95ac19
 * of dealing in the work, even if advised of the possibility of such
Packit Service 95ac19
 * damage or existence of a defect, except proven that it results out
Packit Service 95ac19
 * of said person's immediate fault when using the work as intended.
Packit Service 95ac19
 */
Packit Service 95ac19
Packit Service 95ac19
#define EXTERN
Packit Service 95ac19
#include "sh.h"
Packit Service 95ac19
Packit Service 95ac19
#if HAVE_LANGINFO_CODESET
Packit Service 95ac19
#include <langinfo.h>
Packit Service 95ac19
#endif
Packit Service 95ac19
#if HAVE_SETLOCALE_CTYPE
Packit Service 95ac19
#include <locale.h>
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.347 2018/01/13 21:45:07 tg Exp $");
Packit Service 95ac19
Packit Service 95ac19
#ifndef MKSHRC_PATH
Packit Service 95ac19
#define MKSHRC_PATH	"~/.mkshrc"
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
#ifndef MKSH_DEFAULT_TMPDIR
Packit Service 95ac19
#define MKSH_DEFAULT_TMPDIR	MKSH_UNIXROOT "/tmp"
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
static uint8_t isuc(const char *);
Packit Service 95ac19
static int main_init(int, const char *[], Source **, struct block **);
Packit Service 95ac19
void chvt_reinit(void);
Packit Service 95ac19
static void reclaim(void);
Packit Service 95ac19
static void remove_temps(struct temp *);
Packit Service 95ac19
static mksh_uari_t rndsetup(void);
Packit Service 95ac19
static void init_environ(void);
Packit Service 95ac19
#ifdef SIGWINCH
Packit Service 95ac19
static void x_sigwinch(int);
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
static const char initsubs[] =
Packit Service 95ac19
    "${PS2=> }"
Packit Service 95ac19
    "${PS3=#? }"
Packit Service 95ac19
    "${PS4=+ }"
Packit Service 95ac19
    "${SECONDS=0}"
Packit Service 95ac19
    "${TMOUT=0}"
Packit Service 95ac19
    "${EPOCHREALTIME=}";
Packit Service 95ac19
Packit Service 95ac19
static const char *initcoms[] = {
Packit Service 95ac19
	Ttypeset, "-r", initvsn, NULL,
Packit Service 95ac19
	Ttypeset, "-x", "HOME", TPATH, TSHELL, NULL,
Packit Service 95ac19
	Ttypeset, "-i10", "COLUMNS", "LINES", "SECONDS", "TMOUT", NULL,
Packit Service 95ac19
	Talias,
Packit Service 95ac19
	"integer=\\\\builtin typeset -i",
Packit Service 95ac19
	"local=\\\\builtin typeset",
Packit Service 95ac19
	/* not "alias -t --": hash -r needs to work */
Packit Service 95ac19
	"hash=\\\\builtin alias -t",
Packit Service 95ac19
	"type=\\\\builtin whence -v",
Packit Service 95ac19
	"autoload=\\\\builtin typeset -fu",
Packit Service 95ac19
	"functions=\\\\builtin typeset -f",
Packit Service 95ac19
	"history=\\\\builtin fc -l",
Packit Service 95ac19
	"nameref=\\\\builtin typeset -n",
Packit Service 95ac19
	"nohup=nohup ",
Packit Service 95ac19
	"r=\\\\builtin fc -e -",
Packit Service 95ac19
	"login=\\\\builtin exec login",
Packit Service 95ac19
	NULL,
Packit Service 95ac19
	 /* this is what AT&T ksh seems to track, with the addition of emacs */
Packit Service 95ac19
	Talias, "-tU",
Packit Service 95ac19
	Tcat, "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls",
Packit Service 95ac19
	"make", "mv", "pr", "rm", "sed", Tsh, "vi", "who", NULL,
Packit Service 95ac19
	NULL
Packit Service 95ac19
};
Packit Service 95ac19
Packit Service 95ac19
static const char *restr_com[] = {
Packit Service 95ac19
	Ttypeset, "-r", TPATH, "ENV", TSHELL, NULL
Packit Service 95ac19
};
Packit Service 95ac19
Packit Service 95ac19
static bool initio_done;
Packit Service 95ac19
Packit Service 95ac19
/* top-level parsing and execution environment */
Packit Service 95ac19
static struct env env;
Packit Service 95ac19
struct env *e = &env;
Packit Service 95ac19
Packit Service 95ac19
/* compile-time assertions */
Packit Service 95ac19
#define cta(name, expr) struct cta_ ## name { char t[(expr) ? 1 : -1]; }
Packit Service 95ac19
Packit Service 95ac19
/* this one should be defined by the standard */
Packit Service 95ac19
cta(char_is_1_char, (sizeof(char) == 1) && (sizeof(signed char) == 1) &&
Packit Service 95ac19
    (sizeof(unsigned char) == 1));
Packit Service 95ac19
cta(char_is_8_bits, ((CHAR_BIT) == 8) && ((int)(unsigned char)0xFF == 0xFF) &&
Packit Service 95ac19
    ((int)(unsigned char)0x100 == 0) && ((int)(unsigned char)(int)-1 == 0xFF));
Packit Service 95ac19
/* the next assertion is probably not really needed */
Packit Service 95ac19
cta(short_is_2_char, sizeof(short) == 2);
Packit Service 95ac19
cta(short_size_no_matter_of_signedness, sizeof(short) == sizeof(unsigned short));
Packit Service 95ac19
/* the next assertion is probably not really needed */
Packit Service 95ac19
cta(int_is_4_char, sizeof(int) == 4);
Packit Service 95ac19
cta(int_size_no_matter_of_signedness, sizeof(int) == sizeof(unsigned int));
Packit Service 95ac19
Packit Service 95ac19
cta(long_ge_int, sizeof(long) >= sizeof(int));
Packit Service 95ac19
cta(long_size_no_matter_of_signedness, sizeof(long) == sizeof(unsigned long));
Packit Service 95ac19
Packit Service 95ac19
#ifndef MKSH_LEGACY_MODE
Packit Service 95ac19
/* the next assertion is probably not really needed */
Packit Service 95ac19
cta(ari_is_4_char, sizeof(mksh_ari_t) == 4);
Packit Service 95ac19
/* but this is */
Packit Service 95ac19
cta(ari_has_31_bit, 0 < (mksh_ari_t)(((((mksh_ari_t)1 << 15) << 15) - 1) * 2 + 1));
Packit Service 95ac19
/* the next assertion is probably not really needed */
Packit Service 95ac19
cta(uari_is_4_char, sizeof(mksh_uari_t) == 4);
Packit Service 95ac19
/* but the next three are; we REQUIRE unsigned integer wraparound */
Packit Service 95ac19
cta(uari_has_31_bit, 0 < (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 2 + 1));
Packit Service 95ac19
cta(uari_has_32_bit, 0 < (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 3));
Packit Service 95ac19
cta(uari_wrap_32_bit,
Packit Service 95ac19
    (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 3) >
Packit Service 95ac19
    (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 4));
Packit Service 95ac19
#endif
Packit Service 95ac19
/* these are always required */
Packit Service 95ac19
cta(ari_is_signed, (mksh_ari_t)-1 < (mksh_ari_t)0);
Packit Service 95ac19
cta(uari_is_unsigned, (mksh_uari_t)-1 > (mksh_uari_t)0);
Packit Service 95ac19
/* we require these to have the precisely same size and assume 2s complement */
Packit Service 95ac19
cta(ari_size_no_matter_of_signedness, sizeof(mksh_ari_t) == sizeof(mksh_uari_t));
Packit Service 95ac19
Packit Service 95ac19
cta(sizet_size_no_matter_of_signedness, sizeof(ssize_t) == sizeof(size_t));
Packit Service 95ac19
cta(sizet_voidptr_same_size, sizeof(size_t) == sizeof(void *));
Packit Service 95ac19
cta(sizet_funcptr_same_size, sizeof(size_t) == sizeof(void (*)(void)));
Packit Service 95ac19
/* our formatting routines assume this */
Packit Service 95ac19
cta(ptr_fits_in_long, sizeof(size_t) <= sizeof(long));
Packit Service 95ac19
cta(ari_fits_in_long, sizeof(mksh_ari_t) <= sizeof(long));
Packit Service 95ac19
Packit Service 95ac19
static mksh_uari_t
Packit Service 95ac19
rndsetup(void)
Packit Service 95ac19
{
Packit Service 95ac19
	register uint32_t h;
Packit Service 95ac19
	struct {
Packit Service 95ac19
		ALLOC_ITEM alloc_INT;
Packit Service 95ac19
		void *dataptr, *stkptr, *mallocptr;
Packit Service 95ac19
#if defined(__GLIBC__) && (__GLIBC__ >= 2)
Packit Service 95ac19
		sigjmp_buf jbuf;
Packit Service 95ac19
#endif
Packit Service 95ac19
		struct timeval tv;
Packit Service 95ac19
	} *bufptr;
Packit Service 95ac19
	char *cp;
Packit Service 95ac19
Packit Service 95ac19
	cp = alloc(sizeof(*bufptr) - sizeof(ALLOC_ITEM), APERM);
Packit Service 95ac19
	/* clear the allocated space, for valgrind and to avoid UB */
Packit Service 95ac19
	memset(cp, 0, sizeof(*bufptr) - sizeof(ALLOC_ITEM));
Packit Service 95ac19
	/* undo what alloc() did to the malloc result address */
Packit Service 95ac19
	bufptr = (void *)(cp - sizeof(ALLOC_ITEM));
Packit Service 95ac19
	/* PIE or something similar provides us with deltas here */
Packit Service 95ac19
	bufptr->dataptr = &rndsetupstate;
Packit Service 95ac19
	/* ASLR in at least Windows, Linux, some BSDs */
Packit Service 95ac19
	bufptr->stkptr = &bufptr;
Packit Service 95ac19
	/* randomised malloc in BSD (and possibly others) */
Packit Service 95ac19
	bufptr->mallocptr = bufptr;
Packit Service 95ac19
#if defined(__GLIBC__) && (__GLIBC__ >= 2)
Packit Service 95ac19
	/* glibc pointer guard */
Packit Service 95ac19
	sigsetjmp(bufptr->jbuf, 1);
Packit Service 95ac19
#endif
Packit Service 95ac19
	/* introduce variation (and yes, second arg MBZ for portability) */
Packit Service 95ac19
	mksh_TIME(bufptr->tv);
Packit Service 95ac19
Packit Service 95ac19
#ifdef MKSH_ALLOC_CATCH_UNDERRUNS
Packit Service 95ac19
	mprotect(((char *)bufptr) + 4096, 4096, PROT_READ | PROT_WRITE);
Packit Service 95ac19
#endif
Packit Service 95ac19
	h = chvt_rndsetup(bufptr, sizeof(*bufptr));
Packit Service 95ac19
Packit Service 95ac19
	afree(cp, APERM);
Packit Service 95ac19
	return ((mksh_uari_t)h);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
chvt_reinit(void)
Packit Service 95ac19
{
Packit Service 95ac19
	kshpid = procpid = getpid();
Packit Service 95ac19
	ksheuid = geteuid();
Packit Service 95ac19
	kshpgrp = getpgrp();
Packit Service 95ac19
	kshppid = getppid();
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
static const char *empty_argv[] = {
Packit Service 95ac19
	Tmksh, NULL
Packit Service 95ac19
};
Packit Service 95ac19
Packit Service 95ac19
static uint8_t
Packit Service 95ac19
isuc(const char *cx) {
Packit Service 95ac19
	char *cp, *x;
Packit Service 95ac19
	uint8_t rv = 0;
Packit Service 95ac19
Packit Service 95ac19
	if (!cx || !*cx)
Packit Service 95ac19
		return (0);
Packit Service 95ac19
Packit Service 95ac19
	/* uppercase a string duplicate */
Packit Service 95ac19
	strdupx(x, cx, ATEMP);
Packit Service 95ac19
	cp = x;
Packit Service 95ac19
	while ((*cp = ksh_toupper(*cp)))
Packit Service 95ac19
		++cp;
Packit Service 95ac19
Packit Service 95ac19
	/* check for UTF-8 */
Packit Service 95ac19
	if (strstr(x, "UTF-8") || strstr(x, "UTF8"))
Packit Service 95ac19
		rv = 1;
Packit Service 95ac19
Packit Service 95ac19
	/* free copy and out */
Packit Service 95ac19
	afree(x, ATEMP);
Packit Service 95ac19
	return (rv);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
static int
Packit Service 95ac19
main_init(int argc, const char *argv[], Source **sp, struct block **lp)
Packit Service 95ac19
{
Packit Service 95ac19
	int argi, i;
Packit Service 95ac19
	Source *s = NULL;
Packit Service 95ac19
	struct block *l;
Packit Service 95ac19
	unsigned char restricted_shell, errexit, utf_flag;
Packit Service 95ac19
	char *cp;
Packit Service 95ac19
	const char *ccp, **wp;
Packit Service 95ac19
	struct tbl *vp;
Packit Service 95ac19
	struct stat s_stdin;
Packit Service 95ac19
#if !defined(_PATH_DEFPATH) && defined(_CS_PATH)
Packit Service 95ac19
	ssize_t k;
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
#if defined(MKSH_EBCDIC) || defined(MKSH_FAUX_EBCDIC)
Packit Service 95ac19
	ebcdic_init();
Packit Service 95ac19
#endif
Packit Service 95ac19
	set_ifs(TC_IFSWS);
Packit Service 95ac19
Packit Service 95ac19
#ifdef __OS2__
Packit Service 95ac19
	os2_init(&argc, &argv);
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
	/* do things like getpgrp() et al. */
Packit Service 95ac19
	chvt_reinit();
Packit Service 95ac19
Packit Service 95ac19
	/* make sure argv[] is sane, for weird OSes */
Packit Service 95ac19
	if (!*argv) {
Packit Service 95ac19
		argv = empty_argv;
Packit Service 95ac19
		argc = 1;
Packit Service 95ac19
	}
Packit Service 95ac19
	kshname = argv[0];
Packit Service 95ac19
Packit Service 95ac19
	/* initialise permanent Area */
Packit Service 95ac19
	ainit(&aperm);
Packit Service 95ac19
	/* max. name length: -2147483648 = 11 (+ NUL) */
Packit Service 95ac19
	vtemp = alloc(offsetof(struct tbl, name[0]) + 12, APERM);
Packit Service 95ac19
Packit Service 95ac19
	/* set up base environment */
Packit Service 95ac19
	env.type = E_NONE;
Packit Service 95ac19
	ainit(&env.area);
Packit Service 95ac19
	/* set up global l->vars and l->funs */
Packit Service 95ac19
	newblock();
Packit Service 95ac19
Packit Service 95ac19
	/* Do this first so output routines (eg, errorf, shellf) can work */
Packit Service 95ac19
	initio();
Packit Service 95ac19
Packit Service 95ac19
	/* determine the basename (without '-' or path) of the executable */
Packit Service 95ac19
	ccp = kshname;
Packit Service 95ac19
	goto begin_parsing_kshname;
Packit Service 95ac19
	while ((i = ccp[argi++])) {
Packit Service 95ac19
		if (mksh_cdirsep(i)) {
Packit Service 95ac19
			ccp += argi;
Packit Service 95ac19
 begin_parsing_kshname:
Packit Service 95ac19
			argi = 0;
Packit Service 95ac19
			if (*ccp == '-')
Packit Service 95ac19
				++ccp;
Packit Service 95ac19
		}
Packit Service 95ac19
	}
Packit Service 95ac19
	if (!*ccp)
Packit Service 95ac19
		ccp = empty_argv[0];
Packit Service 95ac19
Packit Service 95ac19
	/*
Packit Service 95ac19
	 * Turn on nohup by default. (AT&T ksh does not have a nohup
Packit Service 95ac19
	 * option - it always sends the hup).
Packit Service 95ac19
	 */
Packit Service 95ac19
	Flag(FNOHUP) = 1;
Packit Service 95ac19
Packit Service 95ac19
	/*
Packit Service 95ac19
	 * Turn on brace expansion by default. AT&T kshs that have
Packit Service 95ac19
	 * alternation always have it on.
Packit Service 95ac19
	 */
Packit Service 95ac19
	Flag(FBRACEEXPAND) = 1;
Packit Service 95ac19
Packit Service 95ac19
	/*
Packit Service 95ac19
	 * Turn on "set -x" inheritance by default.
Packit Service 95ac19
	 */
Packit Service 95ac19
	Flag(FXTRACEREC) = 1;
Packit Service 95ac19
Packit Service 95ac19
	/* define built-in commands and see if we were called as one */
Packit Service 95ac19
	ktinit(APERM, &builtins,
Packit Service 95ac19
	    /* currently up to 54 builtins: 75% of 128 = 2^7 */
Packit Service 95ac19
	    7);
Packit Service 95ac19
	for (i = 0; mkshbuiltins[i].name != NULL; i++)
Packit Service 95ac19
		if (!strcmp(ccp, builtin(mkshbuiltins[i].name,
Packit Service 95ac19
		    mkshbuiltins[i].func)))
Packit Service 95ac19
			Flag(FAS_BUILTIN) = 1;
Packit Service 95ac19
Packit Service 95ac19
	if (!Flag(FAS_BUILTIN)) {
Packit Service 95ac19
		/* check for -T option early */
Packit Service 95ac19
		argi = parse_args(argv, OF_FIRSTTIME, NULL);
Packit Service 95ac19
		if (argi < 0)
Packit Service 95ac19
			return (1);
Packit Service 95ac19
Packit Service 95ac19
#if defined(MKSH_BINSHPOSIX) || defined(MKSH_BINSHREDUCED)
Packit Service 95ac19
		/* are we called as -sh or /bin/sh or so? */
Packit Service 95ac19
		if (!strcmp(ccp, "sh" MKSH_EXE_EXT)) {
Packit Service 95ac19
			/* either also turns off braceexpand */
Packit Service 95ac19
#ifdef MKSH_BINSHPOSIX
Packit Service 95ac19
			/* enable better POSIX conformance */
Packit Service 95ac19
			change_flag(FPOSIX, OF_FIRSTTIME, true);
Packit Service 95ac19
#endif
Packit Service 95ac19
#ifdef MKSH_BINSHREDUCED
Packit Service 95ac19
			/* enable kludge/compat mode */
Packit Service 95ac19
			change_flag(FSH, OF_FIRSTTIME, true);
Packit Service 95ac19
#endif
Packit Service 95ac19
		}
Packit Service 95ac19
#endif
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	initvar();
Packit Service 95ac19
Packit Service 95ac19
	inittraps();
Packit Service 95ac19
Packit Service 95ac19
	coproc_init();
Packit Service 95ac19
Packit Service 95ac19
	/* set up variable and command dictionaries */
Packit Service 95ac19
	ktinit(APERM, &taliases, 0);
Packit Service 95ac19
	ktinit(APERM, &aliases, 0);
Packit Service 95ac19
#ifndef MKSH_NOPWNAM
Packit Service 95ac19
	ktinit(APERM, &homedirs, 0);
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
	/* define shell keywords */
Packit Service 95ac19
	initkeywords();
Packit Service 95ac19
Packit Service 95ac19
	init_histvec();
Packit Service 95ac19
Packit Service 95ac19
	/* initialise tty size before importing environment */
Packit Service 95ac19
	change_winsz();
Packit Service 95ac19
Packit Service 95ac19
#ifdef _PATH_DEFPATH
Packit Service 95ac19
	def_path = _PATH_DEFPATH;
Packit Service 95ac19
#else
Packit Service 95ac19
#ifdef _CS_PATH
Packit Service 95ac19
	if ((k = confstr(_CS_PATH, NULL, 0)) > 0 &&
Packit Service 95ac19
	    confstr(_CS_PATH, cp = alloc(k + 1, APERM), k + 1) == k + 1)
Packit Service 95ac19
		def_path = cp;
Packit Service 95ac19
	else
Packit Service 95ac19
#endif
Packit Service 95ac19
		/*
Packit Service 95ac19
		 * this is uniform across all OSes unless it
Packit Service 95ac19
		 * breaks somewhere hard; don't try to optimise,
Packit Service 95ac19
		 * e.g. add stuff for Interix or remove /usr
Packit Service 95ac19
		 * for HURD, because e.g. Debian GNU/HURD is
Packit Service 95ac19
		 * "keeping a regular /usr"; this is supposed
Packit Service 95ac19
		 * to be a sane 'basic' default PATH
Packit Service 95ac19
		 */
Packit Service 95ac19
		def_path = MKSH_UNIXROOT "/bin" MKSH_PATHSEPS
Packit Service 95ac19
		    MKSH_UNIXROOT "/usr/bin" MKSH_PATHSEPS
Packit Service 95ac19
		    MKSH_UNIXROOT "/sbin" MKSH_PATHSEPS
Packit Service 95ac19
		    MKSH_UNIXROOT "/usr/sbin";
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
	/*
Packit Service 95ac19
	 * Set PATH to def_path (will set the path global variable).
Packit Service 95ac19
	 * (import of environment below will probably change this setting).
Packit Service 95ac19
	 */
Packit Service 95ac19
	vp = global(TPATH);
Packit Service 95ac19
	/* setstr can't fail here */
Packit Service 95ac19
	setstr(vp, def_path, KSH_RETURN_ERROR);
Packit Service 95ac19
Packit Service 95ac19
#ifndef MKSH_NO_CMDLINE_EDITING
Packit Service 95ac19
	/*
Packit Service 95ac19
	 * Set edit mode to emacs by default, may be overridden
Packit Service 95ac19
	 * by the environment or the user. Also, we want tab completion
Packit Service 95ac19
	 * on in vi by default.
Packit Service 95ac19
	 */
Packit Service 95ac19
	change_flag(FEMACS, OF_SPECIAL, true);
Packit Service 95ac19
#if !MKSH_S_NOVI
Packit Service 95ac19
	Flag(FVITABCOMPLETE) = 1;
Packit Service 95ac19
#endif
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
	/* import environment */
Packit Service 95ac19
	init_environ();
Packit Service 95ac19
Packit Service 95ac19
	/* for security */
Packit Service 95ac19
	typeset(TinitIFS, 0, 0, 0, 0);
Packit Service 95ac19
Packit Service 95ac19
	/* assign default shell variable values */
Packit Service 95ac19
	typeset("PATHSEP=" MKSH_PATHSEPS, 0, 0, 0, 0);
Packit Service 95ac19
	substitute(initsubs, 0);
Packit Service 95ac19
Packit Service 95ac19
	/* Figure out the current working directory and set $PWD */
Packit Service 95ac19
	vp = global(TPWD);
Packit Service 95ac19
	cp = str_val(vp);
Packit Service 95ac19
	/* Try to use existing $PWD if it is valid */
Packit Service 95ac19
	set_current_wd((mksh_abspath(cp) && test_eval(NULL, TO_FILEQ, cp,
Packit Service 95ac19
	    Tdot, true)) ? cp : NULL);
Packit Service 95ac19
	if (current_wd[0])
Packit Service 95ac19
		simplify_path(current_wd);
Packit Service 95ac19
	/* Only set pwd if we know where we are or if it had a bogus value */
Packit Service 95ac19
	if (current_wd[0] || *cp)
Packit Service 95ac19
		/* setstr can't fail here */
Packit Service 95ac19
		setstr(vp, current_wd, KSH_RETURN_ERROR);
Packit Service 95ac19
Packit Service 95ac19
	for (wp = initcoms; *wp != NULL; wp++) {
Packit Service 95ac19
		c_builtin(wp);
Packit Service 95ac19
		while (*wp != NULL)
Packit Service 95ac19
			wp++;
Packit Service 95ac19
	}
Packit Service 95ac19
	setint_n(global("OPTIND"), 1, 10);
Packit Service 95ac19
Packit Service 95ac19
	kshuid = getuid();
Packit Service 95ac19
	kshgid = getgid();
Packit Service 95ac19
	kshegid = getegid();
Packit Service 95ac19
Packit Service 95ac19
	safe_prompt = ksheuid ? "$ " : "# ";
Packit Service 95ac19
	vp = global("PS1");
Packit Service 95ac19
	/* Set PS1 if unset or we are root and prompt doesn't contain a # */
Packit Service 95ac19
	if (!(vp->flag & ISSET) ||
Packit Service 95ac19
	    (!ksheuid && !strchr(str_val(vp), '#')))
Packit Service 95ac19
		/* setstr can't fail here */
Packit Service 95ac19
		setstr(vp, safe_prompt, KSH_RETURN_ERROR);
Packit Service 95ac19
	setint_n((vp = global("BASHPID")), 0, 10);
Packit Service 95ac19
	vp->flag |= INT_U;
Packit Service 95ac19
	setint_n((vp = global("PGRP")), (mksh_uari_t)kshpgrp, 10);
Packit Service 95ac19
	vp->flag |= INT_U;
Packit Service 95ac19
	setint_n((vp = global("PPID")), (mksh_uari_t)kshppid, 10);
Packit Service 95ac19
	vp->flag |= INT_U;
Packit Service 95ac19
	setint_n((vp = global("USER_ID")), (mksh_uari_t)ksheuid, 10);
Packit Service 95ac19
	vp->flag |= INT_U;
Packit Service 95ac19
	setint_n((vp = global("KSHUID")), (mksh_uari_t)kshuid, 10);
Packit Service 95ac19
	vp->flag |= INT_U;
Packit Service 95ac19
	setint_n((vp = global("KSHEGID")), (mksh_uari_t)kshegid, 10);
Packit Service 95ac19
	vp->flag |= INT_U;
Packit Service 95ac19
	setint_n((vp = global("KSHGID")), (mksh_uari_t)kshgid, 10);
Packit Service 95ac19
	vp->flag |= INT_U;
Packit Service 95ac19
	setint_n((vp = global("RANDOM")), rndsetup(), 10);
Packit Service 95ac19
	vp->flag |= INT_U;
Packit Service 95ac19
	setint_n((vp_pipest = global("PIPESTATUS")), 0, 10);
Packit Service 95ac19
Packit Service 95ac19
	/* Set this before parsing arguments */
Packit Service 95ac19
	Flag(FPRIVILEGED) = (kshuid != ksheuid || kshgid != kshegid) ? 2 : 0;
Packit Service 95ac19
Packit Service 95ac19
	/* this to note if monitor is set on command line (see below) */
Packit Service 95ac19
#ifndef MKSH_UNEMPLOYED
Packit Service 95ac19
	Flag(FMONITOR) = 127;
Packit Service 95ac19
#endif
Packit Service 95ac19
	/* this to note if utf-8 mode is set on command line (see below) */
Packit Service 95ac19
	UTFMODE = 2;
Packit Service 95ac19
Packit Service 95ac19
	if (!Flag(FAS_BUILTIN)) {
Packit Service 95ac19
		argi = parse_args(argv, OF_CMDLINE, NULL);
Packit Service 95ac19
		if (argi < 0)
Packit Service 95ac19
			return (1);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	/* process this later only, default to off (hysterical raisins) */
Packit Service 95ac19
	utf_flag = UTFMODE;
Packit Service 95ac19
	UTFMODE = 0;
Packit Service 95ac19
Packit Service 95ac19
	if (Flag(FAS_BUILTIN)) {
Packit Service 95ac19
		/* auto-detect from environment variables, always */
Packit Service 95ac19
		utf_flag = 3;
Packit Service 95ac19
	} else if (Flag(FCOMMAND)) {
Packit Service 95ac19
		s = pushs(SSTRINGCMDLINE, ATEMP);
Packit Service 95ac19
		if (!(s->start = s->str = argv[argi++]))
Packit Service 95ac19
			errorf(Tf_optfoo, "", "", 'c', Treq_arg);
Packit Service 95ac19
		while (*s->str) {
Packit Service 95ac19
			if (ctype(*s->str, C_QUOTE))
Packit Service 95ac19
				break;
Packit Service 95ac19
			s->str++;
Packit Service 95ac19
		}
Packit Service 95ac19
		if (!*s->str)
Packit Service 95ac19
			s->flags |= SF_MAYEXEC;
Packit Service 95ac19
		s->str = s->start;
Packit Service 95ac19
#ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT
Packit Service 95ac19
		/* compatibility to MidnightBSD 0.1 /bin/sh (kludge) */
Packit Service 95ac19
		if (Flag(FSH) && argv[argi] && !strcmp(argv[argi], "--"))
Packit Service 95ac19
			++argi;
Packit Service 95ac19
#endif
Packit Service 95ac19
		if (argv[argi])
Packit Service 95ac19
			kshname = argv[argi++];
Packit Service 95ac19
	} else if (argi < argc && !Flag(FSTDIN)) {
Packit Service 95ac19
		s = pushs(SFILE, ATEMP);
Packit Service 95ac19
#ifdef __OS2__
Packit Service 95ac19
		/*
Packit Service 95ac19
		 * A bug in OS/2 extproc (like shebang) handling makes
Packit Service 95ac19
		 * it not pass the full pathname of a script, so we need
Packit Service 95ac19
		 * to search for it. This changes the behaviour of a
Packit Service 95ac19
		 * simple "mksh foo", but can't be helped.
Packit Service 95ac19
		 */
Packit Service 95ac19
		s->file = argv[argi++];
Packit Service 95ac19
		if (search_access(s->file, X_OK) != 0)
Packit Service 95ac19
			s->file = search_path(s->file, path, X_OK, NULL);
Packit Service 95ac19
		if (!s->file || !*s->file)
Packit Service 95ac19
			s->file = argv[argi - 1];
Packit Service 95ac19
#else
Packit Service 95ac19
		s->file = argv[argi++];
Packit Service 95ac19
#endif
Packit Service 95ac19
		s->u.shf = shf_open(s->file, O_RDONLY, 0,
Packit Service 95ac19
		    SHF_MAPHI | SHF_CLEXEC);
Packit Service 95ac19
		if (s->u.shf == NULL) {
Packit Service 95ac19
			shl_stdout_ok = false;
Packit Service 95ac19
			warningf(true, Tf_sD_s, s->file, cstrerror(errno));
Packit Service 95ac19
			/* mandated by SUSv4 */
Packit Service 95ac19
			exstat = 127;
Packit Service 95ac19
			unwind(LERROR);
Packit Service 95ac19
		}
Packit Service 95ac19
		kshname = s->file;
Packit Service 95ac19
	} else {
Packit Service 95ac19
		Flag(FSTDIN) = 1;
Packit Service 95ac19
		s = pushs(SSTDIN, ATEMP);
Packit Service 95ac19
		s->file = "<stdin>";
Packit Service 95ac19
		s->u.shf = shf_fdopen(0, SHF_RD | can_seek(0),
Packit Service 95ac19
		    NULL);
Packit Service 95ac19
		if (isatty(0) && isatty(2)) {
Packit Service 95ac19
			Flag(FTALKING) = Flag(FTALKING_I) = 1;
Packit Service 95ac19
			/* The following only if isatty(0) */
Packit Service 95ac19
			s->flags |= SF_TTY;
Packit Service 95ac19
			s->u.shf->flags |= SHF_INTERRUPT;
Packit Service 95ac19
			s->file = NULL;
Packit Service 95ac19
		}
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	/* this bizarreness is mandated by POSIX */
Packit Service 95ac19
	if (fstat(0, &s_stdin) >= 0 && S_ISCHR(s_stdin.st_mode) &&
Packit Service 95ac19
	    Flag(FTALKING))
Packit Service 95ac19
		reset_nonblock(0);
Packit Service 95ac19
Packit Service 95ac19
	/* initialise job control */
Packit Service 95ac19
	j_init();
Packit Service 95ac19
	/* do this after j_init() which calls tty_init_state() */
Packit Service 95ac19
	if (Flag(FTALKING)) {
Packit Service 95ac19
		if (utf_flag == 2) {
Packit Service 95ac19
#ifndef MKSH_ASSUME_UTF8
Packit Service 95ac19
			/* auto-detect from locale or environment */
Packit Service 95ac19
			utf_flag = 4;
Packit Service 95ac19
#else /* this may not be an #elif */
Packit Service 95ac19
#if MKSH_ASSUME_UTF8
Packit Service 95ac19
			utf_flag = 1;
Packit Service 95ac19
#else
Packit Service 95ac19
			/* always disable UTF-8 (for interactive) */
Packit Service 95ac19
			utf_flag = 0;
Packit Service 95ac19
#endif
Packit Service 95ac19
#endif
Packit Service 95ac19
		}
Packit Service 95ac19
#ifndef MKSH_NO_CMDLINE_EDITING
Packit Service 95ac19
		x_init();
Packit Service 95ac19
#endif
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
#ifdef SIGWINCH
Packit Service 95ac19
	sigtraps[SIGWINCH].flags |= TF_SHELL_USES;
Packit Service 95ac19
	setsig(&sigtraps[SIGWINCH], x_sigwinch,
Packit Service 95ac19
	    SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP);
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
	l = e->loc;
Packit Service 95ac19
	if (Flag(FAS_BUILTIN)) {
Packit Service 95ac19
		l->argc = argc;
Packit Service 95ac19
		l->argv = argv;
Packit Service 95ac19
		l->argv[0] = ccp;
Packit Service 95ac19
	} else {
Packit Service 95ac19
		l->argc = argc - argi;
Packit Service 95ac19
		/*
Packit Service 95ac19
		 * allocate a new array because otherwise, when we modify
Packit Service 95ac19
		 * it in-place, ps(1) output changes; the meaning of argc
Packit Service 95ac19
		 * here is slightly different as it excludes kshname, and
Packit Service 95ac19
		 * we add a trailing NULL sentinel as well
Packit Service 95ac19
		 */
Packit Service 95ac19
		l->argv = alloc2(l->argc + 2, sizeof(void *), APERM);
Packit Service 95ac19
		l->argv[0] = kshname;
Packit Service 95ac19
		memcpy(&l->argv[1], &argv[argi], l->argc * sizeof(void *));
Packit Service 95ac19
		l->argv[l->argc + 1] = NULL;
Packit Service 95ac19
		getopts_reset(1);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	/* divine the initial state of the utf8-mode Flag */
Packit Service 95ac19
	ccp = null;
Packit Service 95ac19
	switch (utf_flag) {
Packit Service 95ac19
Packit Service 95ac19
	/* auto-detect from locale or environment */
Packit Service 95ac19
	case 4:
Packit Service 95ac19
#if HAVE_SETLOCALE_CTYPE
Packit Service 95ac19
		ccp = setlocale(LC_CTYPE, "");
Packit Service 95ac19
#if HAVE_LANGINFO_CODESET
Packit Service 95ac19
		if (!isuc(ccp))
Packit Service 95ac19
			ccp = nl_langinfo(CODESET);
Packit Service 95ac19
#endif
Packit Service 95ac19
		if (!isuc(ccp))
Packit Service 95ac19
			ccp = null;
Packit Service 95ac19
#endif
Packit Service 95ac19
		/* FALLTHROUGH */
Packit Service 95ac19
Packit Service 95ac19
	/* auto-detect from environment */
Packit Service 95ac19
	case 3:
Packit Service 95ac19
		/* these were imported from environ earlier */
Packit Service 95ac19
		if (ccp == null)
Packit Service 95ac19
			ccp = str_val(global("LC_ALL"));
Packit Service 95ac19
		if (ccp == null)
Packit Service 95ac19
			ccp = str_val(global("LC_CTYPE"));
Packit Service 95ac19
		if (ccp == null)
Packit Service 95ac19
			ccp = str_val(global("LANG"));
Packit Service 95ac19
		UTFMODE = isuc(ccp);
Packit Service 95ac19
		break;
Packit Service 95ac19
Packit Service 95ac19
	/* not set on command line, not FTALKING */
Packit Service 95ac19
	case 2:
Packit Service 95ac19
	/* unknown values */
Packit Service 95ac19
	default:
Packit Service 95ac19
		utf_flag = 0;
Packit Service 95ac19
		/* FALLTHROUGH */
Packit Service 95ac19
Packit Service 95ac19
	/* known values */
Packit Service 95ac19
	case 1:
Packit Service 95ac19
	case 0:
Packit Service 95ac19
		UTFMODE = utf_flag;
Packit Service 95ac19
		break;
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	/* Disable during .profile/ENV reading */
Packit Service 95ac19
	restricted_shell = Flag(FRESTRICTED);
Packit Service 95ac19
	Flag(FRESTRICTED) = 0;
Packit Service 95ac19
	errexit = Flag(FERREXIT);
Packit Service 95ac19
	Flag(FERREXIT) = 0;
Packit Service 95ac19
Packit Service 95ac19
	/*
Packit Service 95ac19
	 * Do this before profile/$ENV so that if it causes problems in them,
Packit Service 95ac19
	 * user will know why things broke.
Packit Service 95ac19
	 */
Packit Service 95ac19
	if (!current_wd[0] && Flag(FTALKING))
Packit Service 95ac19
		warningf(false, "can't determine current directory");
Packit Service 95ac19
Packit Service 95ac19
	if (Flag(FLOGIN))
Packit Service 95ac19
		include(MKSH_SYSTEM_PROFILE, 0, NULL, true);
Packit Service 95ac19
	if (!Flag(FPRIVILEGED)) {
Packit Service 95ac19
		if (Flag(FLOGIN))
Packit Service 95ac19
			include(substitute("$HOME/.profile", 0), 0, NULL, true);
Packit Service 95ac19
		if (Flag(FTALKING)) {
Packit Service 95ac19
			cp = substitute("${ENV:-" MKSHRC_PATH "}", DOTILDE);
Packit Service 95ac19
			if (cp[0] != '\0')
Packit Service 95ac19
				include(cp, 0, NULL, true);
Packit Service 95ac19
		}
Packit Service 95ac19
	} else {
Packit Service 95ac19
		include(MKSH_SUID_PROFILE, 0, NULL, true);
Packit Service 95ac19
		/* turn off -p if not set explicitly */
Packit Service 95ac19
		if (Flag(FPRIVILEGED) != 1)
Packit Service 95ac19
			change_flag(FPRIVILEGED, OF_INTERNAL, false);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	if (restricted_shell) {
Packit Service 95ac19
		c_builtin(restr_com);
Packit Service 95ac19
		/* After typeset command... */
Packit Service 95ac19
		Flag(FRESTRICTED) = 1;
Packit Service 95ac19
	}
Packit Service 95ac19
	Flag(FERREXIT) = errexit;
Packit Service 95ac19
Packit Service 95ac19
	if (Flag(FTALKING) && s)
Packit Service 95ac19
		hist_init(s);
Packit Service 95ac19
	else
Packit Service 95ac19
		/* set after ENV */
Packit Service 95ac19
		Flag(FTRACKALL) = 1;
Packit Service 95ac19
Packit Service 95ac19
	alarm_init();
Packit Service 95ac19
Packit Service 95ac19
	*sp = s;
Packit Service 95ac19
	*lp = l;
Packit Service 95ac19
	return (0);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* this indirection barrier reduces stack usage during normal operation */
Packit Service 95ac19
Packit Service 95ac19
int
Packit Service 95ac19
main(int argc, const char *argv[])
Packit Service 95ac19
{
Packit Service 95ac19
	int rv;
Packit Service 95ac19
	Source *s;
Packit Service 95ac19
	struct block *l;
Packit Service 95ac19
Packit Service 95ac19
	if ((rv = main_init(argc, argv, &s, &l)) == 0) {
Packit Service 95ac19
		if (Flag(FAS_BUILTIN)) {
Packit Service 95ac19
			rv = c_builtin(l->argv);
Packit Service 95ac19
		} else {
Packit Service 95ac19
			shell(s, 0);
Packit Service 95ac19
			/* NOTREACHED */
Packit Service 95ac19
		}
Packit Service 95ac19
	}
Packit Service 95ac19
	return (rv);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
int
Packit Service 95ac19
include(const char *name, int argc, const char **argv, bool intr_ok)
Packit Service 95ac19
{
Packit Service 95ac19
	Source *volatile s = NULL;
Packit Service 95ac19
	struct shf *shf;
Packit Service 95ac19
	const char **volatile old_argv;
Packit Service 95ac19
	volatile int old_argc;
Packit Service 95ac19
	int i;
Packit Service 95ac19
Packit Service 95ac19
	shf = shf_open(name, O_RDONLY, 0, SHF_MAPHI | SHF_CLEXEC);
Packit Service 95ac19
	if (shf == NULL)
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
Packit Service 95ac19
	if (argv) {
Packit Service 95ac19
		old_argv = e->loc->argv;
Packit Service 95ac19
		old_argc = e->loc->argc;
Packit Service 95ac19
	} else {
Packit Service 95ac19
		old_argv = NULL;
Packit Service 95ac19
		old_argc = 0;
Packit Service 95ac19
	}
Packit Service 95ac19
	newenv(E_INCL);
Packit Service 95ac19
	if ((i = kshsetjmp(e->jbuf))) {
Packit Service 95ac19
		quitenv(s ? s->u.shf : NULL);
Packit Service 95ac19
		if (old_argv) {
Packit Service 95ac19
			e->loc->argv = old_argv;
Packit Service 95ac19
			e->loc->argc = old_argc;
Packit Service 95ac19
		}
Packit Service 95ac19
		switch (i) {
Packit Service 95ac19
		case LRETURN:
Packit Service 95ac19
		case LERROR:
Packit Service 95ac19
			/* see below */
Packit Service 95ac19
			return (exstat & 0xFF);
Packit Service 95ac19
		case LINTR:
Packit Service 95ac19
			/*
Packit Service 95ac19
			 * intr_ok is set if we are including .profile or $ENV.
Packit Service 95ac19
			 * If user ^Cs out, we don't want to kill the shell...
Packit Service 95ac19
			 */
Packit Service 95ac19
			if (intr_ok && ((exstat & 0xFF) - 128) != SIGTERM)
Packit Service 95ac19
				return (1);
Packit Service 95ac19
			/* FALLTHROUGH */
Packit Service 95ac19
		case LEXIT:
Packit Service 95ac19
		case LLEAVE:
Packit Service 95ac19
		case LSHELL:
Packit Service 95ac19
			unwind(i);
Packit Service 95ac19
			/* NOTREACHED */
Packit Service 95ac19
		default:
Packit Service 95ac19
			internal_errorf(Tunexpected_type, Tunwind, Tsource, i);
Packit Service 95ac19
			/* NOTREACHED */
Packit Service 95ac19
		}
Packit Service 95ac19
	}
Packit Service 95ac19
	if (argv) {
Packit Service 95ac19
		e->loc->argv = argv;
Packit Service 95ac19
		e->loc->argc = argc;
Packit Service 95ac19
	}
Packit Service 95ac19
	s = pushs(SFILE, ATEMP);
Packit Service 95ac19
	s->u.shf = shf;
Packit Service 95ac19
	strdupx(s->file, name, ATEMP);
Packit Service 95ac19
	i = shell(s, 1);
Packit Service 95ac19
	quitenv(s->u.shf);
Packit Service 95ac19
	if (old_argv) {
Packit Service 95ac19
		e->loc->argv = old_argv;
Packit Service 95ac19
		e->loc->argc = old_argc;
Packit Service 95ac19
	}
Packit Service 95ac19
	/* & 0xff to ensure value not -1 */
Packit Service 95ac19
	return (i & 0xFF);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* spawn a command into a shell optionally keeping track of the line number */
Packit Service 95ac19
int
Packit Service 95ac19
command(const char *comm, int line)
Packit Service 95ac19
{
Packit Service 95ac19
	Source *s, *sold = source;
Packit Service 95ac19
	int rv;
Packit Service 95ac19
Packit Service 95ac19
	s = pushs(SSTRING, ATEMP);
Packit Service 95ac19
	s->start = s->str = comm;
Packit Service 95ac19
	s->line = line;
Packit Service 95ac19
	rv = shell(s, 1);
Packit Service 95ac19
	source = sold;
Packit Service 95ac19
	return (rv);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * run the commands from the input source, returning status.
Packit Service 95ac19
 */
Packit Service 95ac19
int
Packit Service 95ac19
shell(Source * volatile s, volatile int level)
Packit Service 95ac19
{
Packit Service 95ac19
	struct op *t;
Packit Service 95ac19
	volatile bool wastty = tobool(s->flags & SF_TTY);
Packit Service 95ac19
	volatile uint8_t attempts = 13;
Packit Service 95ac19
	volatile bool interactive = (level == 0) && Flag(FTALKING);
Packit Service 95ac19
	volatile bool sfirst = true;
Packit Service 95ac19
	Source *volatile old_source = source;
Packit Service 95ac19
	int i;
Packit Service 95ac19
Packit Service 95ac19
	newenv(level == 2 ? E_EVAL : E_PARSE);
Packit Service 95ac19
	if (interactive)
Packit Service 95ac19
		really_exit = false;
Packit Service 95ac19
	switch ((i = kshsetjmp(e->jbuf))) {
Packit Service 95ac19
	case 0:
Packit Service 95ac19
		break;
Packit Service 95ac19
	case LBREAK:
Packit Service 95ac19
	case LCONTIN:
Packit Service 95ac19
		if (level != 2) {
Packit Service 95ac19
			source = old_source;
Packit Service 95ac19
			quitenv(NULL);
Packit Service 95ac19
			internal_errorf(Tf_cant_s, Tshell,
Packit Service 95ac19
			    i == LBREAK ? Tbreak : Tcontinue);
Packit Service 95ac19
			/* NOTREACHED */
Packit Service 95ac19
		}
Packit Service 95ac19
		/* assert: interactive == false */
Packit Service 95ac19
		/* FALLTHROUGH */
Packit Service 95ac19
	case LINTR:
Packit Service 95ac19
		/* we get here if SIGINT not caught or ignored */
Packit Service 95ac19
	case LERROR:
Packit Service 95ac19
	case LSHELL:
Packit Service 95ac19
		if (interactive) {
Packit Service 95ac19
			if (i == LINTR)
Packit Service 95ac19
				shellf("\n");
Packit Service 95ac19
			/*
Packit Service 95ac19
			 * Reset any eof that was read as part of a
Packit Service 95ac19
			 * multiline command.
Packit Service 95ac19
			 */
Packit Service 95ac19
			if (Flag(FIGNOREEOF) && s->type == SEOF && wastty)
Packit Service 95ac19
				s->type = SSTDIN;
Packit Service 95ac19
			/*
Packit Service 95ac19
			 * Used by exit command to get back to
Packit Service 95ac19
			 * top level shell. Kind of strange since
Packit Service 95ac19
			 * interactive is set if we are reading from
Packit Service 95ac19
			 * a tty, but to have stopped jobs, one only
Packit Service 95ac19
			 * needs FMONITOR set (not FTALKING/SF_TTY)...
Packit Service 95ac19
			 */
Packit Service 95ac19
			/* toss any input we have so far */
Packit Service 95ac19
			yyrecursive_pop(true);
Packit Service 95ac19
			s->start = s->str = null;
Packit Service 95ac19
			retrace_info = NULL;
Packit Service 95ac19
			herep = heres;
Packit Service 95ac19
			break;
Packit Service 95ac19
		}
Packit Service 95ac19
		/* FALLTHROUGH */
Packit Service 95ac19
	case LEXIT:
Packit Service 95ac19
	case LLEAVE:
Packit Service 95ac19
	case LRETURN:
Packit Service 95ac19
		source = old_source;
Packit Service 95ac19
		quitenv(NULL);
Packit Service 95ac19
		/* keep on going */
Packit Service 95ac19
		unwind(i);
Packit Service 95ac19
		/* NOTREACHED */
Packit Service 95ac19
	default:
Packit Service 95ac19
		source = old_source;
Packit Service 95ac19
		quitenv(NULL);
Packit Service 95ac19
		internal_errorf(Tunexpected_type, Tunwind, Tshell, i);
Packit Service 95ac19
		/* NOTREACHED */
Packit Service 95ac19
	}
Packit Service 95ac19
	while (/* CONSTCOND */ 1) {
Packit Service 95ac19
		if (trap)
Packit Service 95ac19
			runtraps(0);
Packit Service 95ac19
Packit Service 95ac19
		if (s->next == NULL) {
Packit Service 95ac19
			if (Flag(FVERBOSE))
Packit Service 95ac19
				s->flags |= SF_ECHO;
Packit Service 95ac19
			else
Packit Service 95ac19
				s->flags &= ~SF_ECHO;
Packit Service 95ac19
		}
Packit Service 95ac19
		if (interactive) {
Packit Service 95ac19
			j_notify();
Packit Service 95ac19
			set_prompt(PS1, s);
Packit Service 95ac19
		}
Packit Service 95ac19
		t = compile(s, sfirst, true);
Packit Service 95ac19
		if (interactive)
Packit Service 95ac19
			histsave(&s->line, NULL, HIST_FLUSH, true);
Packit Service 95ac19
		sfirst = false;
Packit Service 95ac19
		if (!t)
Packit Service 95ac19
			goto source_no_tree;
Packit Service 95ac19
		if (t->type == TEOF) {
Packit Service 95ac19
			if (wastty && Flag(FIGNOREEOF) && --attempts > 0) {
Packit Service 95ac19
				shellf("Use 'exit' to leave mksh\n");
Packit Service 95ac19
				s->type = SSTDIN;
Packit Service 95ac19
			} else if (wastty && !really_exit &&
Packit Service 95ac19
			    j_stopped_running()) {
Packit Service 95ac19
				really_exit = true;
Packit Service 95ac19
				s->type = SSTDIN;
Packit Service 95ac19
			} else {
Packit Service 95ac19
				/*
Packit Service 95ac19
				 * this for POSIX which says EXIT traps
Packit Service 95ac19
				 * shall be taken in the environment
Packit Service 95ac19
				 * immediately after the last command
Packit Service 95ac19
				 * executed.
Packit Service 95ac19
				 */
Packit Service 95ac19
				if (level == 0)
Packit Service 95ac19
					unwind(LEXIT);
Packit Service 95ac19
				break;
Packit Service 95ac19
			}
Packit Service 95ac19
		} else if ((s->flags & SF_MAYEXEC) && t->type == TCOM)
Packit Service 95ac19
			t->u.evalflags |= DOTCOMEXEC;
Packit Service 95ac19
		if (!Flag(FNOEXEC) || (s->flags & SF_TTY))
Packit Service 95ac19
			exstat = execute(t, 0, NULL) & 0xFF;
Packit Service 95ac19
Packit Service 95ac19
		if (t->type != TEOF && interactive && really_exit)
Packit Service 95ac19
			really_exit = false;
Packit Service 95ac19
Packit Service 95ac19
 source_no_tree:
Packit Service 95ac19
		reclaim();
Packit Service 95ac19
	}
Packit Service 95ac19
	quitenv(NULL);
Packit Service 95ac19
	source = old_source;
Packit Service 95ac19
	return (exstat & 0xFF);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* return to closest error handler or shell(), exit if none found */
Packit Service 95ac19
/* note: i MUST NOT be 0 */
Packit Service 95ac19
void
Packit Service 95ac19
unwind(int i)
Packit Service 95ac19
{
Packit Service 95ac19
	/*
Packit Service 95ac19
	 * This is a kludge. We need to restore everything that was
Packit Service 95ac19
	 * changed in the new environment, see cid 1005090337C7A669439
Packit Service 95ac19
	 * and 10050903386452ACBF1, but fail to even save things most of
Packit Service 95ac19
	 * the time. funcs.c:c_eval() changes FERREXIT temporarily to 0,
Packit Service 95ac19
	 * which needs to be restored thus (related to Debian #696823).
Packit Service 95ac19
	 * We did not save the shell flags, so we use a special or'd
Packit Service 95ac19
	 * value here... this is mostly to clean up behind *other*
Packit Service 95ac19
	 * callers of unwind(LERROR) here; exec.c has the regular case.
Packit Service 95ac19
	 */
Packit Service 95ac19
	if (Flag(FERREXIT) & 0x80) {
Packit Service 95ac19
		/* GNU bash does not run this trapsig */
Packit Service 95ac19
		trapsig(ksh_SIGERR);
Packit Service 95ac19
		Flag(FERREXIT) &= ~0x80;
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	/* ordering for EXIT vs ERR is a bit odd (this is what AT&T ksh does) */
Packit Service 95ac19
	if (i == LEXIT || ((i == LERROR || i == LINTR) &&
Packit Service 95ac19
	    sigtraps[ksh_SIGEXIT].trap &&
Packit Service 95ac19
	    (!Flag(FTALKING) || Flag(FERREXIT)))) {
Packit Service 95ac19
		++trap_nested;
Packit Service 95ac19
		runtrap(&sigtraps[ksh_SIGEXIT], trap_nested == 1);
Packit Service 95ac19
		--trap_nested;
Packit Service 95ac19
		i = LLEAVE;
Packit Service 95ac19
	} else if (Flag(FERREXIT) == 1 && (i == LERROR || i == LINTR)) {
Packit Service 95ac19
		++trap_nested;
Packit Service 95ac19
		runtrap(&sigtraps[ksh_SIGERR], trap_nested == 1);
Packit Service 95ac19
		--trap_nested;
Packit Service 95ac19
		i = LLEAVE;
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	while (/* CONSTCOND */ 1) {
Packit Service 95ac19
		switch (e->type) {
Packit Service 95ac19
		case E_PARSE:
Packit Service 95ac19
		case E_FUNC:
Packit Service 95ac19
		case E_INCL:
Packit Service 95ac19
		case E_LOOP:
Packit Service 95ac19
		case E_ERRH:
Packit Service 95ac19
		case E_EVAL:
Packit Service 95ac19
			kshlongjmp(e->jbuf, i);
Packit Service 95ac19
			/* NOTREACHED */
Packit Service 95ac19
		case E_NONE:
Packit Service 95ac19
			if (i == LINTR)
Packit Service 95ac19
				e->flags |= EF_FAKE_SIGDIE;
Packit Service 95ac19
			/* FALLTHROUGH */
Packit Service 95ac19
		default:
Packit Service 95ac19
			quitenv(NULL);
Packit Service 95ac19
		}
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
newenv(int type)
Packit Service 95ac19
{
Packit Service 95ac19
	struct env *ep;
Packit Service 95ac19
	char *cp;
Packit Service 95ac19
Packit Service 95ac19
	/*
Packit Service 95ac19
	 * struct env includes ALLOC_ITEM for alignment constraints
Packit Service 95ac19
	 * so first get the actually used memory, then assign it
Packit Service 95ac19
	 */
Packit Service 95ac19
	cp = alloc(sizeof(struct env) - sizeof(ALLOC_ITEM), ATEMP);
Packit Service 95ac19
	/* undo what alloc() did to the malloc result address */
Packit Service 95ac19
	ep = (void *)(cp - sizeof(ALLOC_ITEM));
Packit Service 95ac19
	/* initialise public members of struct env (not the ALLOC_ITEM) */
Packit Service 95ac19
	ainit(&ep->area);
Packit Service 95ac19
	ep->oenv = e;
Packit Service 95ac19
	ep->loc = e->loc;
Packit Service 95ac19
	ep->savefd = NULL;
Packit Service 95ac19
	ep->temps = NULL;
Packit Service 95ac19
	ep->yyrecursive_statep = NULL;
Packit Service 95ac19
	ep->type = type;
Packit Service 95ac19
	ep->flags = 0;
Packit Service 95ac19
	/* jump buffer is invalid because flags == 0 */
Packit Service 95ac19
	e = ep;
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
quitenv(struct shf *shf)
Packit Service 95ac19
{
Packit Service 95ac19
	struct env *ep = e;
Packit Service 95ac19
	char *cp;
Packit Service 95ac19
	int fd;
Packit Service 95ac19
Packit Service 95ac19
	yyrecursive_pop(true);
Packit Service 95ac19
	while (ep->oenv && ep->oenv->loc != ep->loc)
Packit Service 95ac19
		popblock();
Packit Service 95ac19
	if (ep->savefd != NULL) {
Packit Service 95ac19
		for (fd = 0; fd < NUFILE; fd++)
Packit Service 95ac19
			/* if ep->savefd[fd] < 0, means fd was closed */
Packit Service 95ac19
			if (ep->savefd[fd])
Packit Service 95ac19
				restfd(fd, ep->savefd[fd]);
Packit Service 95ac19
		if (ep->savefd[2])
Packit Service 95ac19
			/* Clear any write errors */
Packit Service 95ac19
			shf_reopen(2, SHF_WR, shl_out);
Packit Service 95ac19
	}
Packit Service 95ac19
	/*
Packit Service 95ac19
	 * Bottom of the stack.
Packit Service 95ac19
	 * Either main shell is exiting or cleanup_parents_env() was called.
Packit Service 95ac19
	 */
Packit Service 95ac19
	if (ep->oenv == NULL) {
Packit Service 95ac19
#ifdef DEBUG_LEAKS
Packit Service 95ac19
		int i;
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
		if (ep->type == E_NONE) {
Packit Service 95ac19
			/* Main shell exiting? */
Packit Service 95ac19
#if HAVE_PERSISTENT_HISTORY
Packit Service 95ac19
			if (Flag(FTALKING))
Packit Service 95ac19
				hist_finish();
Packit Service 95ac19
#endif
Packit Service 95ac19
			j_exit();
Packit Service 95ac19
			if (ep->flags & EF_FAKE_SIGDIE) {
Packit Service 95ac19
				int sig = (exstat & 0xFF) - 128;
Packit Service 95ac19
Packit Service 95ac19
				/*
Packit Service 95ac19
				 * ham up our death a bit (AT&T ksh
Packit Service 95ac19
				 * only seems to do this for SIGTERM)
Packit Service 95ac19
				 * Don't do it for SIGQUIT, since we'd
Packit Service 95ac19
				 * dump a core..
Packit Service 95ac19
				 */
Packit Service 95ac19
				if ((sig == SIGINT || sig == SIGTERM) &&
Packit Service 95ac19
				    (kshpgrp == kshpid)) {
Packit Service 95ac19
					setsig(&sigtraps[sig], SIG_DFL,
Packit Service 95ac19
					    SS_RESTORE_CURR | SS_FORCE);
Packit Service 95ac19
					kill(0, sig);
Packit Service 95ac19
				}
Packit Service 95ac19
			}
Packit Service 95ac19
		}
Packit Service 95ac19
		if (shf)
Packit Service 95ac19
			shf_close(shf);
Packit Service 95ac19
		reclaim();
Packit Service 95ac19
#ifdef DEBUG_LEAKS
Packit Service 95ac19
#ifndef MKSH_NO_CMDLINE_EDITING
Packit Service 95ac19
		x_done();
Packit Service 95ac19
#endif
Packit Service 95ac19
#ifndef MKSH_NOPROSPECTOFWORK
Packit Service 95ac19
		/* block at least SIGCHLD during/after afreeall */
Packit Service 95ac19
		sigprocmask(SIG_BLOCK, &sm_sigchld, NULL);
Packit Service 95ac19
#endif
Packit Service 95ac19
		afreeall(APERM);
Packit Service 95ac19
		for (fd = 3; fd < NUFILE; fd++)
Packit Service 95ac19
			if ((i = fcntl(fd, F_GETFD, 0)) != -1 &&
Packit Service 95ac19
			    (i & FD_CLOEXEC))
Packit Service 95ac19
				close(fd);
Packit Service 95ac19
		close(2);
Packit Service 95ac19
		close(1);
Packit Service 95ac19
		close(0);
Packit Service 95ac19
#endif
Packit Service 95ac19
		exit(exstat & 0xFF);
Packit Service 95ac19
	}
Packit Service 95ac19
	if (shf)
Packit Service 95ac19
		shf_close(shf);
Packit Service 95ac19
	reclaim();
Packit Service 95ac19
Packit Service 95ac19
	e = e->oenv;
Packit Service 95ac19
Packit Service 95ac19
	/* free the struct env - tricky due to the ALLOC_ITEM inside */
Packit Service 95ac19
	cp = (void *)ep;
Packit Service 95ac19
	afree(cp + sizeof(ALLOC_ITEM), ATEMP);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* Called after a fork to cleanup stuff left over from parents environment */
Packit Service 95ac19
void
Packit Service 95ac19
cleanup_parents_env(void)
Packit Service 95ac19
{
Packit Service 95ac19
	struct env *ep;
Packit Service 95ac19
	int fd;
Packit Service 95ac19
Packit Service 95ac19
	/*
Packit Service 95ac19
	 * Don't clean up temporary files - parent will probably need them.
Packit Service 95ac19
	 * Also, can't easily reclaim memory since variables, etc. could be
Packit Service 95ac19
	 * anywhere.
Packit Service 95ac19
	 */
Packit Service 95ac19
Packit Service 95ac19
	/* close all file descriptors hiding in savefd */
Packit Service 95ac19
	for (ep = e; ep; ep = ep->oenv) {
Packit Service 95ac19
		if (ep->savefd) {
Packit Service 95ac19
			for (fd = 0; fd < NUFILE; fd++)
Packit Service 95ac19
				if (ep->savefd[fd] > 0)
Packit Service 95ac19
					close(ep->savefd[fd]);
Packit Service 95ac19
			afree(ep->savefd, &ep->area);
Packit Service 95ac19
			ep->savefd = NULL;
Packit Service 95ac19
		}
Packit Service 95ac19
#ifdef DEBUG_LEAKS
Packit Service 95ac19
		if (ep->type != E_NONE)
Packit Service 95ac19
			ep->type = E_GONE;
Packit Service 95ac19
#endif
Packit Service 95ac19
	}
Packit Service 95ac19
#ifndef DEBUG_LEAKS
Packit Service 95ac19
	e->oenv = NULL;
Packit Service 95ac19
#endif
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* Called just before an execve cleanup stuff temporary files */
Packit Service 95ac19
void
Packit Service 95ac19
cleanup_proc_env(void)
Packit Service 95ac19
{
Packit Service 95ac19
	struct env *ep;
Packit Service 95ac19
Packit Service 95ac19
	for (ep = e; ep; ep = ep->oenv)
Packit Service 95ac19
		remove_temps(ep->temps);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* remove temp files and free ATEMP Area */
Packit Service 95ac19
static void
Packit Service 95ac19
reclaim(void)
Packit Service 95ac19
{
Packit Service 95ac19
	struct block *l;
Packit Service 95ac19
Packit Service 95ac19
	while ((l = e->loc) && (!e->oenv || e->oenv->loc != l)) {
Packit Service 95ac19
		e->loc = l->next;
Packit Service 95ac19
		afreeall(&l->area);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	remove_temps(e->temps);
Packit Service 95ac19
	e->temps = NULL;
Packit Service 95ac19
Packit Service 95ac19
	/*
Packit Service 95ac19
	 * if the memory backing source is reclaimed, things
Packit Service 95ac19
	 * will end up badly when a function expecting it to
Packit Service 95ac19
	 * be valid is run; a NULL pointer is easily debugged
Packit Service 95ac19
	 */
Packit Service 95ac19
	if (source && source->areap == &e->area)
Packit Service 95ac19
		source = NULL;
Packit Service 95ac19
	afreeall(&e->area);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
static void
Packit Service 95ac19
remove_temps(struct temp *tp)
Packit Service 95ac19
{
Packit Service 95ac19
	while (tp) {
Packit Service 95ac19
		if (tp->pid == procpid)
Packit Service 95ac19
			unlink(tp->tffn);
Packit Service 95ac19
		tp = tp->next;
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Initialise tty_fd. Used for tracking the size of the terminal,
Packit Service 95ac19
 * saving/resetting tty modes upon forground job completion, and
Packit Service 95ac19
 * for setting up the tty process group. Return values:
Packit Service 95ac19
 *	0 = got controlling tty
Packit Service 95ac19
 *	1 = got terminal but no controlling tty
Packit Service 95ac19
 *	2 = cannot find a terminal
Packit Service 95ac19
 *	3 = cannot dup fd
Packit Service 95ac19
 *	4 = cannot make fd close-on-exec
Packit Service 95ac19
 * An existing tty_fd is cached if no "better" one could be found,
Packit Service 95ac19
 * i.e. if tty_devtty was already set or the new would not set it.
Packit Service 95ac19
 */
Packit Service 95ac19
int
Packit Service 95ac19
tty_init_fd(void)
Packit Service 95ac19
{
Packit Service 95ac19
	int fd, rv, eno = 0;
Packit Service 95ac19
	bool do_close = false, is_devtty = true;
Packit Service 95ac19
Packit Service 95ac19
	if (tty_devtty) {
Packit Service 95ac19
		/* already got a tty which is /dev/tty */
Packit Service 95ac19
		return (0);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
#ifdef _UWIN
Packit Service 95ac19
	/*XXX imake style */
Packit Service 95ac19
	if (isatty(3)) {
Packit Service 95ac19
		/* fd 3 on UWIN _is_ /dev/tty (or our controlling tty) */
Packit Service 95ac19
		fd = 3;
Packit Service 95ac19
		goto got_fd;
Packit Service 95ac19
	}
Packit Service 95ac19
#endif
Packit Service 95ac19
	if ((fd = open(T_devtty, O_RDWR, 0)) >= 0) {
Packit Service 95ac19
		do_close = true;
Packit Service 95ac19
		goto got_fd;
Packit Service 95ac19
	}
Packit Service 95ac19
	eno = errno;
Packit Service 95ac19
Packit Service 95ac19
	if (tty_fd >= 0) {
Packit Service 95ac19
		/* already got a non-devtty one */
Packit Service 95ac19
		rv = 1;
Packit Service 95ac19
		goto out;
Packit Service 95ac19
	}
Packit Service 95ac19
	is_devtty = false;
Packit Service 95ac19
Packit Service 95ac19
	if (isatty((fd = 0)) || isatty((fd = 2)))
Packit Service 95ac19
		goto got_fd;
Packit Service 95ac19
	/* cannot find one */
Packit Service 95ac19
	rv = 2;
Packit Service 95ac19
	/* assert: do_close == false */
Packit Service 95ac19
	goto out;
Packit Service 95ac19
Packit Service 95ac19
 got_fd:
Packit Service 95ac19
	if ((rv = fcntl(fd, F_DUPFD, FDBASE)) < 0) {
Packit Service 95ac19
		eno = errno;
Packit Service 95ac19
		rv = 3;
Packit Service 95ac19
		goto out;
Packit Service 95ac19
	}
Packit Service 95ac19
	if (fcntl(rv, F_SETFD, FD_CLOEXEC) < 0) {
Packit Service 95ac19
		eno = errno;
Packit Service 95ac19
		close(rv);
Packit Service 95ac19
		rv = 4;
Packit Service 95ac19
		goto out;
Packit Service 95ac19
	}
Packit Service 95ac19
	tty_fd = rv;
Packit Service 95ac19
	tty_devtty = is_devtty;
Packit Service 95ac19
	rv = eno = 0;
Packit Service 95ac19
 out:
Packit Service 95ac19
	if (do_close)
Packit Service 95ac19
		close(fd);
Packit Service 95ac19
	errno = eno;
Packit Service 95ac19
	return (rv);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* A shell error occurred (eg, syntax error, etc.) */
Packit Service 95ac19
Packit Service 95ac19
#define VWARNINGF_ERRORPREFIX	1
Packit Service 95ac19
#define VWARNINGF_FILELINE	2
Packit Service 95ac19
#define VWARNINGF_BUILTIN	4
Packit Service 95ac19
#define VWARNINGF_INTERNAL	8
Packit Service 95ac19
Packit Service 95ac19
static void vwarningf(unsigned int, const char *, va_list)
Packit Service 95ac19
    MKSH_A_FORMAT(__printf__, 2, 0);
Packit Service 95ac19
Packit Service 95ac19
static void
Packit Service 95ac19
vwarningf(unsigned int flags, const char *fmt, va_list ap)
Packit Service 95ac19
{
Packit Service 95ac19
	if (fmt) {
Packit Service 95ac19
		if (flags & VWARNINGF_INTERNAL)
Packit Service 95ac19
			shf_fprintf(shl_out, Tf_sD_, "internal error");
Packit Service 95ac19
		if (flags & VWARNINGF_ERRORPREFIX)
Packit Service 95ac19
			error_prefix(tobool(flags & VWARNINGF_FILELINE));
Packit Service 95ac19
		if ((flags & VWARNINGF_BUILTIN) &&
Packit Service 95ac19
		    /* not set when main() calls parse_args() */
Packit Service 95ac19
		    builtin_argv0 && builtin_argv0 != kshname)
Packit Service 95ac19
			shf_fprintf(shl_out, Tf_sD_, builtin_argv0);
Packit Service 95ac19
		shf_vfprintf(shl_out, fmt, ap);
Packit Service 95ac19
		shf_putchar('\n', shl_out);
Packit Service 95ac19
	}
Packit Service 95ac19
	shf_flush(shl_out);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
errorfx(int rc, const char *fmt, ...)
Packit Service 95ac19
{
Packit Service 95ac19
	va_list va;
Packit Service 95ac19
Packit Service 95ac19
	exstat = rc;
Packit Service 95ac19
Packit Service 95ac19
	/* debugging: note that stdout not valid */
Packit Service 95ac19
	shl_stdout_ok = false;
Packit Service 95ac19
Packit Service 95ac19
	va_start(va, fmt);
Packit Service 95ac19
	vwarningf(VWARNINGF_ERRORPREFIX | VWARNINGF_FILELINE, fmt, va);
Packit Service 95ac19
	va_end(va);
Packit Service 95ac19
	unwind(LERROR);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
errorf(const char *fmt, ...)
Packit Service 95ac19
{
Packit Service 95ac19
	va_list va;
Packit Service 95ac19
Packit Service 95ac19
	exstat = 1;
Packit Service 95ac19
Packit Service 95ac19
	/* debugging: note that stdout not valid */
Packit Service 95ac19
	shl_stdout_ok = false;
Packit Service 95ac19
Packit Service 95ac19
	va_start(va, fmt);
Packit Service 95ac19
	vwarningf(VWARNINGF_ERRORPREFIX | VWARNINGF_FILELINE, fmt, va);
Packit Service 95ac19
	va_end(va);
Packit Service 95ac19
	unwind(LERROR);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* like errorf(), but no unwind is done */
Packit Service 95ac19
void
Packit Service 95ac19
warningf(bool fileline, const char *fmt, ...)
Packit Service 95ac19
{
Packit Service 95ac19
	va_list va;
Packit Service 95ac19
Packit Service 95ac19
	va_start(va, fmt);
Packit Service 95ac19
	vwarningf(VWARNINGF_ERRORPREFIX | (fileline ? VWARNINGF_FILELINE : 0),
Packit Service 95ac19
	    fmt, va);
Packit Service 95ac19
	va_end(va);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Used by built-in utilities to prefix shell and utility name to message
Packit Service 95ac19
 * (also unwinds environments for special builtins).
Packit Service 95ac19
 */
Packit Service 95ac19
void
Packit Service 95ac19
bi_errorf(const char *fmt, ...)
Packit Service 95ac19
{
Packit Service 95ac19
	va_list va;
Packit Service 95ac19
Packit Service 95ac19
	/* debugging: note that stdout not valid */
Packit Service 95ac19
	shl_stdout_ok = false;
Packit Service 95ac19
Packit Service 95ac19
	exstat = 1;
Packit Service 95ac19
Packit Service 95ac19
	va_start(va, fmt);
Packit Service 95ac19
	vwarningf(VWARNINGF_ERRORPREFIX | VWARNINGF_FILELINE |
Packit Service 95ac19
	    VWARNINGF_BUILTIN, fmt, va);
Packit Service 95ac19
	va_end(va);
Packit Service 95ac19
Packit Service 95ac19
	/* POSIX special builtins cause non-interactive shells to exit */
Packit Service 95ac19
	if (builtin_spec) {
Packit Service 95ac19
		builtin_argv0 = NULL;
Packit Service 95ac19
		/* may not want to use LERROR here */
Packit Service 95ac19
		unwind(LERROR);
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* Called when something that shouldn't happen does */
Packit Service 95ac19
void
Packit Service 95ac19
internal_errorf(const char *fmt, ...)
Packit Service 95ac19
{
Packit Service 95ac19
	va_list va;
Packit Service 95ac19
Packit Service 95ac19
	va_start(va, fmt);
Packit Service 95ac19
	vwarningf(VWARNINGF_INTERNAL, fmt, va);
Packit Service 95ac19
	va_end(va);
Packit Service 95ac19
	unwind(LERROR);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
internal_warningf(const char *fmt, ...)
Packit Service 95ac19
{
Packit Service 95ac19
	va_list va;
Packit Service 95ac19
Packit Service 95ac19
	va_start(va, fmt);
Packit Service 95ac19
	vwarningf(VWARNINGF_INTERNAL, fmt, va);
Packit Service 95ac19
	va_end(va);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* used by error reporting functions to print "ksh: .kshrc[25]: " */
Packit Service 95ac19
void
Packit Service 95ac19
error_prefix(bool fileline)
Packit Service 95ac19
{
Packit Service 95ac19
	/* Avoid foo: foo[2]: ... */
Packit Service 95ac19
	if (!fileline || !source || !source->file ||
Packit Service 95ac19
	    strcmp(source->file, kshname) != 0)
Packit Service 95ac19
		shf_fprintf(shl_out, Tf_sD_, kshname + (*kshname == '-'));
Packit Service 95ac19
	if (fileline && source && source->file != NULL) {
Packit Service 95ac19
		shf_fprintf(shl_out, "%s[%lu]: ", source->file,
Packit Service 95ac19
		    (unsigned long)(source->errline ?
Packit Service 95ac19
		    source->errline : source->line));
Packit Service 95ac19
		source->errline = 0;
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* printf to shl_out (stderr) with flush */
Packit Service 95ac19
void
Packit Service 95ac19
shellf(const char *fmt, ...)
Packit Service 95ac19
{
Packit Service 95ac19
	va_list va;
Packit Service 95ac19
Packit Service 95ac19
	if (!initio_done)
Packit Service 95ac19
		/* shl_out may not be set up yet... */
Packit Service 95ac19
		return;
Packit Service 95ac19
	va_start(va, fmt);
Packit Service 95ac19
	shf_vfprintf(shl_out, fmt, va);
Packit Service 95ac19
	va_end(va);
Packit Service 95ac19
	shf_flush(shl_out);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* printf to shl_stdout (stdout) */
Packit Service 95ac19
void
Packit Service 95ac19
shprintf(const char *fmt, ...)
Packit Service 95ac19
{
Packit Service 95ac19
	va_list va;
Packit Service 95ac19
Packit Service 95ac19
	if (!shl_stdout_ok)
Packit Service 95ac19
		internal_errorf("shl_stdout not valid");
Packit Service 95ac19
	va_start(va, fmt);
Packit Service 95ac19
	shf_vfprintf(shl_stdout, fmt, va);
Packit Service 95ac19
	va_end(va);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* test if we can seek backwards fd (returns 0 or SHF_UNBUF) */
Packit Service 95ac19
int
Packit Service 95ac19
can_seek(int fd)
Packit Service 95ac19
{
Packit Service 95ac19
	struct stat statb;
Packit Service 95ac19
Packit Service 95ac19
	return (fstat(fd, &statb) == 0 && !S_ISREG(statb.st_mode) ?
Packit Service 95ac19
	    SHF_UNBUF : 0);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
#ifdef DF
Packit Service 95ac19
int shl_dbg_fd;
Packit Service 95ac19
#define NSHF_IOB 4
Packit Service 95ac19
#else
Packit Service 95ac19
#define NSHF_IOB 3
Packit Service 95ac19
#endif
Packit Service 95ac19
struct shf shf_iob[NSHF_IOB];
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
initio(void)
Packit Service 95ac19
{
Packit Service 95ac19
#ifdef DF
Packit Service 95ac19
	const char *lfp;
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
	/* force buffer allocation */
Packit Service 95ac19
	shf_fdopen(1, SHF_WR, shl_stdout);
Packit Service 95ac19
	shf_fdopen(2, SHF_WR, shl_out);
Packit Service 95ac19
	shf_fdopen(2, SHF_WR, shl_xtrace);
Packit Service 95ac19
#ifdef DF
Packit Service 95ac19
	if ((lfp = getenv("SDMKSH_PATH")) == NULL) {
Packit Service 95ac19
		if ((lfp = getenv("HOME")) == NULL || !mksh_abspath(lfp))
Packit Service 95ac19
			errorf("can't get home directory");
Packit Service 95ac19
		lfp = shf_smprintf(Tf_sSs, lfp, "mksh-dbg.txt");
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	if ((shl_dbg_fd = open(lfp, O_WRONLY | O_APPEND | O_CREAT, 0600)) < 0)
Packit Service 95ac19
		errorf("can't open debug output file %s", lfp);
Packit Service 95ac19
	if (shl_dbg_fd < FDBASE) {
Packit Service 95ac19
		int nfd;
Packit Service 95ac19
Packit Service 95ac19
		nfd = fcntl(shl_dbg_fd, F_DUPFD, FDBASE);
Packit Service 95ac19
		close(shl_dbg_fd);
Packit Service 95ac19
		if ((shl_dbg_fd = nfd) == -1)
Packit Service 95ac19
			errorf("can't dup debug output file");
Packit Service 95ac19
	}
Packit Service 95ac19
	fcntl(shl_dbg_fd, F_SETFD, FD_CLOEXEC);
Packit Service 95ac19
	shf_fdopen(shl_dbg_fd, SHF_WR, shl_dbg);
Packit Service 95ac19
	DF("=== open ===");
Packit Service 95ac19
#endif
Packit Service 95ac19
	initio_done = true;
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* A dup2() with error checking */
Packit Service 95ac19
int
Packit Service 95ac19
ksh_dup2(int ofd, int nfd, bool errok)
Packit Service 95ac19
{
Packit Service 95ac19
	int rv;
Packit Service 95ac19
Packit Service 95ac19
	if (((rv = dup2(ofd, nfd)) < 0) && !errok && (errno != EBADF))
Packit Service 95ac19
		errorf(Ttoo_many_files);
Packit Service 95ac19
Packit Service 95ac19
#ifdef __ultrix
Packit Service 95ac19
	/*XXX imake style */
Packit Service 95ac19
	if (rv >= 0)
Packit Service 95ac19
		fcntl(nfd, F_SETFD, 0);
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
	return (rv);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Move fd from user space (0 <= fd < 10) to shell space (fd >= 10),
Packit Service 95ac19
 * set close-on-exec flag. See FDBASE in sh.h, maybe 24 not 10 here.
Packit Service 95ac19
 */
Packit Service 95ac19
short
Packit Service 95ac19
savefd(int fd)
Packit Service 95ac19
{
Packit Service 95ac19
	int nfd = fd;
Packit Service 95ac19
Packit Service 95ac19
	if (fd < FDBASE && (nfd = fcntl(fd, F_DUPFD, FDBASE)) < 0 &&
Packit Service 95ac19
	    (errno == EBADF || errno == EPERM))
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
	if (nfd < 0 || nfd > SHRT_MAX)
Packit Service 95ac19
		errorf(Ttoo_many_files);
Packit Service 95ac19
	fcntl(nfd, F_SETFD, FD_CLOEXEC);
Packit Service 95ac19
	return ((short)nfd);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
restfd(int fd, int ofd)
Packit Service 95ac19
{
Packit Service 95ac19
	if (fd == 2)
Packit Service 95ac19
		shf_flush(&shf_iob[/* fd */ 2]);
Packit Service 95ac19
	if (ofd < 0)
Packit Service 95ac19
		/* original fd closed */
Packit Service 95ac19
		close(fd);
Packit Service 95ac19
	else if (fd != ofd) {
Packit Service 95ac19
		/*XXX: what to do if this dup fails? */
Packit Service 95ac19
		ksh_dup2(ofd, fd, true);
Packit Service 95ac19
		close(ofd);
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
openpipe(int *pv)
Packit Service 95ac19
{
Packit Service 95ac19
	int lpv[2];
Packit Service 95ac19
Packit Service 95ac19
	if (pipe(lpv) < 0)
Packit Service 95ac19
		errorf("can't create pipe - try again");
Packit Service 95ac19
	pv[0] = savefd(lpv[0]);
Packit Service 95ac19
	if (pv[0] != lpv[0])
Packit Service 95ac19
		close(lpv[0]);
Packit Service 95ac19
	pv[1] = savefd(lpv[1]);
Packit Service 95ac19
	if (pv[1] != lpv[1])
Packit Service 95ac19
		close(lpv[1]);
Packit Service 95ac19
#ifdef __OS2__
Packit Service 95ac19
	setmode(pv[0], O_BINARY);
Packit Service 95ac19
	setmode(pv[1], O_BINARY);
Packit Service 95ac19
#endif
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
closepipe(int *pv)
Packit Service 95ac19
{
Packit Service 95ac19
	close(pv[0]);
Packit Service 95ac19
	close(pv[1]);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn
Packit Service 95ac19
 * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor.
Packit Service 95ac19
 */
Packit Service 95ac19
int
Packit Service 95ac19
check_fd(const char *name, int mode, const char **emsgp)
Packit Service 95ac19
{
Packit Service 95ac19
	int fd, fl;
Packit Service 95ac19
Packit Service 95ac19
	if (!name[0] || name[1])
Packit Service 95ac19
		goto illegal_fd_name;
Packit Service 95ac19
	if (name[0] == 'p')
Packit Service 95ac19
		return (coproc_getfd(mode, emsgp));
Packit Service 95ac19
	if (!ctype(name[0], C_DIGIT)) {
Packit Service 95ac19
 illegal_fd_name:
Packit Service 95ac19
		if (emsgp)
Packit Service 95ac19
			*emsgp = "illegal file descriptor name";
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	if ((fl = fcntl((fd = ksh_numdig(name[0])), F_GETFL, 0)) < 0) {
Packit Service 95ac19
		if (emsgp)
Packit Service 95ac19
			*emsgp = "bad file descriptor";
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
	}
Packit Service 95ac19
	fl &= O_ACCMODE;
Packit Service 95ac19
	/*
Packit Service 95ac19
	 * X_OK is a kludge to disable this check for dups (x<&1):
Packit Service 95ac19
	 * historical shells never did this check (XXX don't know what
Packit Service 95ac19
	 * POSIX has to say).
Packit Service 95ac19
	 */
Packit Service 95ac19
	if (!(mode & X_OK) && fl != O_RDWR && (
Packit Service 95ac19
	    ((mode & R_OK) && fl != O_RDONLY) ||
Packit Service 95ac19
	    ((mode & W_OK) && fl != O_WRONLY))) {
Packit Service 95ac19
		if (emsgp)
Packit Service 95ac19
			*emsgp = (fl == O_WRONLY) ?
Packit Service 95ac19
			    "fd not open for reading" :
Packit Service 95ac19
			    "fd not open for writing";
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
	}
Packit Service 95ac19
	return (fd);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* Called once from main */
Packit Service 95ac19
void
Packit Service 95ac19
coproc_init(void)
Packit Service 95ac19
{
Packit Service 95ac19
	coproc.read = coproc.readw = coproc.write = -1;
Packit Service 95ac19
	coproc.njobs = 0;
Packit Service 95ac19
	coproc.id = 0;
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* Called by c_read() when eof is read - close fd if it is the co-process fd */
Packit Service 95ac19
void
Packit Service 95ac19
coproc_read_close(int fd)
Packit Service 95ac19
{
Packit Service 95ac19
	if (coproc.read >= 0 && fd == coproc.read) {
Packit Service 95ac19
		coproc_readw_close(fd);
Packit Service 95ac19
		close(coproc.read);
Packit Service 95ac19
		coproc.read = -1;
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Called by c_read() and by iosetup() to close the other side of the
Packit Service 95ac19
 * read pipe, so reads will actually terminate.
Packit Service 95ac19
 */
Packit Service 95ac19
void
Packit Service 95ac19
coproc_readw_close(int fd)
Packit Service 95ac19
{
Packit Service 95ac19
	if (coproc.readw >= 0 && coproc.read >= 0 && fd == coproc.read) {
Packit Service 95ac19
		close(coproc.readw);
Packit Service 95ac19
		coproc.readw = -1;
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Called by c_print when a write to a fd fails with EPIPE and by iosetup
Packit Service 95ac19
 * when co-process input is dup'd
Packit Service 95ac19
 */
Packit Service 95ac19
void
Packit Service 95ac19
coproc_write_close(int fd)
Packit Service 95ac19
{
Packit Service 95ac19
	if (coproc.write >= 0 && fd == coproc.write) {
Packit Service 95ac19
		close(coproc.write);
Packit Service 95ac19
		coproc.write = -1;
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Called to check for existence of/value of the co-process file descriptor.
Packit Service 95ac19
 * (Used by check_fd() and by c_read/c_print to deal with -p option).
Packit Service 95ac19
 */
Packit Service 95ac19
int
Packit Service 95ac19
coproc_getfd(int mode, const char **emsgp)
Packit Service 95ac19
{
Packit Service 95ac19
	int fd = (mode & R_OK) ? coproc.read : coproc.write;
Packit Service 95ac19
Packit Service 95ac19
	if (fd >= 0)
Packit Service 95ac19
		return (fd);
Packit Service 95ac19
	if (emsgp)
Packit Service 95ac19
		*emsgp = "no coprocess";
Packit Service 95ac19
	return (-1);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * called to close file descriptors related to the coprocess (if any)
Packit Service 95ac19
 * Should be called with SIGCHLD blocked.
Packit Service 95ac19
 */
Packit Service 95ac19
void
Packit Service 95ac19
coproc_cleanup(int reuse)
Packit Service 95ac19
{
Packit Service 95ac19
	/* This to allow co-processes to share output pipe */
Packit Service 95ac19
	if (!reuse || coproc.readw < 0 || coproc.read < 0) {
Packit Service 95ac19
		if (coproc.read >= 0) {
Packit Service 95ac19
			close(coproc.read);
Packit Service 95ac19
			coproc.read = -1;
Packit Service 95ac19
		}
Packit Service 95ac19
		if (coproc.readw >= 0) {
Packit Service 95ac19
			close(coproc.readw);
Packit Service 95ac19
			coproc.readw = -1;
Packit Service 95ac19
		}
Packit Service 95ac19
	}
Packit Service 95ac19
	if (coproc.write >= 0) {
Packit Service 95ac19
		close(coproc.write);
Packit Service 95ac19
		coproc.write = -1;
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
struct temp *
Packit Service 95ac19
maketemp(Area *ap, Temp_type type, struct temp **tlist)
Packit Service 95ac19
{
Packit Service 95ac19
	char *cp;
Packit Service 95ac19
	size_t len;
Packit Service 95ac19
	int i, j;
Packit Service 95ac19
	struct temp *tp;
Packit Service 95ac19
	const char *dir;
Packit Service 95ac19
	struct stat sb;
Packit Service 95ac19
Packit Service 95ac19
	dir = tmpdir ? tmpdir : MKSH_DEFAULT_TMPDIR;
Packit Service 95ac19
	/* add "/shXXXXXX.tmp" plus NUL */
Packit Service 95ac19
	len = strlen(dir);
Packit Service 95ac19
	checkoktoadd(len, offsetof(struct temp, tffn[0]) + 14);
Packit Service 95ac19
	tp = alloc(offsetof(struct temp, tffn[0]) + 14 + len, ap);
Packit Service 95ac19
Packit Service 95ac19
	tp->shf = NULL;
Packit Service 95ac19
	tp->pid = procpid;
Packit Service 95ac19
	tp->type = type;
Packit Service 95ac19
Packit Service 95ac19
	if (stat(dir, &sb) || !S_ISDIR(sb.st_mode)) {
Packit Service 95ac19
		tp->tffn[0] = '\0';
Packit Service 95ac19
		goto maketemp_out;
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	cp = (void *)tp;
Packit Service 95ac19
	cp += offsetof(struct temp, tffn[0]);
Packit Service 95ac19
	memcpy(cp, dir, len);
Packit Service 95ac19
	cp += len;
Packit Service 95ac19
	memcpy(cp, "/shXXXXXX.tmp", 14);
Packit Service 95ac19
	/* point to the first of six Xes */
Packit Service 95ac19
	cp += 3;
Packit Service 95ac19
Packit Service 95ac19
	/* cyclically attempt to open a temporary file */
Packit Service 95ac19
	do {
Packit Service 95ac19
		/* generate random part of filename */
Packit Service 95ac19
		len = 0;
Packit Service 95ac19
		do {
Packit Service 95ac19
			cp[len++] = digits_lc[rndget() % 36];
Packit Service 95ac19
		} while (len < 6);
Packit Service 95ac19
Packit Service 95ac19
		/* check if this one works */
Packit Service 95ac19
		if ((i = binopen3(tp->tffn, O_CREAT | O_EXCL | O_RDWR,
Packit Service 95ac19
		    0600)) < 0 && errno != EEXIST)
Packit Service 95ac19
			goto maketemp_out;
Packit Service 95ac19
	} while (i < 0);
Packit Service 95ac19
Packit Service 95ac19
	if (type == TT_FUNSUB) {
Packit Service 95ac19
		/* map us high and mark as close-on-exec */
Packit Service 95ac19
		if ((j = savefd(i)) != i) {
Packit Service 95ac19
			close(i);
Packit Service 95ac19
			i = j;
Packit Service 95ac19
		}
Packit Service 95ac19
Packit Service 95ac19
		/* operation mode for the shf */
Packit Service 95ac19
		j = SHF_RD;
Packit Service 95ac19
	} else
Packit Service 95ac19
		j = SHF_WR;
Packit Service 95ac19
Packit Service 95ac19
	/* shf_fdopen cannot fail, so no fd leak */
Packit Service 95ac19
	tp->shf = shf_fdopen(i, j, NULL);
Packit Service 95ac19
Packit Service 95ac19
 maketemp_out:
Packit Service 95ac19
	tp->next = *tlist;
Packit Service 95ac19
	*tlist = tp;
Packit Service 95ac19
	return (tp);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * We use a similar collision resolution algorithm as Python 2.5.4
Packit Service 95ac19
 * but with a slightly tweaked implementation written from scratch.
Packit Service 95ac19
 */
Packit Service 95ac19
Packit Service 95ac19
#define	INIT_TBLSHIFT	3	/* initial table shift (2^3 = 8) */
Packit Service 95ac19
#define PERTURB_SHIFT	5	/* see Python 2.5.4 Objects/dictobject.c */
Packit Service 95ac19
Packit Service 95ac19
static void tgrow(struct table *);
Packit Service 95ac19
static int tnamecmp(const void *, const void *);
Packit Service 95ac19
Packit Service 95ac19
static void
Packit Service 95ac19
tgrow(struct table *tp)
Packit Service 95ac19
{
Packit Service 95ac19
	size_t i, j, osize, mask, perturb;
Packit Service 95ac19
	struct tbl *tblp, **pp;
Packit Service 95ac19
	struct tbl **ntblp, **otblp = tp->tbls;
Packit Service 95ac19
Packit Service 95ac19
	if (tp->tshift > 29)
Packit Service 95ac19
		internal_errorf("hash table size limit reached");
Packit Service 95ac19
Packit Service 95ac19
	/* calculate old size, new shift and new size */
Packit Service 95ac19
	osize = (size_t)1 << (tp->tshift++);
Packit Service 95ac19
	i = osize << 1;
Packit Service 95ac19
Packit Service 95ac19
	ntblp = alloc2(i, sizeof(struct tbl *), tp->areap);
Packit Service 95ac19
	/* multiplication cannot overflow: alloc2 checked that */
Packit Service 95ac19
	memset(ntblp, 0, i * sizeof(struct tbl *));
Packit Service 95ac19
Packit Service 95ac19
	/* table can get very full when reaching its size limit */
Packit Service 95ac19
	tp->nfree = (tp->tshift == 30) ? 0x3FFF0000UL :
Packit Service 95ac19
	    /* but otherwise, only 75% */
Packit Service 95ac19
	    ((i * 3) / 4);
Packit Service 95ac19
	tp->tbls = ntblp;
Packit Service 95ac19
	if (otblp == NULL)
Packit Service 95ac19
		return;
Packit Service 95ac19
Packit Service 95ac19
	mask = i - 1;
Packit Service 95ac19
	for (i = 0; i < osize; i++)
Packit Service 95ac19
		if ((tblp = otblp[i]) != NULL) {
Packit Service 95ac19
			if ((tblp->flag & DEFINED)) {
Packit Service 95ac19
				/* search for free hash table slot */
Packit Service 95ac19
				j = perturb = tblp->ua.hval;
Packit Service 95ac19
				goto find_first_empty_slot;
Packit Service 95ac19
 find_next_empty_slot:
Packit Service 95ac19
				j = (j << 2) + j + perturb + 1;
Packit Service 95ac19
				perturb >>= PERTURB_SHIFT;
Packit Service 95ac19
 find_first_empty_slot:
Packit Service 95ac19
				pp = &ntblp[j & mask];
Packit Service 95ac19
				if (*pp != NULL)
Packit Service 95ac19
					goto find_next_empty_slot;
Packit Service 95ac19
				/* found an empty hash table slot */
Packit Service 95ac19
				*pp = tblp;
Packit Service 95ac19
				tp->nfree--;
Packit Service 95ac19
			} else if (!(tblp->flag & FINUSE)) {
Packit Service 95ac19
				afree(tblp, tp->areap);
Packit Service 95ac19
			}
Packit Service 95ac19
		}
Packit Service 95ac19
	afree(otblp, tp->areap);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
ktinit(Area *ap, struct table *tp, uint8_t initshift)
Packit Service 95ac19
{
Packit Service 95ac19
	tp->areap = ap;
Packit Service 95ac19
	tp->tbls = NULL;
Packit Service 95ac19
	tp->tshift = ((initshift > INIT_TBLSHIFT) ?
Packit Service 95ac19
	    initshift : INIT_TBLSHIFT) - 1;
Packit Service 95ac19
	tgrow(tp);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* table, name (key) to search for, hash(name), rv pointer to tbl ptr */
Packit Service 95ac19
struct tbl *
Packit Service 95ac19
ktscan(struct table *tp, const char *name, uint32_t h, struct tbl ***ppp)
Packit Service 95ac19
{
Packit Service 95ac19
	size_t j, perturb, mask;
Packit Service 95ac19
	struct tbl **pp, *p;
Packit Service 95ac19
Packit Service 95ac19
	mask = ((size_t)1 << (tp->tshift)) - 1;
Packit Service 95ac19
	/* search for hash table slot matching name */
Packit Service 95ac19
	j = perturb = h;
Packit Service 95ac19
	goto find_first_slot;
Packit Service 95ac19
 find_next_slot:
Packit Service 95ac19
	j = (j << 2) + j + perturb + 1;
Packit Service 95ac19
	perturb >>= PERTURB_SHIFT;
Packit Service 95ac19
 find_first_slot:
Packit Service 95ac19
	pp = &tp->tbls[j & mask];
Packit Service 95ac19
	if ((p = *pp) != NULL && (p->ua.hval != h || !(p->flag & DEFINED) ||
Packit Service 95ac19
	    strcmp(p->name, name)))
Packit Service 95ac19
		goto find_next_slot;
Packit Service 95ac19
	/* p == NULL if not found, correct found entry otherwise */
Packit Service 95ac19
	if (ppp)
Packit Service 95ac19
		*ppp = pp;
Packit Service 95ac19
	return (p);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* table, name (key) to enter, hash(n) */
Packit Service 95ac19
struct tbl *
Packit Service 95ac19
ktenter(struct table *tp, const char *n, uint32_t h)
Packit Service 95ac19
{
Packit Service 95ac19
	struct tbl **pp, *p;
Packit Service 95ac19
	size_t len;
Packit Service 95ac19
Packit Service 95ac19
 Search:
Packit Service 95ac19
	if ((p = ktscan(tp, n, h, &pp)))
Packit Service 95ac19
		return (p);
Packit Service 95ac19
Packit Service 95ac19
	if (tp->nfree == 0) {
Packit Service 95ac19
		/* too full */
Packit Service 95ac19
		tgrow(tp);
Packit Service 95ac19
		goto Search;
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	/* create new tbl entry */
Packit Service 95ac19
	len = strlen(n);
Packit Service 95ac19
	checkoktoadd(len, offsetof(struct tbl, name[0]) + 1);
Packit Service 95ac19
	p = alloc(offsetof(struct tbl, name[0]) + ++len, tp->areap);
Packit Service 95ac19
	p->flag = 0;
Packit Service 95ac19
	p->type = 0;
Packit Service 95ac19
	p->areap = tp->areap;
Packit Service 95ac19
	p->ua.hval = h;
Packit Service 95ac19
	p->u2.field = 0;
Packit Service 95ac19
	p->u.array = NULL;
Packit Service 95ac19
	memcpy(p->name, n, len);
Packit Service 95ac19
Packit Service 95ac19
	/* enter in tp->tbls */
Packit Service 95ac19
	tp->nfree--;
Packit Service 95ac19
	*pp = p;
Packit Service 95ac19
	return (p);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
ktwalk(struct tstate *ts, struct table *tp)
Packit Service 95ac19
{
Packit Service 95ac19
	ts->left = (size_t)1 << (tp->tshift);
Packit Service 95ac19
	ts->next = tp->tbls;
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
struct tbl *
Packit Service 95ac19
ktnext(struct tstate *ts)
Packit Service 95ac19
{
Packit Service 95ac19
	while (--ts->left >= 0) {
Packit Service 95ac19
		struct tbl *p = *ts->next++;
Packit Service 95ac19
		if (p != NULL && (p->flag & DEFINED))
Packit Service 95ac19
			return (p);
Packit Service 95ac19
	}
Packit Service 95ac19
	return (NULL);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
static int
Packit Service 95ac19
tnamecmp(const void *p1, const void *p2)
Packit Service 95ac19
{
Packit Service 95ac19
	const struct tbl *a = *((const struct tbl * const *)p1);
Packit Service 95ac19
	const struct tbl *b = *((const struct tbl * const *)p2);
Packit Service 95ac19
Packit Service 95ac19
	return (ascstrcmp(a->name, b->name));
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
struct tbl **
Packit Service 95ac19
ktsort(struct table *tp)
Packit Service 95ac19
{
Packit Service 95ac19
	size_t i;
Packit Service 95ac19
	struct tbl **p, **sp, **dp;
Packit Service 95ac19
Packit Service 95ac19
	/*
Packit Service 95ac19
	 * since the table is never entirely full, no need to reserve
Packit Service 95ac19
	 * additional space for the trailing NULL appended below
Packit Service 95ac19
	 */
Packit Service 95ac19
	i = (size_t)1 << (tp->tshift);
Packit Service 95ac19
	p = alloc2(i, sizeof(struct tbl *), ATEMP);
Packit Service 95ac19
	sp = tp->tbls;		/* source */
Packit Service 95ac19
	dp = p;			/* dest */
Packit Service 95ac19
	while (i--)
Packit Service 95ac19
		if ((*dp = *sp++) != NULL && (((*dp)->flag & DEFINED) ||
Packit Service 95ac19
		    ((*dp)->flag & ARRAY)))
Packit Service 95ac19
			dp++;
Packit Service 95ac19
	qsort(p, (i = dp - p), sizeof(struct tbl *), tnamecmp);
Packit Service 95ac19
	p[i] = NULL;
Packit Service 95ac19
	return (p);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
#ifdef SIGWINCH
Packit Service 95ac19
static void
Packit Service 95ac19
x_sigwinch(int sig MKSH_A_UNUSED)
Packit Service 95ac19
{
Packit Service 95ac19
	/* this runs inside interrupt context, with errno saved */
Packit Service 95ac19
Packit Service 95ac19
	got_winch = 1;
Packit Service 95ac19
}
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
#ifdef DF
Packit Service 95ac19
void
Packit Service 95ac19
DF(const char *fmt, ...)
Packit Service 95ac19
{
Packit Service 95ac19
	va_list args;
Packit Service 95ac19
	struct timeval tv;
Packit Service 95ac19
	mirtime_mjd mjd;
Packit Service 95ac19
Packit Service 95ac19
	mksh_lockfd(shl_dbg_fd);
Packit Service 95ac19
	mksh_TIME(tv);
Packit Service 95ac19
	timet2mjd(&mjd, tv.tv_sec);
Packit Service 95ac19
	shf_fprintf(shl_dbg, "[%02u:%02u:%02u (%u) %u.%06u] ",
Packit Service 95ac19
	    (unsigned)mjd.sec / 3600, ((unsigned)mjd.sec / 60) % 60,
Packit Service 95ac19
	    (unsigned)mjd.sec % 60, (unsigned)getpid(),
Packit Service 95ac19
	    (unsigned)tv.tv_sec, (unsigned)tv.tv_usec);
Packit Service 95ac19
	va_start(args, fmt);
Packit Service 95ac19
	shf_vfprintf(shl_dbg, fmt, args);
Packit Service 95ac19
	va_end(args);
Packit Service 95ac19
	shf_putc('\n', shl_dbg);
Packit Service 95ac19
	shf_flush(shl_dbg);
Packit Service 95ac19
	mksh_unlkfd(shl_dbg_fd);
Packit Service 95ac19
}
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
x_mkraw(int fd, mksh_ttyst *ocb, bool forread)
Packit Service 95ac19
{
Packit Service 95ac19
	mksh_ttyst cb;
Packit Service 95ac19
Packit Service 95ac19
	if (ocb)
Packit Service 95ac19
		mksh_tcget(fd, ocb);
Packit Service 95ac19
	else
Packit Service 95ac19
		ocb = &tty_state;
Packit Service 95ac19
Packit Service 95ac19
	cb = *ocb;
Packit Service 95ac19
	if (forread) {
Packit Service 95ac19
		cb.c_iflag &= ~(ISTRIP);
Packit Service 95ac19
		cb.c_lflag &= ~(ICANON) | ECHO;
Packit Service 95ac19
	} else {
Packit Service 95ac19
		cb.c_iflag &= ~(INLCR | ICRNL | ISTRIP);
Packit Service 95ac19
		cb.c_lflag &= ~(ISIG | ICANON | ECHO);
Packit Service 95ac19
	}
Packit Service 95ac19
#if defined(VLNEXT) && defined(_POSIX_VDISABLE)
Packit Service 95ac19
	/* OSF/1 processes lnext when ~icanon */
Packit Service 95ac19
	cb.c_cc[VLNEXT] = _POSIX_VDISABLE;
Packit Service 95ac19
#endif
Packit Service 95ac19
	/* SunOS 4.1.x & OSF/1 processes discard(flush) when ~icanon */
Packit Service 95ac19
#if defined(VDISCARD) && defined(_POSIX_VDISABLE)
Packit Service 95ac19
	cb.c_cc[VDISCARD] = _POSIX_VDISABLE;
Packit Service 95ac19
#endif
Packit Service 95ac19
	cb.c_cc[VTIME] = 0;
Packit Service 95ac19
	cb.c_cc[VMIN] = 1;
Packit Service 95ac19
Packit Service 95ac19
	mksh_tcset(fd, &cb;;
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
#ifdef MKSH_ENVDIR
Packit Service 95ac19
static void
Packit Service 95ac19
init_environ(void)
Packit Service 95ac19
{
Packit Service 95ac19
	char *xp;
Packit Service 95ac19
	ssize_t n;
Packit Service 95ac19
	XString xs;
Packit Service 95ac19
	struct shf *shf;
Packit Service 95ac19
	DIR *dirp;
Packit Service 95ac19
	struct dirent *dent;
Packit Service 95ac19
Packit Service 95ac19
	if ((dirp = opendir(MKSH_ENVDIR)) == NULL) {
Packit Service 95ac19
		warningf(false, "cannot read environment from %s: %s",
Packit Service 95ac19
		    MKSH_ENVDIR, cstrerror(errno));
Packit Service 95ac19
		return;
Packit Service 95ac19
	}
Packit Service 95ac19
	XinitN(xs, 256, ATEMP);
Packit Service 95ac19
 read_envfile:
Packit Service 95ac19
	errno = 0;
Packit Service 95ac19
	if ((dent = readdir(dirp)) != NULL) {
Packit Service 95ac19
		if (skip_varname(dent->d_name, true)[0] == '\0') {
Packit Service 95ac19
			xp = shf_smprintf(Tf_sSs, MKSH_ENVDIR, dent->d_name);
Packit Service 95ac19
			if (!(shf = shf_open(xp, O_RDONLY, 0, 0))) {
Packit Service 95ac19
				warningf(false,
Packit Service 95ac19
				    "cannot read environment %s from %s: %s",
Packit Service 95ac19
				    dent->d_name, MKSH_ENVDIR,
Packit Service 95ac19
				    cstrerror(errno));
Packit Service 95ac19
				goto read_envfile;
Packit Service 95ac19
			}
Packit Service 95ac19
			afree(xp, ATEMP);
Packit Service 95ac19
			n = strlen(dent->d_name);
Packit Service 95ac19
			xp = Xstring(xs, xp);
Packit Service 95ac19
			XcheckN(xs, xp, n + 32);
Packit Service 95ac19
			memcpy(xp, dent->d_name, n);
Packit Service 95ac19
			xp += n;
Packit Service 95ac19
			*xp++ = '=';
Packit Service 95ac19
			while ((n = shf_read(xp, Xnleft(xs, xp), shf)) > 0) {
Packit Service 95ac19
				xp += n;
Packit Service 95ac19
				if (Xnleft(xs, xp) <= 0)
Packit Service 95ac19
					XcheckN(xs, xp, Xlength(xs, xp));
Packit Service 95ac19
			}
Packit Service 95ac19
			if (n < 0) {
Packit Service 95ac19
				warningf(false,
Packit Service 95ac19
				    "cannot read environment %s from %s: %s",
Packit Service 95ac19
				    dent->d_name, MKSH_ENVDIR,
Packit Service 95ac19
				    cstrerror(shf_errno(shf)));
Packit Service 95ac19
			} else {
Packit Service 95ac19
				*xp = '\0';
Packit Service 95ac19
				xp = Xstring(xs, xp);
Packit Service 95ac19
				rndpush(xp);
Packit Service 95ac19
				typeset(xp, IMPORT | EXPORT, 0, 0, 0);
Packit Service 95ac19
			}
Packit Service 95ac19
			shf_close(shf);
Packit Service 95ac19
		}
Packit Service 95ac19
		goto read_envfile;
Packit Service 95ac19
	} else if (errno)
Packit Service 95ac19
		warningf(false, "cannot read environment from %s: %s",
Packit Service 95ac19
		    MKSH_ENVDIR, cstrerror(errno));
Packit Service 95ac19
	closedir(dirp);
Packit Service 95ac19
	Xfree(xs, xp);
Packit Service 95ac19
}
Packit Service 95ac19
#else
Packit Service 95ac19
extern char **environ;
Packit Service 95ac19
Packit Service 95ac19
static void
Packit Service 95ac19
init_environ(void)
Packit Service 95ac19
{
Packit Service 95ac19
	const char **wp;
Packit Service 95ac19
Packit Service 95ac19
	if (environ == NULL)
Packit Service 95ac19
		return;
Packit Service 95ac19
Packit Service 95ac19
	wp = (const char **)environ;
Packit Service 95ac19
	while (*wp != NULL) {
Packit Service 95ac19
		rndpush(*wp);
Packit Service 95ac19
		typeset(*wp, IMPORT | EXPORT, 0, 0, 0);
Packit Service 95ac19
		++wp;
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
#ifdef MKSH_EARLY_LOCALE_TRACKING
Packit Service 95ac19
void
Packit Service 95ac19
recheck_ctype(void)
Packit Service 95ac19
{
Packit Service 95ac19
	const char *ccp;
Packit Service 95ac19
Packit Service 95ac19
	ccp = str_val(global("LC_ALL"));
Packit Service 95ac19
	if (ccp == null)
Packit Service 95ac19
		ccp = str_val(global("LC_CTYPE"));
Packit Service 95ac19
	if (ccp == null)
Packit Service 95ac19
		ccp = str_val(global("LANG"));
Packit Service 95ac19
	UTFMODE = isuc(ccp);
Packit Service 95ac19
#if HAVE_SETLOCALE_CTYPE
Packit Service 95ac19
	ccp = setlocale(LC_CTYPE, ccp);
Packit Service 95ac19
#if HAVE_LANGINFO_CODESET
Packit Service 95ac19
	if (!isuc(ccp))
Packit Service 95ac19
		ccp = nl_langinfo(CODESET);
Packit Service 95ac19
#endif
Packit Service 95ac19
	if (isuc(ccp))
Packit Service 95ac19
		UTFMODE = 1;
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
	if (Flag(FPOSIX))
Packit Service 95ac19
		warningf(true, "early locale tracking enabled UTF-8 mode while in POSIX mode, you are now noncompliant");
Packit Service 95ac19
}
Packit Service 95ac19
#endif