15155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*	$OpenBSD: history.c,v 1.39 2010/05/19 17:36:08 jasper Exp $	*/
25155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*	$OpenBSD: trap.c,v 1.23 2010/05/19 17:36:08 jasper Exp $	*/
35155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
45155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*-
5c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
6427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes *		 2011, 2012, 2014
75155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	Thorsten Glaser <tg@mirbsd.org>
85155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
95155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Provided that these terms and disclaimer and all copyright notices
105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * are retained or reproduced in an accompanying document, permission
115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * is granted to deal in this work without restriction, including un-
125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * limited rights to use, publicly perform, distribute, sell, modify,
135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * merge, give away, or sublicence.
145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * the utmost extent permitted by applicable law, neither express nor
175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * implied; without malicious intent or gross negligence. In no event
185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * may a licensor, author or contributor be held liable for indirect,
195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * direct, other damage, loss, or other issues arising in any way out
205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * of dealing in the work, even if advised of the possibility of such
215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * damage or existence of a defect, except proven that it results out
225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * of said person's immediate fault when using the work as intended.
235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#include "sh.h"
2603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#if HAVE_SYS_FILE_H
275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#include <sys/file.h>
285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
30427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.134 2014/06/09 13:25:53 tg Exp $");
315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste QueruTrap sigtraps[NSIG + 1];
335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct sigaction Sigact_ign;
345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if HAVE_PERSISTENT_HISTORY
36c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic int histload(Source *, unsigned char *, size_t);
37c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic int writehistline(int, int, const char *);
38c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic void writehistfile(int, const char *);
395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int hist_execute(char *);
425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic char **hist_get(const char *, bool, bool);
435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic char **hist_get_oldest(void);
445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
45c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic bool hstarted;		/* set after hist_init() called */
465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic Source *hist_source;
475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if HAVE_PERSISTENT_HISTORY
49c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser/*XXX imake style */
50c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#if defined(__linux)
51c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#define caddr_cast(x)	((void *)(x))
52c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#else
53c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#define caddr_cast(x)	((caddr_t)(x))
54c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
55c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
56c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser/* several OEs do not have these constants */
57c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifndef MAP_FAILED
58c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#define MAP_FAILED	caddr_cast(-1)
59c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
60c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
61c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser/* some OEs need the default mapping type specified */
62c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifndef MAP_FILE
63c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#define MAP_FILE	0
64c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
65c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
6603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* current history file: name, fd, size */
6703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic char *hname;
68c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic int histfd = -1;
69c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic off_t histfsize;
705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic const char Tnot_in_history[] = "not in history";
7303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define Thistory (Tnot_in_history + 7)
7403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
75c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const char TFCEDIT_dollaru[] = "${FCEDIT:-/bin/ed} $_";
76c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#define Tspdollaru (TFCEDIT_dollaru + 18)
77c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
78c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser/* HISTSIZE default: size of saved history, persistent or standard */
79c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifdef MKSH_SMALL
80c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#define MKSH_DEFHISTSIZE	255
81c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#else
82c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#define MKSH_DEFHISTSIZE	2047
83c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
84c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser/* maximum considered size of persistent history file */
85c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#define MKSH_MAXHISTFSIZE	((off_t)1048576 * 96)
86c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruc_fc(const char **wp)
895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct shf *shf;
915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct temp *tf;
925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	bool gflag = false, lflag = false, nflag = false, rflag = false,
935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    sflag = false;
945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int optc;
95c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	const char *p, *first = NULL, *last = NULL;
96c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	char **hfirst, **hlast, **hp, *editor = NULL;
975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!Flag(FTALKING_I)) {
9903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		bi_errorf("history %ss not available", Tfunction);
1005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (1);
1015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while ((optc = ksh_getopt(wp, &builtin_opt,
1045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    "e:glnrs0,1,2,3,4,5,6,7,8,9,")) != -1)
1055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		switch (optc) {
10603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
1075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case 'e':
1085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			p = builtin_opt.optarg;
1095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (ksh_isdash(p))
1105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				sflag = true;
1115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else {
1125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				size_t len = strlen(p);
11303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
11403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* almost certainly not overflowing */
1155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				editor = alloc(len + 4, ATEMP);
1165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				memcpy(editor, p, len);
117c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				memcpy(editor + len, Tspdollaru, 4);
1185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
1195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
12003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
12103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* non-AT&T ksh */
12203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case 'g':
1235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			gflag = true;
1245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
12503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
1265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case 'l':
1275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			lflag = true;
1285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
12903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
1305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case 'n':
1315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			nflag = true;
1325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
13303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
1345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case 'r':
1355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			rflag = true;
1365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
13703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
13803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* POSIX version of -e - */
13903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case 's':
1405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			sflag = true;
1415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
14203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
1435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* kludge city - accept -num as -- -num (kind of) */
1445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case '0': case '1': case '2': case '3': case '4':
1455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case '5': case '6': case '7': case '8': case '9':
1465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			p = shf_smprintf("-%c%s",
1475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					optc, builtin_opt.optarg);
1485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (!first)
1495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				first = p;
1505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else if (!last)
1515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				last = p;
1525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else {
1535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				bi_errorf("too many arguments");
1545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (1);
1555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
1565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
15703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
1585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case '?':
1595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (1);
1605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	wp += builtin_opt.optind;
1625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Substitute and execute command */
1645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (sflag) {
165c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		char *pat = NULL, *rep = NULL, *line;
1665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (editor || lflag || nflag || rflag) {
1685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			bi_errorf("can't use -e, -l, -n, -r with -s (-e -)");
1695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (1);
1705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* Check for pattern replacement argument */
1735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (*wp && **wp && (p = cstrchr(*wp + 1, '='))) {
1745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			strdupx(pat, *wp, ATEMP);
1755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			rep = pat + (p - *wp);
1765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*rep++ = '\0';
1775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			wp++;
1785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* Check for search prefix */
1805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!first && (first = *wp))
1815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			wp++;
1825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (last || *wp) {
1835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			bi_errorf("too many arguments");
1845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (1);
1855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		hp = first ? hist_get(first, false, false) :
1885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    hist_get_newest(false);
1895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!hp)
1905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (1);
191c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* hist_replace */
192c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (!pat)
193c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			strdupx(line, *hp, ATEMP);
194c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		else {
195c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			char *s, *s1;
196c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			size_t len, pat_len, rep_len;
197c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			XString xs;
198c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			char *xp;
199c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			bool any_subst = false;
200c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
201c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			pat_len = strlen(pat);
202c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			rep_len = strlen(rep);
203c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			Xinit(xs, xp, 128, ATEMP);
204c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			for (s = *hp; (s1 = strstr(s, pat)) &&
205c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			    (!any_subst || gflag); s = s1 + pat_len) {
206c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				any_subst = true;
207c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				len = s1 - s;
208c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				XcheckN(xs, xp, len + rep_len);
209c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				/*; first part */
210c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				memcpy(xp, s, len);
211c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				xp += len;
212c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				/* replacement */
213c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				memcpy(xp, rep, rep_len);
214c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				xp += rep_len;
215c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			}
216c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			if (!any_subst) {
217c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				bi_errorf("bad substitution");
218c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				return (1);
219c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			}
220c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			len = strlen(s) + 1;
221c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			XcheckN(xs, xp, len);
222c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			memcpy(xp, s, len);
223c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			xp += len;
224c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			line = Xclose(xs, xp);
225c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		}
226c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return (hist_execute(line));
2275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (editor && (lflag || nflag)) {
2305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		bi_errorf("can't use -l, -n with -e");
2315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (1);
2325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!first && (first = *wp))
2355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		wp++;
2365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!last && (last = *wp))
2375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		wp++;
2385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (*wp) {
2395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		bi_errorf("too many arguments");
2405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (1);
2415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!first) {
2435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		hfirst = lflag ? hist_get("-16", true, true) :
2445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    hist_get_newest(false);
2455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!hfirst)
2465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (1);
2475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* can't fail if hfirst didn't fail */
2485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		hlast = hist_get_newest(false);
2495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else {
25003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
25103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * POSIX says not an error if first/last out of bounds
25203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * when range is specified; AT&T ksh and pdksh allow out
25303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * of bounds for -l as well.
2545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
25503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		hfirst = hist_get(first, tobool(lflag || last), lflag);
2565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!hfirst)
2575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (1);
2585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		hlast = last ? hist_get(last, true, lflag) :
2595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (lflag ? hist_get_newest(false) : hfirst);
2605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!hlast)
2615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (1);
2625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (hfirst > hlast) {
2645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		char **temp;
2655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		temp = hfirst; hfirst = hlast; hlast = temp;
26703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* POSIX */
26803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		rflag = !rflag;
2695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* List history */
2725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (lflag) {
2735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		char *s, *t;
2745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (hp = rflag ? hlast : hfirst;
2765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    hp >= hfirst && hp <= hlast; hp += rflag ? -1 : 1) {
2775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (!nflag)
2785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				shf_fprintf(shl_stdout, "%d",
2795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    hist_source->line - (int)(histptr - hp));
2805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			shf_putc('\t', shl_stdout);
2815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* print multi-line commands correctly */
2825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			s = *hp;
2835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			while ((t = strchr(s, '\n'))) {
2845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*t = '\0';
2855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				shf_fprintf(shl_stdout, "%s\n\t", s);
2865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*t++ = '\n';
2875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				s = t;
2885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
2895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			shf_fprintf(shl_stdout, "%s\n", s);
2905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
2915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf_flush(shl_stdout);
2925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (0);
2935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Run editor on selected lines, then run resulting commands */
2965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	tf = maketemp(ATEMP, TT_HIST_EDIT, &e->temps);
2985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(shf = tf->shf)) {
29903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		bi_errorf("can't %s temporary file %s: %s",
300c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		    "create", tf->tffn, cstrerror(errno));
3015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (1);
3025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
3035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (hp = rflag ? hlast : hfirst;
3045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    hp >= hfirst && hp <= hlast; hp += rflag ? -1 : 1)
3055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf_fprintf(shf, "%s\n", *hp);
3065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf_close(shf) == EOF) {
30703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		bi_errorf("can't %s temporary file %s: %s",
308c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		    "write", tf->tffn, cstrerror(errno));
3095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (1);
3105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
3115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Ignore setstr errors here (arbitrary) */
313c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	setstr(local("_", false), tf->tffn, KSH_RETURN_ERROR);
3145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* XXX: source should not get trashed by this.. */
3165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{
3175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		Source *sold = source;
3185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		int ret;
3195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
320c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		ret = command(editor ? editor : TFCEDIT_dollaru, 0);
3215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		source = sold;
3225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (ret)
3235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (ret);
3245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
3255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{
3275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		struct stat statb;
3285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XString xs;
3295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		char *xp;
330c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		ssize_t n;
3315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
332c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (!(shf = shf_open(tf->tffn, O_RDONLY, 0, 0))) {
33303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			bi_errorf("can't %s temporary file %s: %s",
334c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			    "open", tf->tffn, cstrerror(errno));
3355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (1);
3365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
3375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
338c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (stat(tf->tffn, &statb) < 0)
33903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			n = 128;
340c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		else if ((off_t)statb.st_size > MKSH_MAXHISTFSIZE) {
34103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			bi_errorf("%s %s too large: %lu", Thistory,
34203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			    "file", (unsigned long)statb.st_size);
34303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			goto errout;
34403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		} else
345c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			n = (size_t)statb.st_size + 1;
3465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		Xinit(xs, xp, n, hist_source->areap);
3475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while ((n = shf_read(xp, Xnleft(xs, xp), shf)) > 0) {
3485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			xp += n;
3495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (Xnleft(xs, xp) <= 0)
3505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				XcheckN(xs, xp, Xlength(xs, xp));
3515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
3525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (n < 0) {
35303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			bi_errorf("can't %s temporary file %s: %s",
354c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			    "read", tf->tffn, cstrerror(shf_errno(shf)));
35503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra errout:
3565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			shf_close(shf);
3575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (1);
3585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
3595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf_close(shf);
3605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*xp = '\0';
3615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		strip_nuls(Xstring(xs, xp), Xlength(xs, xp));
3625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (hist_execute(Xstring(xs, xp)));
3635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
3645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
3655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Save cmd in history, execute cmd (cmd gets trashed) */
3675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
3685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruhist_execute(char *cmd)
3695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
370c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	static int last_line = -1;
3715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Source *sold;
3725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int ret;
3735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *p, *q;
3745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
375c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* Back up over last histsave */
376c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (histptr >= history && last_line != hist_source->line) {
377c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		hist_source->line--;
378c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		afree(*histptr, APERM);
379c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		histptr--;
380c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		last_line = hist_source->line;
381c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	}
3825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (p = cmd; p; p = q) {
3845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((q = strchr(p, '\n'))) {
38503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* kill the newline */
38603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			*q++ = '\0';
38703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (!*q)
38803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* ignore trailing newline */
3895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				q = NULL;
3905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
3915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		histsave(&hist_source->line, p, true, true);
3925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
39303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* POSIX doesn't say this is done... */
39403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		shellf("%s\n", p);
39503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (q)
39603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* restore \n (trailing \n not restored) */
3975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			q[-1] = '\n';
3985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
3995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
40003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*-
4015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * Commands are executed here instead of pushing them onto the
4025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * input 'cause POSIX says the redirection and variable assignments
4035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * in
4045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 *	X=y fc -e - 42 2> /dev/null
4055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * are to effect the repeated commands environment.
4065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
4075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* XXX: source should not get trashed by this.. */
4085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	sold = source;
4095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	ret = command(cmd, 0);
4105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	source = sold;
4115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (ret);
4125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
4135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
4155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * get pointer to history given pattern
4165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * pattern is a number or string
4175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
4185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic char **
4195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruhist_get(const char *str, bool approx, bool allow_cur)
4205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
4215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char **hp = NULL;
4225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int n;
4235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (getn(str, &n)) {
4255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		hp = histptr + (n < 0 ? n : (n - hist_source->line));
4265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((ptrdiff_t)hp < (ptrdiff_t)history) {
4275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (approx)
4285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				hp = hist_get_oldest();
4295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else {
43003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				bi_errorf("%s: %s", str, Tnot_in_history);
4315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				hp = NULL;
4325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
4335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else if ((ptrdiff_t)hp > (ptrdiff_t)histptr) {
4345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (approx)
4355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				hp = hist_get_newest(allow_cur);
4365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else {
43703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				bi_errorf("%s: %s", str, Tnot_in_history);
4385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				hp = NULL;
4395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
4405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else if (!allow_cur && hp == histptr) {
44103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			bi_errorf("%s: %s", str, "invalid range");
4425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			hp = NULL;
4435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
4445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else {
445427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes		bool anchored = *str == '?' ? (++str, false) : true;
4465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* the -1 is to avoid the current fc command */
4485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((n = findhist(histptr - history - 1, 0, str, anchored)) < 0)
44903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			bi_errorf("%s: %s", str, Tnot_in_history);
4505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else
4515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			hp = &history[n];
4525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
4535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (hp);
4545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
4555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Return a pointer to the newest command in the history */
4575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar **
4585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruhist_get_newest(bool allow_cur)
4595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
4605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (histptr < history || (!allow_cur && histptr == history)) {
4615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		bi_errorf("no history (yet)");
4625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (NULL);
4635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
4645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (allow_cur ? histptr : histptr - 1);
4655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
4665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Return a pointer to the oldest command in the history */
4685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic char **
4695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruhist_get_oldest(void)
4705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
4715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (histptr <= history) {
4725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		bi_errorf("no history (yet)");
4735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (NULL);
4745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
4755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (history);
4765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
4775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
478c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#if !defined(MKSH_NO_CMDLINE_EDITING) && !MKSH_S_NOVI
479c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser/* current position in history[] */
480c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic char **current;
4815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
4835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Return the current position.
4845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
4855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar **
4865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruhistpos(void)
4875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
4885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (current);
4895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
4905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
4925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruhistnum(int n)
4935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
4945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int last = histptr - history;
4955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (n < 0 || n >= last) {
4975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		current = histptr;
4985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (last);
4995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else {
5005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		current = &history[n];
5015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (n);
5025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
5035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
504c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
5055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
5075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * This will become unnecessary if hist_get is modified to allow
5085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * searching from positions other than the end, and in either
5095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * direction.
5105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
5115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
512427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughesfindhist(int start, int fwd, const char *str, bool anchored)
5135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
51403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char **hp;
51503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int maxhist = histptr - history;
51603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int incr = fwd ? 1 : -1;
51703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	size_t len = strlen(str);
5185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (start < 0 || start >= maxhist)
5205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		start = maxhist;
5215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	hp = &history[start];
5235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (; hp >= history && hp <= histptr; hp += incr)
5245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((anchored && strncmp(*hp, str, len) == 0) ||
5255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (!anchored && strstr(*hp, str)))
5265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (hp - history);
5275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (-1);
5295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
5305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
532c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * set history; this means reallocating the dataspace
5335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
5345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
535c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glasersethistsize(mksh_ari_t n)
5365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
5375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (n > 0 && n != histsize) {
5385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		int cursize = histptr - history;
5395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* save most recent history */
5415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (n < cursize) {
542c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			memmove(history, histptr - n + 1, n * sizeof(char *));
543c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			cursize = n - 1;
5445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
5455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
54603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		history = aresize2(history, n, sizeof(char *), APERM);
5475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		histsize = n;
5495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		histptr = history + cursize;
5505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
5515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
5525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if HAVE_PERSISTENT_HISTORY
5545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
555c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * set history file; this can mean reloading/resetting/starting
556c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * history file maintenance
5575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
5585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
5595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querusethistfile(const char *name)
5605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
5615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* if not started then nothing to do */
562c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (hstarted == false)
5635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return;
5645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* if the name is the same as the name we have */
5665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (hname && strcmp(hname, name) == 0)
5675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return;
5685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/*
570c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	 * it's a new name - possibly
5715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
572c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (histfd != -1) {
5735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* yes the file is open */
5745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		(void)close(histfd);
575c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		histfd = -1;
576c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		histfsize = 0;
5775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		afree(hname, APERM);
5785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		hname = NULL;
5795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* let's reset the history */
5805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		histptr = history - 1;
5815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		hist_source->line = 0;
5825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
5835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	hist_init(hist_source);
5855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
5865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
5875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
589c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * initialise the history vector
5905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
5915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
5925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruinit_histvec(void)
5935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
5945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (history == (char **)NULL) {
595c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		histsize = MKSH_DEFHISTSIZE;
59603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		history = alloc2(histsize, sizeof(char *), APERM);
5975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		histptr = history - 1;
5985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
5995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
6005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
603c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * It turns out that there is a lot of ghastly hackery here
6045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
6055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if !defined(MKSH_SMALL) && HAVE_PERSISTENT_HISTORY
6075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* do not save command in history but possibly sync */
6085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querubool
6095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruhistsync(void)
6105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
6115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	bool changed = false;
6125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
613c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (histfd != -1) {
6145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		int lno = hist_source->line;
6155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		hist_source->line++;
6175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		writehistfile(0, NULL);
6185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		hist_source->line--;
6195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (lno != hist_source->line)
6215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			changed = true;
6225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
6235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (changed);
6255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
6265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
6275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
6295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * save command in history
6305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
6315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
6325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruhistsave(int *lnp, const char *cmd, bool dowrite MKSH_A_UNUSED, bool ignoredups)
6335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
6345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char **hp;
6355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *c, *cp;
6365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
637c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	mkssert(cmd != NULL);
6385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	strdupx(c, cmd, APERM);
6395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((cp = strchr(c, '\n')) != NULL)
6405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*cp = '\0';
6415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (ignoredups && !strcmp(c, *histptr)
6435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if !defined(MKSH_SMALL) && HAVE_PERSISTENT_HISTORY
6445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    && !histsync()
6455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
6465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    ) {
6475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		afree(c, APERM);
6485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return;
6495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
6505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	++*lnp;
6515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if HAVE_PERSISTENT_HISTORY
653c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (dowrite && histfd != -1)
6545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		writehistfile(*lnp, c);
6555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
6565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	hp = histptr;
6585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
65903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (++hp >= history + histsize) {
66003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* remove oldest command */
6615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		afree(*history, APERM);
6625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (hp = history; hp < history + histsize - 1; hp++)
6635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			hp[0] = hp[1];
6645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
6655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	*hp = c;
6665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	histptr = hp;
6675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
6685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
670c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * Write history data to a file nominated by HISTFILE;
671c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * if HISTFILE is unset then history still happens, but
672c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * the data is not written to a file. All copies of ksh
673c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * looking at the file will maintain the same history.
674c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * This is ksh behaviour.
675c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser *
676c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * This stuff uses mmap()
6775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
678c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * This stuff is so totally broken it must eventually be
679c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * redesigned, without mmap, better checks, support for
680c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * larger files, etc. and handle partially corrupted files
6815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
6825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
68303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*-
684c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * Open a history file
685c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * Format is:
686c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * Bytes 1, 2:
687c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser *	HMAGIC - just to check that we are dealing with the correct object
688c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * Then follows a number of stored commands
689c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * Each command is
690c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser *	<command byte><command number(4 octets, big endian)><bytes><NUL>
6915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
692c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#define HMAGIC1		0xAB
693c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#define HMAGIC2		0xCD
694c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#define COMMAND		0xFF
695c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
696c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#if HAVE_PERSISTENT_HISTORY
697c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const unsigned char sprinkle[2] = { HMAGIC1, HMAGIC2 };
698c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
6995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
7015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruhist_init(Source *s)
7025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
7035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if HAVE_PERSISTENT_HISTORY
7045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	unsigned char *base;
705c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	int lines, fd;
706c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	enum { hist_init_first, hist_init_retry, hist_init_restore } hs;
7075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
7085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (Flag(FTALKING) == 0)
7105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return;
7115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
712c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	hstarted = true;
7135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	hist_source = s;
7145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if HAVE_PERSISTENT_HISTORY
7165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((hname = str_val(global("HISTFILE"))) == NULL)
7175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return;
7185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	strdupx(hname, hname, APERM);
719c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	hs = hist_init_first;
7205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru retry:
7225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* we have a file and are interactive */
723427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes	if ((fd = open(hname, O_RDWR | O_CREAT | O_APPEND | O_BINARY,
724427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes	    0600)) < 0)
7255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return;
7265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	histfd = savefd(fd);
7285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (histfd != fd)
7295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		close(fd);
7305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
731c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	mksh_lockfd(histfd);
7325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
733c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	histfsize = lseek(histfd, (off_t)0, SEEK_END);
734c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (histfsize > MKSH_MAXHISTFSIZE || hs == hist_init_restore) {
735c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* we ignore too large files but still append to them */
736c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* we also don't need to re-read after truncation */
737c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		goto hist_init_tail;
738c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	} else if (histfsize > 2) {
739c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* we have some data, check its validity */
740c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		base = (void *)mmap(NULL, (size_t)histfsize, PROT_READ,
7415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    MAP_FILE | MAP_PRIVATE, histfd, (off_t)0);
742c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (base == (unsigned char *)MAP_FAILED)
743c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			goto hist_init_fail;
744c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (base[0] != HMAGIC1 || base[1] != HMAGIC2) {
745c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			munmap(caddr_cast(base), (size_t)histfsize);
746c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			goto hist_init_fail;
747c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		}
748c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* load _all_ data */
749c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		lines = histload(hist_source, base + 2, (size_t)histfsize - 2);
750c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		munmap(caddr_cast(base), (size_t)histfsize);
751c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* check if the file needs to be truncated */
752c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (lines > histsize && histptr >= history) {
753c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* you're fucked up with the current code, trust me */
754c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			char *nhname, **hp;
755c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			struct stat sb;
756c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
757c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* create temporary file */
758c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			nhname = shf_smprintf("%s.%d", hname, (int)procpid);
759c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			if ((fd = open(nhname, O_RDWR | O_CREAT | O_TRUNC |
760427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes			    O_EXCL | O_BINARY, 0600)) < 0) {
761c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				/* just don't truncate then, meh. */
762c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				goto hist_trunc_dont;
763c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			}
764c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			if (fstat(histfd, &sb) >= 0 &&
765c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			    chown(nhname, sb.st_uid, sb.st_gid)) {
766c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				/* abort the truncation then, meh. */
767c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				goto hist_trunc_abort;
768c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			}
769c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* we definitively want some magic in that file */
770c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			if (write(fd, sprinkle, 2) != 2)
771c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				goto hist_trunc_abort;
772c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* and of course the entries */
773c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			hp = history;
774c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			while (hp < histptr) {
775c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				if (!writehistline(fd,
776c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				    s->line - (histptr - hp), *hp))
777c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					goto hist_trunc_abort;
778c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				++hp;
779c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			}
780c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* now unlock, close both, rename, rinse, repeat */
781c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			close(fd);
782c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			fd = -1;
7835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			hist_finish();
784c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			if (rename(nhname, hname) < 0) {
785c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser hist_trunc_abort:
786c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				if (fd != -1)
787c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					close(fd);
788c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				unlink(nhname);
789c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				if (fd != -1)
790c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					goto hist_trunc_dont;
791c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				/* darn! restore histfd and pray */
792c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			}
793c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			hs = hist_init_restore;
794c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser hist_trunc_dont:
795c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			afree(nhname, ATEMP);
796c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			if (hs == hist_init_restore)
797c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				goto retry;
798c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		}
799c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	} else if (histfsize != 0) {
800c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* negative or too small... */
801c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser hist_init_fail:
802c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* ... or mmap failed or illegal */
803c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		hist_finish();
804c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* nuke the bogus file then retry, at most once */
805c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (!unlink(hname) && hs != hist_init_retry) {
806c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			hs = hist_init_retry;
8075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto retry;
8085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
809c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (hs != hist_init_retry)
810c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			bi_errorf("can't %s %s: %s",
811c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			    "unlink HISTFILE", hname, cstrerror(errno));
812c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		histfsize = 0;
813c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return;
814c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	} else {
815c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* size 0, add magic to the history file */
816c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (write(histfd, sprinkle, 2) != 2) {
817c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			hist_finish();
818c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			return;
8195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
8205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
821c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	histfsize = lseek(histfd, (off_t)0, SEEK_END);
822c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser hist_init_tail:
823c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	mksh_unlkfd(histfd);
8245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
8255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
8265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if HAVE_PERSISTENT_HISTORY
8285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
829c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * load the history structure from the stored data
8305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
8315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
832c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserhistload(Source *s, unsigned char *base, size_t bytes)
8335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
834c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	int lno = 0, lines = 0;
835c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	unsigned char *cp;
836c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
837c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser histload_loop:
838c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* !bytes check as some systems (older FreeBSDs) have buggy memchr */
839c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (!bytes || (cp = memchr(base, COMMAND, bytes)) == NULL)
840c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return (lines);
841c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* advance base pointer past COMMAND byte */
842c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	bytes -= ++cp - base;
843c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	base = cp;
844c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* if there is no full string left, don't bother with the rest */
845c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (bytes < 5 || (cp = memchr(base + 4, '\0', bytes - 4)) == NULL)
846c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return (lines);
847c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* load the stored line number */
848c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	lno = ((base[0] & 0xFF) << 24) | ((base[1] & 0xFF) << 16) |
849c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	    ((base[2] & 0xFF) << 8) | (base[3] & 0xFF);
850c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* store away the found line (@base[4]) */
851c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	++lines;
852c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (histptr >= history && lno - 1 != s->line) {
853c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* a replacement? */
854c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		char **hp;
855c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
856c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (lno >= s->line - (histptr - history) && lno <= s->line) {
857c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			hp = &histptr[lno - s->line];
858c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			if (*hp)
859c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				afree(*hp, APERM);
860c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			strdupx(*hp, (char *)(base + 4), APERM);
8615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
862c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	} else {
863c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		s->line = lno--;
864c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		histsave(&lno, (char *)(base + 4), false, false);
8655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
866c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* advance base pointer past NUL */
867c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	bytes -= ++cp - base;
868c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	base = cp;
869c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* repeat until no more */
870c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	goto histload_loop;
8715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
8725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
874c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * write a command to the end of the history file
875c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser *
876c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * This *MAY* seem easy but it's also necessary to check
877c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * that the history file has not changed in size.
878c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * If it has - then some other shell has written to it and
879c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * we should (re)read those commands to update our history
8805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
8815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
882c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserwritehistfile(int lno, const char *cmd)
8835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
88403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	off_t sizenow;
885c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	size_t bytes;
886c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	unsigned char *base, *news;
8875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
888c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	mksh_lockfd(histfd);
8895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	sizenow = lseek(histfd, (off_t)0, SEEK_END);
890c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (sizenow < histfsize) {
891c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* the file has shrunk; give up */
892c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		goto bad;
893c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	}
894c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (
895c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* ignore changes when the file is too large */
896c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		sizenow <= MKSH_MAXHISTFSIZE
897c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	    &&
898c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* the size has changed, we need to do read updates */
899c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		sizenow > histfsize
900c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	    ) {
901c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* both sizenow and histfsize are <= MKSH_MAXHISTFSIZE */
902c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		bytes = (size_t)(sizenow - histfsize);
903c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		base = (void *)mmap(NULL, (size_t)sizenow, PROT_READ,
904c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		    MAP_FILE | MAP_PRIVATE, histfd, (off_t)0);
905c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (base == (unsigned char *)MAP_FAILED)
906c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			goto bad;
907c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		news = base + (size_t)histfsize;
908c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (*news == COMMAND) {
9095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			hist_source->line--;
9105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			histload(hist_source, news, bytes);
9115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			hist_source->line++;
9125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			lno = hist_source->line;
913c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		} else
914c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			bytes = 0;
915c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		munmap(caddr_cast(base), (size_t)sizenow);
916c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (!bytes)
9175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto bad;
9185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
919c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (cmd && !writehistline(histfd, lno, cmd)) {
9205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru bad:
921c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		hist_finish();
922c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return;
923c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	}
924c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	histfsize = lseek(histfd, (off_t)0, SEEK_END);
925c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	mksh_unlkfd(histfd);
9265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
9275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
928c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic int
929c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserwritehistline(int fd, int lno, const char *cmd)
9305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
931c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	ssize_t n;
932c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	unsigned char hdr[5];
933c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
934c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	hdr[0] = COMMAND;
935c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	hdr[1] = (lno >> 24) & 0xFF;
936c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	hdr[2] = (lno >> 16) & 0xFF;
937c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	hdr[3] = (lno >> 8) & 0xFF;
938c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	hdr[4] = lno & 0xFF;
939c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	n = strlen(cmd) + 1;
940c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	return (write(fd, hdr, 5) == 5 && write(fd, cmd, n) == n);
9415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
9425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
943c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaservoid
944c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserhist_finish(void)
9455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
946c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (histfd >= 0) {
947c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		mksh_unlkfd(histfd);
948c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		(void)close(histfd);
949c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	}
950c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	histfd = -1;
9515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
9525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
9535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
954c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
9555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if !HAVE_SYS_SIGNAME
9565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const struct mksh_sigpair {
957c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	const char * const name;
9585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int nr;
9595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} mksh_sigpairs[] = {
9605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#include "signames.inc"
9615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ NULL, 0 }
9625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru};
9635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
9645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
965c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#if HAVE_SYS_SIGLIST
966c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#if !HAVE_SYS_SIGLIST_DECL
967c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserextern const char * const sys_siglist[];
968c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
969c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
970c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
9715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
9725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruinittraps(void)
9735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
9745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int i;
9755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *cs;
9765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
97703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	trap_exstat = -1;
97803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
9795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Populate sigtraps based on sys_signame and sys_siglist. */
980427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes	/*XXX this is idiotic, use a multi-key/value hashtable! */
9815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (i = 0; i <= NSIG; i++) {
9825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sigtraps[i].signal = i;
98303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (i == ksh_SIGERR) {
9845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			sigtraps[i].name = "ERR";
9855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			sigtraps[i].mess = "Error handler";
9865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else {
9875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if HAVE_SYS_SIGNAME
9885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			cs = sys_signame[i];
9895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#else
9905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			const struct mksh_sigpair *pair = mksh_sigpairs;
9915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			while ((pair->nr != i) && (pair->name != NULL))
9925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				++pair;
9935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			cs = pair->name;
9945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
9955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((cs == NULL) ||
9965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    (cs[0] == '\0'))
9975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				sigtraps[i].name = shf_smprintf("%d", i);
9985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else {
9995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				char *s;
10005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1001c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				/* this is not optimal, what about SIGSIG1? */
1002c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				if ((cs[0] & 0xDF) == 'S' &&
1003c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				    (cs[1] & 0xDF) == 'I' &&
1004c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				    (cs[2] & 0xDF) == 'G' &&
1005c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				    cs[3] != '\0') {
1006c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					/* skip leading "SIG" */
10075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					cs += 3;
1008c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				}
10095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				strdupx(s, cs, APERM);
10105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				sigtraps[i].name = s;
10115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				while ((*s = ksh_toupper(*s)))
10125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					++s;
10135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
10145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if HAVE_SYS_SIGLIST
10155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			sigtraps[i].mess = sys_siglist[i];
10165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#elif HAVE_STRSIGNAL
10175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			sigtraps[i].mess = strsignal(i);
10185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#else
10195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			sigtraps[i].mess = NULL;
10205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
10215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((sigtraps[i].mess == NULL) ||
10225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    (sigtraps[i].mess[0] == '\0'))
102303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				sigtraps[i].mess = shf_smprintf("%s %d",
102403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				    "Signal", i);
10255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
10265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
102703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* our name for signal 0 */
102803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	sigtraps[ksh_SIGEXIT].name = "EXIT";
10295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	(void)sigemptyset(&Sigact_ign.sa_mask);
10315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Sigact_ign.sa_flags = 0; /* interruptible */
10325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Sigact_ign.sa_handler = SIG_IGN;
10335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	sigtraps[SIGINT].flags |= TF_DFL_INTR | TF_TTY_INTR;
10355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	sigtraps[SIGQUIT].flags |= TF_DFL_INTR | TF_TTY_INTR;
103603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* SIGTERM is not fatal for interactive */
103703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	sigtraps[SIGTERM].flags |= TF_DFL_INTR;
10385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	sigtraps[SIGHUP].flags |= TF_FATAL;
10395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	sigtraps[SIGCHLD].flags |= TF_SHELL_USES;
10405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* these are always caught so we can clean up any temporary files. */
10425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	setsig(&sigtraps[SIGINT], trapsig, SS_RESTORE_ORIG);
10435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	setsig(&sigtraps[SIGQUIT], trapsig, SS_RESTORE_ORIG);
10445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	setsig(&sigtraps[SIGTERM], trapsig, SS_RESTORE_ORIG);
10455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	setsig(&sigtraps[SIGHUP], trapsig, SS_RESTORE_ORIG);
10465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void alarm_catcher(int sig);
10495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
10515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querualarm_init(void)
10525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
10535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	sigtraps[SIGALRM].flags |= TF_SHELL_USES;
10545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	setsig(&sigtraps[SIGALRM], alarm_catcher,
10555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP);
10565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* ARGSUSED */
10595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
10605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querualarm_catcher(int sig MKSH_A_UNUSED)
10615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
10625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* this runs inside interrupt context, with errno saved */
10635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (ksh_tmout_state == TMOUT_READING) {
10655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		int left = alarm(0);
10665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (left == 0) {
10685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ksh_tmout_state = TMOUT_LEAVING;
10695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			intrsig = 1;
10705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else
10715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			alarm(left);
10725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste QueruTrap *
1076c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glasergettrap(const char *cs, bool igncase)
10775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1078c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	int i;
10795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Trap *p;
1080c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	char *as;
10815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1082c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (ksh_isdigit(*cs)) {
1083c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return ((getn(cs, &i) && 0 <= i && i < NSIG) ?
1084c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		    (&sigtraps[i]) : NULL);
10855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1087c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* this breaks SIGSIG1, but we do that above anyway */
1088c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if ((cs[0] & 0xDF) == 'S' &&
1089c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	    (cs[1] & 0xDF) == 'I' &&
1090c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	    (cs[2] & 0xDF) == 'G' &&
1091c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	    cs[3] != '\0') {
1092c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* skip leading "SIG" */
1093c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		cs += 3;
1094c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	}
1095c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (igncase) {
1096c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		char *s;
1097c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1098c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		strdupx(as, cs, ATEMP);
1099c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		cs = s = as;
1100c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		while ((*s = ksh_toupper(*s)))
1101c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			++s;
1102c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	} else
1103c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		as = NULL;
1104c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1105c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	p = sigtraps;
1106c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	for (i = 0; i <= NSIG; i++) {
1107c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (!strcmp(p->name, cs))
1108c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			goto found;
1109c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		++p;
1110c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	}
1111c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	p = NULL;
1112c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser found:
1113c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	afree(as, ATEMP);
1114c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	return (p);
11155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
11165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
11185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * trap signal handler
11195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
11205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
11215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querutrapsig(int i)
11225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
11235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Trap *p = &sigtraps[i];
1124c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	int eno = errno;
11255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	trap = p->set = 1;
11275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (p->flags & TF_DFL_INTR)
11285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		intrsig = 1;
11295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((p->flags & TF_FATAL) && !p->trap) {
11305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		fatal_trap = 1;
11315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		intrsig = 1;
11325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
11335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (p->shtrap)
11345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		(*p->shtrap)(i);
1135c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	errno = eno;
11365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
11375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
11395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * called when we want to allow the user to ^C out of something - won't
11405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * work if user has trapped SIGINT.
11415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
11425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
11435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruintrcheck(void)
11445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
11455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (intrsig)
11465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		runtraps(TF_DFL_INTR|TF_FATAL);
11475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
11485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
11505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * called after EINTR to check if a signal with normally causes process
11515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * termination has been received.
11525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
11535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
11545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querufatal_trap_check(void)
11555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
11565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int i;
11575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Trap *p;
11585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* todo: should check if signal is fatal, not the TF_DFL_INTR flag */
11605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (p = sigtraps, i = NSIG+1; --i >= 0; p++)
11615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (p->set && (p->flags & (TF_DFL_INTR|TF_FATAL)))
11625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* return value is used as an exit code */
11635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (128 + p->signal);
11645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (0);
11655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
11665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
11685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Returns the signal number of any pending traps: ie, a signal which has
11695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * occurred for which a trap has been set or for which the TF_DFL_INTR flag
11705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * is set.
11715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
11725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
11735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querutrap_pending(void)
11745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
11755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int i;
11765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Trap *p;
11775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (p = sigtraps, i = NSIG+1; --i >= 0; p++)
11795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (p->set && ((p->trap && p->trap[0]) ||
11805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    ((p->flags & (TF_DFL_INTR|TF_FATAL)) && !p->trap)))
11815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (p->signal);
11825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (0);
11835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
11845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
11865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * run any pending traps. If intr is set, only run traps that
11875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * can interrupt commands.
11885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
11895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
11905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruruntraps(int flag)
11915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
11925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int i;
11935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Trap *p;
11945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (ksh_tmout_state == TMOUT_LEAVING) {
11965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ksh_tmout_state = TMOUT_EXECUTING;
11975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		warningf(false, "timed out waiting for input");
11985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		unwind(LEXIT);
11995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else
12005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/*
12015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * XXX: this means the alarm will have no effect if a trap
12025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * is caught after the alarm() was started...not good.
12035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
12045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ksh_tmout_state = TMOUT_EXECUTING;
12055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!flag)
12065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		trap = 0;
12075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (flag & TF_DFL_INTR)
12085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		intrsig = 0;
12095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (flag & TF_FATAL)
12105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		fatal_trap = 0;
121103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	++trap_nested;
12125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (p = sigtraps, i = NSIG+1; --i >= 0; p++)
12135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (p->set && (!flag ||
12145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    ((p->flags & flag) && p->trap == NULL)))
121503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			runtrap(p, false);
121603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (!--trap_nested)
121703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		runtrap(NULL, true);
12185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
12195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
122103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraruntrap(Trap *p, bool is_last)
12225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
122303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int old_changed = 0, i;
122403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char *trapstr;
122503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
122603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (p == NULL)
122703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* just clean up, see runtraps() above */
122803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		goto donetrap;
122903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	i = p->signal;
123003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	trapstr = p->trap;
12315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	p->set = 0;
123203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (trapstr == NULL) {
123303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* SIG_DFL */
12345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (p->flags & TF_FATAL) {
12355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* eg, SIGHUP */
1236c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			exstat = (int)ksh_min(128U + (unsigned)i, 255U);
12375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			unwind(LLEAVE);
12385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
12395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (p->flags & TF_DFL_INTR) {
12405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* eg, SIGINT, SIGQUIT, SIGTERM, etc. */
1241c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			exstat = (int)ksh_min(128U + (unsigned)i, 255U);
12425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			unwind(LINTR);
12435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
124403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		goto donetrap;
12455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
124603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (trapstr[0] == '\0')
124703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* SIG_IGN */
124803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		goto donetrap;
124903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (i == ksh_SIGEXIT || i == ksh_SIGERR) {
125003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* avoid recursion on these */
12515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		old_changed = p->flags & TF_CHANGED;
12525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		p->flags &= ~TF_CHANGED;
12535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		p->trap = NULL;
12545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
125503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (trap_exstat == -1)
1256c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		trap_exstat = exstat & 0xFF;
12575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/*
12585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * Note: trapstr is fully parsed before anything is executed, thus
12595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * no problem with afree(p->trap) in settrap() while still in use.
12605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
12615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	command(trapstr, current_lineno);
126203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (i == ksh_SIGEXIT || i == ksh_SIGERR) {
12635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (p->flags & TF_CHANGED)
12645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* don't clear TF_CHANGED */
12655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			afree(trapstr, APERM);
12665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else
12675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			p->trap = trapstr;
12685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		p->flags |= old_changed;
12695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
127003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
127103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra donetrap:
127203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* we're the last trap of a sequence executed */
127303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (is_last && trap_exstat != -1) {
127403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		exstat = trap_exstat;
127503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		trap_exstat = -1;
127603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
12775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
12785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* clear pending traps and reset user's trap handlers; used after fork(2) */
12805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
12815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querucleartraps(void)
12825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
12835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int i;
12845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Trap *p;
12855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	trap = 0;
12875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	intrsig = 0;
12885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	fatal_trap = 0;
12895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (i = NSIG+1, p = sigtraps; --i >= 0; p++) {
12905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		p->set = 0;
12915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((p->flags & TF_USER_SET) && (p->trap && p->trap[0]))
12925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			settrap(p, NULL);
12935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
12945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
12955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* restore signals just before an exec(2) */
12975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
12985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querurestoresigs(void)
12995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
13005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int i;
13015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Trap *p;
13025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (i = NSIG+1, p = sigtraps; --i >= 0; p++)
13045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (p->flags & (TF_EXEC_IGN|TF_EXEC_DFL))
13055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			setsig(p, (p->flags & TF_EXEC_IGN) ? SIG_IGN : SIG_DFL,
13065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    SS_RESTORE_CURR|SS_FORCE);
13075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
13085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
13105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querusettrap(Trap *p, const char *s)
13115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
13125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	sig_t f;
13135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (p->trap)
13155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		afree(p->trap, APERM);
131603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* handles s == NULL */
131703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	strdupx(p->trap, s, APERM);
13185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	p->flags |= TF_CHANGED;
13195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	f = !s ? SIG_DFL : s[0] ? trapsig : SIG_IGN;
13205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	p->flags |= TF_USER_SET;
13225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((p->flags & (TF_DFL_INTR|TF_FATAL)) && f == SIG_DFL)
13235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		f = trapsig;
13245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (p->flags & TF_SHELL_USES) {
13255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!(p->flags & TF_ORIG_IGN) || Flag(FTALKING)) {
13265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* do what user wants at exec time */
13275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL);
13285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (f == SIG_IGN)
13295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				p->flags |= TF_EXEC_IGN;
13305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else
13315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				p->flags |= TF_EXEC_DFL;
13325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
13335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/*
13355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * assumes handler already set to what shell wants it
13365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * (normally trapsig, but could be j_sigchld() or SIG_IGN)
13375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
13385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return;
13395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
13405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* todo: should we let user know signal is ignored? how? */
13425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	setsig(p, f, SS_RESTORE_CURR|SS_USER);
13435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
13445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
13465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Called by c_print() when writing to a co-process to ensure SIGPIPE won't
13475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * kill shell (unless user catches it and exits)
13485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
13495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
13505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querublock_pipe(void)
13515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
13525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int restore_dfl = 0;
13535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Trap *p = &sigtraps[SIGPIPE];
13545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) {
13565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		setsig(p, SIG_IGN, SS_RESTORE_CURR);
13575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (p->flags & TF_ORIG_DFL)
13585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			restore_dfl = 1;
13595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else if (p->cursig == SIG_DFL) {
13605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		setsig(p, SIG_IGN, SS_RESTORE_CURR);
136103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* restore to SIG_DFL */
136203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		restore_dfl = 1;
13635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
13645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (restore_dfl);
13655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
13665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Called by c_print() to undo whatever block_pipe() did */
13685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
13695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querurestore_pipe(int restore_dfl)
13705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
13715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (restore_dfl)
13725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		setsig(&sigtraps[SIGPIPE], SIG_DFL, SS_RESTORE_CURR);
13735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
13745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
13765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Set action for a signal. Action may not be set if original
13775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * action was SIG_IGN, depending on the value of flags and FTALKING.
13785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
13795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
13805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querusetsig(Trap *p, sig_t f, int flags)
13815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
13825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct sigaction sigact;
13835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
138403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (p->signal == ksh_SIGEXIT || p->signal == ksh_SIGERR)
13855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (1);
13865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1387c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	memset(&sigact, 0, sizeof(sigact));
1388c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
13895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/*
13905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * First time setting this signal? If so, get and note the current
13915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * setting.
13925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
13935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) {
13945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sigaction(p->signal, &Sigact_ign, &sigact);
13955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		p->flags |= sigact.sa_handler == SIG_IGN ?
13965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    TF_ORIG_IGN : TF_ORIG_DFL;
13975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		p->cursig = SIG_IGN;
13985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
13995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/*-
14015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * Generally, an ignored signal stays ignored, except if
14025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 *	- the user of an interactive shell wants to change it
14035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 *	- the shell wants for force a change
14045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
14055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((p->flags & TF_ORIG_IGN) && !(flags & SS_FORCE) &&
14065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    (!(flags & SS_USER) || !Flag(FTALKING)))
14075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (0);
14085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	setexecsig(p, flags & SS_RESTORE_MASK);
14105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/*
14125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * This is here 'cause there should be a way of clearing
14135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * shtraps, but don't know if this is a sane way of doing
14145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * it. At the moment, all users of shtrap are lifetime
14155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * users (SIGALRM, SIGCHLD, SIGWINCH).
14165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
14175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(flags & SS_USER))
14185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		p->shtrap = (sig_t)NULL;
14195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (flags & SS_SHTRAP) {
14205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		p->shtrap = f;
14215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		f = trapsig;
14225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
14235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (p->cursig != f) {
14255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		p->cursig = f;
14265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		(void)sigemptyset(&sigact.sa_mask);
142703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* interruptible */
142803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		sigact.sa_flags = 0;
14295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sigact.sa_handler = f;
14305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sigaction(p->signal, &sigact, NULL);
14315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
14325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (1);
14345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
14355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* control what signal is set to before an exec() */
14375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
14385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querusetexecsig(Trap *p, int restore)
14395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
14405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* XXX debugging */
14415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL)))
14425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		internal_errorf("setexecsig: unset signal %d(%s)",
14435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    p->signal, p->name);
14445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* restore original value for exec'd kids */
14465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL);
14475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	switch (restore & SS_RESTORE_MASK) {
144803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	case SS_RESTORE_CURR:
144903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* leave things as they currently are */
14505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
14515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case SS_RESTORE_ORIG:
14525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		p->flags |= p->flags & TF_ORIG_IGN ? TF_EXEC_IGN : TF_EXEC_DFL;
14535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
14545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case SS_RESTORE_DFL:
14555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		p->flags |= TF_EXEC_DFL;
14565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
14575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case SS_RESTORE_IGN:
14585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		p->flags |= TF_EXEC_IGN;
14595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
14605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
14615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1462c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1463c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#if HAVE_PERSISTENT_HISTORY || defined(DF)
1464c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser/*
1465c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * File descriptor locking and unlocking functions.
1466c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * Could use some error handling, but hey, this is only
1467c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * advisory locking anyway, will often not work over NFS,
1468c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * and you are SOL if this fails...
1469c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser */
1470c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1471c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaservoid
1472c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glasermksh_lockfd(int fd)
1473c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser{
1474c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#if defined(__OpenBSD__)
1475c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* flock is not interrupted by signals */
1476c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	(void)flock(fd, LOCK_EX);
1477c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#elif HAVE_FLOCK
1478c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	int rv;
1479c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1480c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* e.g. on Linux */
1481c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	do {
1482c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		rv = flock(fd, LOCK_EX);
1483c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	} while (rv == 1 && errno == EINTR);
1484c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#elif HAVE_LOCK_FCNTL
1485c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	int rv;
1486c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	struct flock lks;
1487c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1488c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	memset(&lks, 0, sizeof(lks));
1489c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	lks.l_type = F_WRLCK;
1490c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	do {
1491c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		rv = fcntl(fd, F_SETLKW, &lks);
1492c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	} while (rv == 1 && errno == EINTR);
1493c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
1494c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser}
1495c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1496c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser/* designed to not define mksh_unlkfd if none triggered */
1497c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#if HAVE_FLOCK
1498c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaservoid
1499c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glasermksh_unlkfd(int fd)
1500c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser{
1501c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	(void)flock(fd, LOCK_UN);
1502c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser}
1503c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#elif HAVE_LOCK_FCNTL
1504c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaservoid
1505c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glasermksh_unlkfd(int fd)
1506c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser{
1507c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	struct flock lks;
1508c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1509c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	memset(&lks, 0, sizeof(lks));
1510c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	lks.l_type = F_UNLCK;
1511c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	(void)fcntl(fd, F_SETLKW, &lks);
1512c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser}
1513c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
1514c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
1515