/* bashhist.c -- bash interface to the GNU history library. */
-/* Copyright (C) 1993-2009 Free Software Foundation, Inc.
+/* Copyright (C) 1993-2012 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
-# include <sys/types.h>
+ # include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "bashintl.h"
+#if defined (SYSLOG_HISTORY)
+# include <syslog.h>
+#endif
+
#include "shell.h"
#include "flags.h"
#include "input.h"
extern int current_command_line_count;
extern struct dstack dstack;
+extern int parser_state;
static int bash_history_inhibit_expansion __P((char *, int));
#if defined (READLINE)
else if (i > 1 && string[i - 1] == '{' && string[i - 2] == '$' &&
member ('}', string + i + 1))
return (1);
+ /* The shell uses $! as a defined parameter expansion. */
+ else if (i > 1 && string[i - 1] == '$' && string[i] == '!')
+ return (1);
#if defined (EXTENDED_GLOB)
else if (extended_glob && i > 1 && string[i+1] == '(' && member (')', string + i + 2))
return (1);
save_history ()
{
char *hf;
+ int r;
hf = get_string_value ("HISTFILE");
if (hf && *hf && file_exists (hf))
the history file. */
using_history ();
- if (history_lines_this_session < where_history () || force_append_history)
- append_history (history_lines_this_session, hf);
+ if (history_lines_this_session <= where_history () || force_append_history)
+ r = append_history (history_lines_this_session, hf);
else
- write_history (hf);
-
+ r = write_history (hf);
sv_histsize ("HISTFILESIZE");
}
}
struct stat buf;
result = EXECUTION_SUCCESS;
- if (history_lines_this_session && (history_lines_this_session < where_history ()))
+ if (history_lines_this_session && (history_lines_this_session <= where_history ()))
{
/* If the filename was supplied, then create it if necessary. */
if (stat (filename, &buf) == -1 && errno == ENOENT)
commenting out the rest of the command when the entire command is saved as
a single history entry (when COMMAND_ORIENTED_HISTORY is enabled). If
LITERAL_HISTORY is set, we're saving lines in the history with embedded
- newlines, so it's OK to save comment lines. We also make sure to save
- multiple-line quoted strings or other constructs. */
+ newlines, so it's OK to save comment lines. If we're collecting the body
+ of a here-document, we should act as if literal_history is enabled, because
+ we want to save the entire contents of the here-document as it was
+ entered. We also make sure to save multiple-line quoted strings or other
+ constructs. */
void
maybe_add_history (line)
char *line;
if (current_command_line_count > 1)
{
if (current_command_first_line_saved &&
- (literal_history || dstack.delimiter_depth != 0 || shell_comment (line) == 0))
+ ((parser_state & PST_HEREDOC) || literal_history || dstack.delimiter_depth != 0 || shell_comment (line) == 0))
bash_add_history (line);
return;
}
return 0;
}
+#if defined (SYSLOG_HISTORY)
+#define SYSLOG_MAXLEN 600
+
+void
+bash_syslog_history (line)
+ const char *line;
+{
+ char trunc[SYSLOG_MAXLEN];
+
+ if (strlen(line) < SYSLOG_MAXLEN)
+ syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY: PID=%d UID=%d %s", getpid(), current_user.uid, line);
+ else
+ {
+ strncpy (trunc, line, SYSLOG_MAXLEN);
+ trunc[SYSLOG_MAXLEN - 1] = '\0';
+ syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY (TRUNCATED): PID=%d UID=%d %s", getpid(), current_user.uid, trunc);
+ }
+}
+#endif
+
/* Add a line to the history list.
The variable COMMAND_ORIENTED_HISTORY controls the style of history
remembering; when non-zero, and LINE is not the first line of a
add_it = 1;
if (command_oriented_history && current_command_line_count > 1)
{
- chars_to_add = literal_history ? "\n" : history_delimiting_chars ();
+ /* The second and subsequent lines of a here document have the trailing
+ newline preserved. We don't want to add extra newlines here, but we
+ do want to add one after the first line (which is the command that
+ contains the here-doc specifier). parse.y:history_delimiting_chars()
+ does the right thing to take care of this for us. We don't want to
+ add extra newlines if the user chooses to enable literal_history,
+ so we have to duplicate some of what that function does here. */
+ if ((parser_state & PST_HEREDOC) && literal_history && current_command_line_count > 2 && line[strlen (line) - 1] == '\n')
+ chars_to_add = "";
+ else
+ chars_to_add = literal_history ? "\n" : history_delimiting_chars (line);
using_history ();
current = previous_history ();
chars_to_add = "";
}
+ /* If we're not in some kind of quoted construct, the current history
+ entry ends with a newline, and we're going to add a semicolon,
+ don't. In some cases, it results in a syntax error (e.g., before
+ a close brace), and it should not be needed. */
+ if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\n' && *chars_to_add == ';')
+ chars_to_add++;
+
new_line = (char *)xmalloc (1
+ curlen
+ strlen (line)
if (add_it)
really_add_history (line);
+#if defined (SYSLOG_HISTORY)
+ bash_syslog_history (line);
+#endif
+
using_history ();
}