diff options
Diffstat (limited to 'system/ksh-openbsd/patches/08-new_history_implementation.diff')
-rw-r--r-- | system/ksh-openbsd/patches/08-new_history_implementation.diff | 584 |
1 files changed, 0 insertions, 584 deletions
diff --git a/system/ksh-openbsd/patches/08-new_history_implementation.diff b/system/ksh-openbsd/patches/08-new_history_implementation.diff deleted file mode 100644 index d083b42554..0000000000 --- a/system/ksh-openbsd/patches/08-new_history_implementation.diff +++ /dev/null @@ -1,584 +0,0 @@ -From: Marco Peereboom -To: tech@openbsd.org -Subject: ksh history corruption - -I have had enough of corrupt ksh history so I had a look at the code to -try to fix it. The magical code was very magical so I basically deleted -most of it and made ksh history into a flat text file. It handles -multiple ksh instances writing to the same text file with locks just -like the current ksh does. I haven't noticed any differences in -behavior running this. - -Code is much simpler and it shaves ~4k of the binary too. - -Index: alloc.c -=================================================================== -RCS file: /cvs/src/bin/ksh/alloc.c,v -retrieving revision 1.8 -diff -u -p -r1.8 alloc.c ---- alloc.c 21 Jul 2008 17:30:08 -0000 1.8 -+++ alloc.c 30 Aug 2011 18:05:47 -0000 -@@ -62,7 +62,7 @@ alloc(size_t size, Area *ap) - { - struct link *l; - -- l = malloc(sizeof(struct link) + size); -+ l = calloc(1, sizeof(struct link) + size); - if (l == NULL) - internal_errorf(1, "unable to allocate memory"); - l->next = ap->freelist; -Index: history.c -=================================================================== -RCS file: /cvs/src/bin/ksh/history.c,v -retrieving revision 1.39 -diff -u -p -r1.39 history.c ---- history.c 19 May 2010 17:36:08 -0000 1.39 -+++ history.c 31 Aug 2011 19:33:24 -0000 -@@ -11,8 +11,7 @@ - * a) the original in-memory history mechanism - * b) a more complicated mechanism done by pc@hillside.co.uk - * that more closely follows the real ksh way of doing -- * things. You need to have the mmap system call for this -- * to work on your system -+ * things. - */ - - #include "sh.h" -@@ -22,19 +21,10 @@ - # include <sys/file.h> - # include <sys/mman.h> - --/* -- * variables for handling the data file -- */ --static int histfd; --static int hsize; -- --static int hist_count_lines(unsigned char *, int); --static int hist_shrink(unsigned char *, int); --static unsigned char *hist_skip_back(unsigned char *,int *,int); --static void histload(Source *, unsigned char *, int); --static void histinsert(Source *, int, unsigned char *); --static void writehistfile(int, char *); --static int sprinkle(int); -+static void writehistfile(FILE *); -+static FILE *history_open(int *); -+static int history_load(FILE *, Source *); -+static void history_close(FILE *); - - static int hist_execute(char *); - static int hist_replace(char **, const char *, const char *, int); -@@ -45,8 +35,8 @@ static void histbackup(void); - static char **current; /* current position in history[] */ - static char *hname; /* current name of history file */ - static int hstarted; /* set after hist_init() called */ --static Source *hist_source; -- -+static Source *hist_source; -+static struct stat last_sb; - - int - c_fc(char **wp) -@@ -529,15 +519,10 @@ sethistfile(const char *name) - /* if the name is the same as the name we have */ - if (hname && strcmp(hname, name) == 0) - return; -- - /* - * its a new name - possibly - */ -- if (histfd) { -- /* yes the file is open */ -- (void) close(histfd); -- histfd = 0; -- hsize = 0; -+ if (hname) { - afree(hname, APERM); - hname = NULL; - /* let's reset the history */ -@@ -577,18 +562,26 @@ init_histvec(void) - void - histsave(int lno, const char *cmd, int dowrite) - { -- char **hp; -- char *c, *cp; -+ char **hp; -+ char *c, *cp; -+ int changed; -+ FILE *f = NULL; -+ -+ if (dowrite) { -+ f = history_open(&changed); -+ if (f && changed) { -+ /* reset history */ -+ histptr = history - 1; -+ hist_source->line = 0; -+ history_load(f, hist_source); -+ } -+ } - - c = str_save(cmd, APERM); - if ((cp = strchr(c, '\n')) != NULL) - *cp = '\0'; - -- if (histfd && dowrite) -- writehistfile(lno, c); -- - hp = histptr; -- - if (++hp >= history + histsize) { /* remove oldest command */ - afree((void*)*history, APERM); - for (hp = history; hp < history + histsize - 1; hp++) -@@ -596,371 +589,125 @@ histsave(int lno, const char *cmd, int d - } - *hp = c; - histptr = hp; --} -- --/* -- * Write history data to a file nominated by HISTFILE -- * if HISTFILE is unset then history still happens, but -- * the data is not written to a file -- * All copies of ksh looking at the file will maintain the -- * same history. This is ksh behaviour. -- * -- * This stuff uses mmap() -- * if your system ain't got it - then you'll have to undef HISTORYFILE -- */ - --/* -- * Open a history file -- * Format is: -- * Bytes 1, 2: HMAGIC - just to check that we are dealing with -- * the correct object -- * Then follows a number of stored commands -- * Each command is -- * <command byte><command number(4 bytes)><bytes><null> -- */ --#define HMAGIC1 0xab --#define HMAGIC2 0xcd --#define COMMAND 0xff -+ if (dowrite && f) { -+ writehistfile(f); -+ history_close(f); -+ } -+} - --void --hist_init(Source *s) -+static FILE * -+history_open(int *changed) - { -- unsigned char *base; -- int lines; -- int fd; -- -- if (Flag(FTALKING) == 0) -- return; -- -- hstarted = 1; -- -- hist_source = s; -- -- hname = str_val(global("HISTFILE")); -- if (hname == NULL) -- return; -- hname = str_save(hname, APERM); -+ int fd; -+ FILE *f = NULL; -+ struct stat sb; - -- retry: -- /* we have a file and are interactive */ -- if ((fd = open(hname, O_RDWR|O_CREAT|O_APPEND, 0600)) < 0) -- return; -- -- histfd = savefd(fd); -- if (histfd != fd) -+ if ((fd = open(hname, O_RDWR | O_CREAT | O_EXLOCK, 0600)) == -1) -+ return (NULL); -+ f = fdopen(fd, "r+"); -+ if (f == NULL) { - close(fd); -+ goto bad; -+ } - -- (void) flock(histfd, LOCK_EX); -+ if (fstat(fileno(f), &sb) == -1) -+ goto bad; -+ if (timespeccmp(&sb.st_mtim, &last_sb.st_mtim, ==)) -+ *changed = 0; -+ else -+ *changed = 1; - -- hsize = lseek(histfd, 0L, SEEK_END); -+ return (f); -+bad: -+ if (f) -+ fclose(f); - -- if (hsize == 0) { -- /* add magic */ -- if (sprinkle(histfd)) { -- hist_finish(); -- return; -- } -- } -- else if (hsize > 0) { -- /* -- * we have some data -- */ -- base = (unsigned char *)mmap(0, hsize, PROT_READ, -- MAP_FILE|MAP_PRIVATE, histfd, 0); -- /* -- * check on its validity -- */ -- if (base == MAP_FAILED || *base != HMAGIC1 || base[1] != HMAGIC2) { -- if (base != MAP_FAILED) -- munmap((caddr_t)base, hsize); -- hist_finish(); -- if (unlink(hname) != 0) -- return; -- goto retry; -- } -- if (hsize > 2) { -- lines = hist_count_lines(base+2, hsize-2); -- if (lines > histsize) { -- /* we need to make the file smaller */ -- if (hist_shrink(base, hsize)) -- if (unlink(hname) != 0) -- return; -- munmap((caddr_t)base, hsize); -- hist_finish(); -- goto retry; -- } -- } -- histload(hist_source, base+2, hsize-2); -- munmap((caddr_t)base, hsize); -- } -- (void) flock(histfd, LOCK_UN); -- hsize = lseek(histfd, 0L, SEEK_END); -+ return (NULL); - } - --typedef enum state { -- shdr, /* expecting a header */ -- sline, /* looking for a null byte to end the line */ -- sn1, /* bytes 1 to 4 of a line no */ -- sn2, sn3, sn4 --} State; -+static void -+history_close(FILE *f) -+{ -+ fflush(f); -+ fstat(fileno(f), &last_sb); -+ fclose(f); -+} - - static int --hist_count_lines(unsigned char *base, int bytes) -+history_load(FILE *f, Source *s) - { -- State state = shdr; -- int lines = 0; -+ char *p, line[LINE + 1]; -+ uint32_t i; - -- while (bytes--) { -- switch (state) { -- case shdr: -- if (*base == COMMAND) -- state = sn1; -+ /* just read it all; will auto resize history upon next command */ -+ for (i = 1; ; i++) { -+ p = fgets(line, sizeof line, f); -+ if (p == NULL || feof(f) || ferror(f)) - break; -- case sn1: -- state = sn2; break; -- case sn2: -- state = sn3; break; -- case sn3: -- state = sn4; break; -- case sn4: -- state = sline; break; -- case sline: -- if (*base == '\0') -- lines++, state = shdr; -+ if ((p = strchr(line, '\n')) == NULL) { -+ bi_errorf("history file is corrupt"); -+ return (1); - } -- base++; -+ *p = '\0'; -+ -+ s->line = i; -+ s->cmd_offset = i; -+ histsave(i, (char *)line, 0); - } -- return lines; -+ -+ return (0); - } - --/* -- * Shrink the history file to histsize lines -- */ --static int --hist_shrink(unsigned char *oldbase, int oldbytes) -+void -+hist_init(Source *s) - { -- int fd; -- char nfile[1024]; -- struct stat statb; -- unsigned char *nbase = oldbase; -- int nbytes = oldbytes; -- -- nbase = hist_skip_back(nbase, &nbytes, histsize); -- if (nbase == NULL) -- return 1; -- if (nbase == oldbase) -- return 0; -- -- /* -- * create temp file -- */ -- (void) shf_snprintf(nfile, sizeof(nfile), "%s.%d", hname, procpid); -- if ((fd = open(nfile, O_CREAT | O_TRUNC | O_WRONLY, 0600)) < 0) -- return 1; -+ FILE *f = NULL; -+ int changed; - -- if (sprinkle(fd)) { -- close(fd); -- unlink(nfile); -- return 1; -- } -- if (write(fd, nbase, nbytes) != nbytes) { -- close(fd); -- unlink(nfile); -- return 1; -- } -- /* -- * worry about who owns this file -- */ -- if (fstat(histfd, &statb) >= 0) -- fchown(fd, statb.st_uid, statb.st_gid); -- close(fd); -+ if (Flag(FTALKING) == 0) -+ return; - -- /* -- * rename -- */ -- if (rename(nfile, hname) < 0) -- return 1; -- return 0; --} -+ hstarted = 1; - -+ hist_source = s; - --/* -- * find a pointer to the data `no' back from the end of the file -- * return the pointer and the number of bytes left -- */ --static unsigned char * --hist_skip_back(unsigned char *base, int *bytes, int no) --{ -- int lines = 0; -- unsigned char *ep; -+ hname = str_val(global("HISTFILE")); -+ if (hname == NULL) -+ return; -+ hname = str_save(hname, APERM); - -- for (ep = base + *bytes; --ep > base; ) { -- /* this doesn't really work: the 4 byte line number that is -- * encoded after the COMMAND byte can itself contain the -- * COMMAND byte.... -- */ -- for (; ep > base && *ep != COMMAND; ep--) -- ; -- if (ep == base) -- break; -- if (++lines == no) { -- *bytes = *bytes - ((char *)ep - (char *)base); -- return ep; -- } -- } -- return NULL; --} -+ f = history_open(&changed); -+ if (f == NULL) -+ return; - --/* -- * load the history structure from the stored data -- */ --static void --histload(Source *s, unsigned char *base, int bytes) --{ -- State state; -- int lno = 0; -- unsigned char *line = NULL; -- -- for (state = shdr; bytes-- > 0; base++) { -- switch (state) { -- case shdr: -- if (*base == COMMAND) -- state = sn1; -- break; -- case sn1: -- lno = (((*base)&0xff)<<24); -- state = sn2; -- break; -- case sn2: -- lno |= (((*base)&0xff)<<16); -- state = sn3; -- break; -- case sn3: -- lno |= (((*base)&0xff)<<8); -- state = sn4; -- break; -- case sn4: -- lno |= (*base)&0xff; -- line = base+1; -- state = sline; -- break; -- case sline: -- if (*base == '\0') { -- /* worry about line numbers */ -- if (histptr >= history && lno-1 != s->line) { -- /* a replacement ? */ -- histinsert(s, lno, line); -- } -- else { -- s->line = lno; -- s->cmd_offset = lno; -- histsave(lno, (char *)line, 0); -- } -- state = shdr; -- } -- } -- } -+ history_load(f, s); -+ history_close(f); - } - --/* -- * Insert a line into the history at a specified number -- */ - static void --histinsert(Source *s, int lno, unsigned char *line) -+writehistfile(FILE *f) - { -- char **hp; -+ int i; -+ char *cmd; - -- if (lno >= s->line-(histptr-history) && lno <= s->line) { -- hp = &histptr[lno-s->line]; -- if (*hp) -- afree((void*)*hp, APERM); -- *hp = str_save((char *)line, APERM); -- } --} -+ if (ftruncate(fileno(f), 0) == -1) -+ return; -+ rewind(f); - --/* -- * write a command to the end of the history file -- * This *MAY* seem easy but it's also necessary to check -- * that the history file has not changed in size. -- * If it has - then some other shell has written to it -- * and we should read those commands to update our history -- */ --static void --writehistfile(int lno, char *cmd) --{ -- int sizenow; -- unsigned char *base; -- unsigned char *new; -- int bytes; -- unsigned char hdr[5]; -- -- (void) flock(histfd, LOCK_EX); -- sizenow = lseek(histfd, 0L, SEEK_END); -- if (sizenow != hsize) { -- /* -- * Things have changed -- */ -- if (sizenow > hsize) { -- /* someone has added some lines */ -- bytes = sizenow - hsize; -- base = (unsigned char *)mmap(0, sizenow, -- PROT_READ, MAP_FILE|MAP_PRIVATE, histfd, 0); -- if (base == MAP_FAILED) -- goto bad; -- new = base + hsize; -- if (*new != COMMAND) { -- munmap((caddr_t)base, sizenow); -- goto bad; -- } -- hist_source->line--; -- histload(hist_source, new, bytes); -- hist_source->line++; -- lno = hist_source->line; -- munmap((caddr_t)base, sizenow); -- hsize = sizenow; -- } else { -- /* it has shrunk */ -- /* but to what? */ -- /* we'll give up for now */ -- goto bad; -- } -+ for (i = 0; i < histsize; i++) { -+ cmd = history[i]; -+ if (cmd == NULL) -+ break; -+ if (fprintf(f, "%s\n", cmd) == -1) -+ return; - } -- /* -- * we can write our bit now -- */ -- hdr[0] = COMMAND; -- hdr[1] = (lno>>24)&0xff; -- hdr[2] = (lno>>16)&0xff; -- hdr[3] = (lno>>8)&0xff; -- hdr[4] = lno&0xff; -- (void) write(histfd, hdr, 5); -- (void) write(histfd, cmd, strlen(cmd)+1); -- hsize = lseek(histfd, 0L, SEEK_END); -- (void) flock(histfd, LOCK_UN); -- return; --bad: -- hist_finish(); - } - - void - hist_finish(void) - { -- (void) flock(histfd, LOCK_UN); -- (void) close(histfd); -- histfd = 0; - } -- --/* -- * add magic to the history file -- */ --static int --sprinkle(int fd) --{ -- static unsigned char mag[] = { HMAGIC1, HMAGIC2 }; -- -- return(write(fd, mag, 2) != 2); --} -- - #else /* HISTORY */ - - /* No history to be compiled in: dummy routines to avoid lots more ifdefs */ - |