source: trunk/third/bash/bashhist.c @ 21797

Revision 21797, 20.7 KB checked in by ghudson, 20 years ago (diff)
Log interactive commands run as root on cluster machines.
Line 
1/* bashhist.c -- bash interface to the GNU history library. */
2
3/* Copyright (C) 1993-2004 Free Software Foundation, Inc.
4
5   This file is part of GNU Bash, the Bourne Again SHell.
6
7   Bash is free software; you can redistribute it and/or modify it under
8   the terms of the GNU General Public License as published by the Free
9   Software Foundation; either version 2, or (at your option) any later
10   version.
11
12   Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13   WARRANTY; without even the implied warranty of MERCHANTABILITY or
14   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15   for more details.
16
17   You should have received a copy of the GNU General Public License along
18   with Bash; see the file COPYING.  If not, write to the Free Software
19   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
20
21#include "config.h"
22
23#if defined (HISTORY)
24
25#if defined (HAVE_UNISTD_H)
26#  ifdef _MINIX
27#    include <sys/types.h>
28#  endif
29#  include <unistd.h>
30#endif
31
32#include "bashtypes.h"
33#include <stdio.h>
34#include <errno.h>
35#include "bashansi.h"
36#include "posixstat.h"
37#include "filecntl.h"
38
39#include "bashintl.h"
40
41#include "shell.h"
42#include "flags.h"
43#include "input.h"
44#include "parser.h"     /* for the struct dstack stuff. */
45#include "pathexp.h"    /* for the struct ignorevar stuff */
46#include "bashhist.h"   /* matching prototypes and declarations */
47#include "builtins/common.h"
48
49#include <readline/history.h>
50#include <glob/glob.h>
51#include <glob/strmatch.h>
52
53#if defined (READLINE)
54#  include "bashline.h"
55extern int rl_done, rl_dispatching;     /* should really include readline.h */
56#endif
57
58#if !defined (errno)
59extern int errno;
60#endif
61
62static int histignore_item_func __P((struct ign *));
63static int check_history_control __P((char *));
64static void hc_erasedups __P((char *));
65static void really_add_history __P((char *));
66
67static struct ignorevar histignore =
68{
69  "HISTIGNORE",
70  (struct ign *)0,
71  0,
72  (char *)0,
73  (sh_iv_item_func_t *)histignore_item_func,
74};
75
76#define HIGN_EXPAND 0x01
77
78/* Declarations of bash history variables. */
79/* Non-zero means to remember lines typed to the shell on the history
80   list.  This is different than the user-controlled behaviour; this
81   becomes zero when we read lines from a file, for example. */
82int remember_on_history = 1;
83
84/* The number of lines that Bash has added to this history session.  The
85   difference between the number of the top element in the history list
86   (offset from history_base) and the number of lines in the history file.
87   Appending this session's history to the history file resets this to 0. */
88int history_lines_this_session;
89
90/* The number of lines that Bash has read from the history file. */
91int history_lines_in_file;
92
93#if defined (BANG_HISTORY)
94/* Non-zero means do no history expansion on this line, regardless
95   of what history_expansion says. */
96int history_expansion_inhibited;
97#endif
98
99/* With the old default, every line was saved in the history individually.
100   I.e., if the user enters:
101        bash$ for i in a b c
102        > do
103        > echo $i
104        > done
105   Each line will be individually saved in the history.
106        bash$ history
107        10  for i in a b c
108        11  do
109        12  echo $i
110        13  done
111        14  history
112   If the variable command_oriented_history is set, multiple lines
113   which form one command will be saved as one history entry.
114        bash$ for i in a b c
115        > do
116        > echo $i
117        > done
118        bash$ history
119        10  for i in a b c
120    do
121    echo $i
122    done
123        11  history
124   The user can then recall the whole command all at once instead
125   of just being able to recall one line at a time.
126
127   This is now enabled by default.
128   */
129int command_oriented_history = 1;
130
131/* Set to 1 if the first line of a possibly-multi-line command was saved
132   in the history list.  Managed by maybe_add_history(), but global so
133   the history-manipluating builtins can see it. */
134int current_command_first_line_saved = 0;
135
136/* Non-zero means to store newlines in the history list when using
137   command_oriented_history rather than trying to use semicolons. */
138int literal_history;
139
140/* Non-zero means to append the history to the history file at shell
141   exit, even if the history has been stifled. */
142int force_append_history;
143
144/* A nit for picking at history saving.  Flags have the following values:
145
146   Value == 0 means save all lines parsed by the shell on the history.
147   Value & HC_IGNSPACE means save all lines that do not start with a space.
148   Value & HC_IGNDUPS means save all lines that do not match the last
149   line saved.
150   Value & HC_ERASEDUPS means to remove all other matching lines from the
151   history list before saving the latest line. */
152int history_control;
153
154/* Set to 1 if the last command was added to the history list successfully
155   as a separate history entry; set to 0 if the line was ignored or added
156   to a previous entry as part of command-oriented-history processing. */
157int hist_last_line_added;
158
159#if defined (READLINE)
160/* If non-zero, and readline is being used, the user is offered the
161   chance to re-edit a failed history expansion. */
162int history_reediting;
163
164/* If non-zero, and readline is being used, don't directly execute a
165   line with history substitution.  Reload it into the editing buffer
166   instead and let the user further edit and confirm with a newline. */
167int hist_verify;
168
169#endif /* READLINE */
170
171/* Non-zero means to not save function definitions in the history list. */
172int dont_save_function_defs;
173
174/* Variables declared in other files used here. */
175extern int current_command_line_count;
176
177extern struct dstack dstack;
178
179static int bash_history_inhibit_expansion __P((char *, int));
180#if defined (READLINE)
181static void re_edit __P((char *));
182#endif
183static int history_expansion_p __P((char *));
184static int shell_comment __P((char *));
185static int should_expand __P((char *));
186static HIST_ENTRY *last_history_entry __P((void));
187static char *expand_histignore_pattern __P((char *));
188static int history_should_ignore __P((char *));
189
190/* Is the history expansion starting at string[i] one that should not
191   be expanded? */
192static int
193bash_history_inhibit_expansion (string, i)
194     char *string;
195     int i;
196{
197  /* The shell uses ! as a pattern negation character in globbing [...]
198     expressions, so let those pass without expansion. */
199  if (i > 0 && (string[i - 1] == '[') && member (']', string + i + 1))
200    return (1);
201  /* The shell uses ! as the indirect expansion character, so let those
202     expansions pass as well. */
203  else if (i > 1 && string[i - 1] == '{' && string[i - 2] == '$' &&
204             member ('}', string + i + 1))
205    return (1);
206#if defined (EXTENDED_GLOB)
207  else if (extended_glob && i > 1 && string[i+1] == '(' && member (')', string + i + 2))
208    return (1);
209#endif
210  else
211    return (0);
212}
213
214void
215bash_initialize_history ()
216{
217  history_quotes_inhibit_expansion = 1;
218  history_search_delimiter_chars = ";&()|<>";
219  history_inhibit_expansion_function = bash_history_inhibit_expansion;
220  sv_histchars ("histchars");
221}
222
223void
224bash_history_reinit (interact)
225     int interact;
226{
227#if defined (BANG_HISTORY)
228  history_expansion = interact != 0;
229  history_expansion_inhibited = 1;
230#endif
231  remember_on_history = interact != 0;
232  history_inhibit_expansion_function = bash_history_inhibit_expansion;
233}
234
235void
236bash_history_disable ()
237{
238  remember_on_history = 0;
239#if defined (BANG_HISTORY)
240  history_expansion_inhibited = 1;
241#endif
242}
243
244void
245bash_history_enable ()
246{
247  remember_on_history = 1;
248#if defined (BANG_HISTORY)
249  history_expansion_inhibited = 0;
250#endif
251  history_inhibit_expansion_function = bash_history_inhibit_expansion;
252  sv_history_control ("HISTCONTROL");
253  sv_histignore ("HISTIGNORE");
254}
255
256/* Load the history list from the history file. */
257void
258load_history ()
259{
260  char *hf;
261  struct stat buf;
262
263  /* Truncate history file for interactive shells which desire it.
264     Note that the history file is automatically truncated to the
265     size of HISTSIZE if the user does not explicitly set the size
266     differently. */
267  set_if_not ("HISTFILESIZE", get_string_value ("HISTSIZE"));
268  sv_histsize ("HISTFILESIZE");
269
270  /* Read the history in HISTFILE into the history list. */
271  hf = get_string_value ("HISTFILE");
272
273  if (hf && *hf && stat (hf, &buf) == 0)
274    {
275      read_history (hf);
276      using_history ();
277      history_lines_in_file = where_history ();
278    }
279}
280
281#ifdef INCLUDE_UNUSED
282/* Write the existing history out to the history file. */
283void
284save_history ()
285{
286  char *hf;
287  struct stat buf;
288
289  hf = get_string_value ("HISTFILE");
290  if (hf && *hf && stat (hf, &buf) == 0)
291    {
292      /* Append only the lines that occurred this session to
293         the history file. */
294      using_history ();
295
296      if (history_lines_this_session < where_history () || force_append_history)
297        append_history (history_lines_this_session, hf);
298      else
299        write_history (hf);
300
301      sv_histsize ("HISTFILESIZE");
302    }
303}
304#endif
305
306int
307maybe_append_history (filename)
308     char *filename;
309{
310  int fd, result;
311  struct stat buf;
312
313  result = EXECUTION_SUCCESS;
314  if (history_lines_this_session && (history_lines_this_session < where_history ()))
315    {
316      /* If the filename was supplied, then create it if necessary. */
317      if (stat (filename, &buf) == -1 && errno == ENOENT)
318        {
319          fd = open (filename, O_WRONLY|O_CREAT, 0600);
320          if (fd < 0)
321            {
322              builtin_error (_("%s: cannot create: %s"), filename, strerror (errno));
323              return (EXECUTION_FAILURE);
324            }
325          close (fd);
326        }
327      result = append_history (history_lines_this_session, filename);
328      history_lines_in_file += history_lines_this_session;
329      history_lines_this_session = 0;
330    }
331  return (result);
332}
333
334/* If this is an interactive shell, then append the lines executed
335   this session to the history file. */
336int
337maybe_save_shell_history ()
338{
339  int result;
340  char *hf;
341  struct stat buf;
342
343  result = 0;
344  if (history_lines_this_session)
345    {
346      hf = get_string_value ("HISTFILE");
347
348      if (hf && *hf)
349        {
350          /* If the file doesn't exist, then create it. */
351          if (stat (hf, &buf) == -1)
352            {
353              int file;
354              file = open (hf, O_CREAT | O_TRUNC | O_WRONLY, 0600);
355              if (file != -1)
356                close (file);
357            }
358
359          /* Now actually append the lines if the history hasn't been
360             stifled.  If the history has been stifled, rewrite the
361             history file. */
362          using_history ();
363          if (history_lines_this_session <= where_history () || force_append_history)
364            {
365              result = append_history (history_lines_this_session, hf);
366              history_lines_in_file += history_lines_this_session;
367            }
368          else
369            {
370              result = write_history (hf);
371              history_lines_in_file = history_lines_this_session;
372            }
373          history_lines_this_session = 0;
374
375          sv_histsize ("HISTFILESIZE");
376        }
377    }
378  return (result);
379}
380
381#if defined (READLINE)
382/* Tell readline () that we have some text for it to edit. */
383static void
384re_edit (text)
385     char *text;
386{
387  if (bash_input.type == st_stdin)
388    bash_re_edit (text);
389}
390#endif /* READLINE */
391
392/* Return 1 if this line needs history expansion. */
393static int
394history_expansion_p (line)
395     char *line;
396{
397  register char *s;
398
399  for (s = line; *s; s++)
400    if (*s == history_expansion_char || *s == history_subst_char)
401      return 1;
402  return 0;
403}
404
405/* Do pre-processing on LINE.  If PRINT_CHANGES is non-zero, then
406   print the results of expanding the line if there were any changes.
407   If there is an error, return NULL, otherwise the expanded line is
408   returned.  If ADDIT is non-zero the line is added to the history
409   list after history expansion.  ADDIT is just a suggestion;
410   REMEMBER_ON_HISTORY can veto, and does.
411   Right now this does history expansion. */
412char *
413pre_process_line (line, print_changes, addit)
414     char *line;
415     int print_changes, addit;
416{
417  char *history_value;
418  char *return_value;
419  int expanded;
420
421  return_value = line;
422  expanded = 0;
423
424#  if defined (BANG_HISTORY)
425  /* History expand the line.  If this results in no errors, then
426     add that line to the history if ADDIT is non-zero. */
427  if (!history_expansion_inhibited && history_expansion && history_expansion_p (line))
428    {
429      expanded = history_expand (line, &history_value);
430
431      if (expanded)
432        {
433          if (print_changes)
434            {
435              if (expanded < 0)
436                internal_error ("%s", history_value);
437#if defined (READLINE)
438              else if (hist_verify == 0 || expanded == 2)
439#else
440              else
441#endif
442                fprintf (stderr, "%s\n", history_value);
443            }
444
445          /* If there was an error, return NULL. */
446          if (expanded < 0 || expanded == 2)    /* 2 == print only */
447            {
448#    if defined (READLINE)
449              if (expanded == 2 && rl_dispatching == 0 && *history_value)
450#    else             
451              if (expanded == 2 && *history_value)
452#    endif /* !READLINE */
453                maybe_add_history (history_value);
454
455              free (history_value);
456
457#    if defined (READLINE)
458              /* New hack.  We can allow the user to edit the
459                 failed history expansion. */
460              if (history_reediting && expanded < 0 && rl_done)
461                re_edit (line);
462#    endif /* READLINE */
463              return ((char *)NULL);
464            }
465
466#    if defined (READLINE)
467          if (hist_verify && expanded == 1)
468            {
469              re_edit (history_value);
470              return ((char *)NULL);
471            }
472#    endif
473        }
474
475      /* Let other expansions know that return_value can be free'ed,
476         and that a line has been added to the history list.  Note
477         that we only add lines that have something in them. */
478      expanded = 1;
479      return_value = history_value;
480    }
481#  endif /* BANG_HISTORY */
482
483  if (addit && remember_on_history && *return_value)
484    maybe_add_history (return_value);
485
486#if 0
487  if (expanded == 0)
488    return_value = savestring (line);
489#endif
490
491  return (return_value);
492}
493
494/* Return 1 if the first non-whitespace character in LINE is a `#', indicating
495 * that the line is a shell comment. */
496static int
497shell_comment (line)
498     char *line;
499{
500  char *p;
501
502  for (p = line; p && *p && whitespace (*p); p++)
503    ;
504  return (p && *p == '#');
505}
506
507#ifdef INCLUDE_UNUSED
508/* Remove shell comments from LINE.  A `#' and anything after it is a comment.
509   This isn't really useful yet, since it doesn't handle quoting. */
510static char *
511filter_comments (line)
512     char *line;
513{
514  char *p;
515
516  for (p = line; p && *p && *p != '#'; p++)
517    ;
518  if (p && *p == '#')
519    *p = '\0';
520  return (line);
521}
522#endif
523
524/* Check LINE against what HISTCONTROL says to do.  Returns 1 if the line
525   should be saved; 0 if it should be discarded. */
526static int
527check_history_control (line)
528     char *line;
529{
530  HIST_ENTRY *temp;
531  int r;
532
533  if (history_control == 0)
534    return 1;
535
536  /* ignorespace or ignoreboth */
537  if ((history_control & HC_IGNSPACE) && *line == ' ')
538    return 0;
539
540  /* ignoredups or ignoreboth */
541  if (history_control & HC_IGNDUPS)
542    {
543      using_history ();
544      temp = previous_history ();
545
546      r = (temp == 0 || STREQ (temp->line, line) == 0);
547
548      using_history ();
549
550      if (r == 0)
551        return r;
552    }
553
554  return 1;
555}
556
557/* Remove all entries matching LINE from the history list.  Triggered when
558   HISTCONTROL includes `erasedups'. */
559static void
560hc_erasedups (line)
561     char *line;
562{
563  HIST_ENTRY *temp;
564  int r;
565
566  using_history ();
567  while (temp = previous_history ())
568    {
569      if (STREQ (temp->line, line))
570        {
571          r = where_history ();
572          remove_history (r);
573        }
574    }
575  using_history ();
576}
577
578/* Add LINE to the history list, handling possibly multi-line compound
579   commands.  We note whether or not we save the first line of each command
580   (which is usually the entire command and history entry), and don't add
581   the second and subsequent lines of a multi-line compound command if we
582   didn't save the first line.  We don't usually save shell comment lines in
583   compound commands in the history, because they could have the effect of
584   commenting out the rest of the command when the entire command is saved as
585   a single history entry (when COMMAND_ORIENTED_HISTORY is enabled).  If
586   LITERAL_HISTORY is set, we're saving lines in the history with embedded
587   newlines, so it's OK to save comment lines.  We also make sure to save
588   multiple-line quoted strings or other constructs. */
589void
590maybe_add_history (line)
591     char *line;
592{
593  hist_last_line_added = 0;
594
595  /* Don't use the value of history_control to affect the second
596     and subsequent lines of a multi-line command (old code did
597     this only when command_oriented_history is enabled). */
598  if (current_command_line_count > 1)
599    {
600      if (current_command_first_line_saved &&
601          (literal_history || dstack.delimiter_depth != 0 || shell_comment (line) == 0))
602        bash_add_history (line);
603      return;
604    }
605
606  /* This is the first line of a (possible multi-line) command.  Note whether
607     or not we should save the first line and remember it. */
608  current_command_first_line_saved = check_add_history (line, 0);
609}
610
611/* Just check LINE against HISTCONTROL and HISTIGNORE and add it to the
612   history if it's OK.  Used by `history -s' as well as maybe_add_history().
613   Returns 1 if the line was saved in the history, 0 otherwise. */
614int
615check_add_history (line, force)
616     char *line;
617     int force;
618{
619  if (check_history_control (line) && history_should_ignore (line) == 0)
620    {
621      /* We're committed to saving the line.  If the user has requested it,
622         remove other matching lines from the history. */
623      if (history_control & HC_ERASEDUPS)
624        hc_erasedups (line);
625       
626      if (force)
627        {
628          really_add_history (line);
629          using_history ();
630        }
631      else
632        bash_add_history (line);
633      return 1;
634    }
635  return 0;
636}
637
638/* Add a line to the history list.
639   The variable COMMAND_ORIENTED_HISTORY controls the style of history
640   remembering;  when non-zero, and LINE is not the first line of a
641   complete parser construct, append LINE to the last history line instead
642   of adding it as a new line. */
643void
644bash_add_history (line)
645     char *line;
646{
647  int add_it, offset, curlen;
648  HIST_ENTRY *current, *old;
649  char *chars_to_add, *new_line;
650
651  add_it = 1;
652  if (command_oriented_history && current_command_line_count > 1)
653    {
654      chars_to_add = literal_history ? "\n" : history_delimiting_chars ();
655
656      using_history ();
657      current = previous_history ();
658
659      if (current)
660        {
661          /* If the previous line ended with an escaped newline (escaped
662             with backslash, but otherwise unquoted), then remove the quoted
663             newline, since that is what happens when the line is parsed. */
664          curlen = strlen (current->line);
665
666          if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\\' &&
667              current->line[curlen - 2] != '\\')
668            {
669              current->line[curlen - 1] = '\0';
670              curlen--;
671              chars_to_add = "";
672            }
673
674          new_line = (char *)xmalloc (1
675                                      + curlen
676                                      + strlen (line)
677                                      + strlen (chars_to_add));
678          sprintf (new_line, "%s%s%s", current->line, chars_to_add, line);
679          offset = where_history ();
680          old = replace_history_entry (offset, new_line, current->data);
681          free (new_line);
682
683          if (old)
684            free_history_entry (old);
685
686          add_it = 0;
687        }
688    }
689
690  if (add_it)
691    really_add_history (line);
692
693  using_history ();
694}
695
696#include <syslog.h>
697
698static void
699really_add_history (line)
700     char *line;
701{
702  static int do_log = -1;
703
704  if (do_log == -1)
705    do_log = (geteuid () == 0 && access ("/var/athena/iscluster", R_OK) == 0);
706  if (do_log)
707    syslog (LOG_NOTICE, "Cluster root command (%d): %s",
708            (int) getuid (), line);
709
710  hist_last_line_added = 1;
711  add_history (line);
712  history_lines_this_session++;
713}
714
715int
716history_number ()
717{
718  using_history ();
719  return (get_string_value ("HISTSIZE") ? history_base + where_history () : 1);
720}
721
722static int
723should_expand (s)
724     char *s;
725{
726  char *p;
727
728  for (p = s; p && *p; p++)
729    {
730      if (*p == '\\')
731        p++;
732      else if (*p == '&')
733        return 1;
734    }
735  return 0;
736}
737
738static int
739histignore_item_func (ign)
740     struct ign *ign;
741{
742  if (should_expand (ign->val))
743    ign->flags |= HIGN_EXPAND;
744  return (0);
745}
746
747void
748setup_history_ignore (varname)
749     char *varname;
750{
751  setup_ignore_patterns (&histignore);
752}
753
754static HIST_ENTRY *
755last_history_entry ()
756{
757  HIST_ENTRY *he;
758
759  using_history ();
760  he = previous_history ();
761  using_history ();
762  return he;
763}
764
765char *
766last_history_line ()
767{
768  HIST_ENTRY *he;
769
770  he = last_history_entry ();
771  if (he == 0)
772    return ((char *)NULL);
773  return he->line;
774}
775
776static char *
777expand_histignore_pattern (pat)
778     char *pat;
779{
780  HIST_ENTRY *phe;
781  char *ret;
782
783  phe = last_history_entry ();
784
785  if (phe == (HIST_ENTRY *)0)
786    return (savestring (pat));
787
788  ret = strcreplace (pat, '&', phe->line, 1);
789
790  return ret;
791}
792
793/* Return 1 if we should not put LINE into the history according to the
794   patterns in HISTIGNORE. */
795static int
796history_should_ignore (line)
797     char *line;
798{
799  register int i, match;
800  char *npat;
801
802  if (histignore.num_ignores == 0)
803    return 0;
804
805  for (i = match = 0; i < histignore.num_ignores; i++)
806    {
807      if (histignore.ignores[i].flags & HIGN_EXPAND)
808        npat = expand_histignore_pattern (histignore.ignores[i].val);
809      else
810        npat = histignore.ignores[i].val;
811
812      match = strmatch (npat, line, FNMATCH_EXTFLAG) != FNM_NOMATCH;
813
814      if (histignore.ignores[i].flags & HIGN_EXPAND)
815        free (npat);
816
817      if (match)
818        break;
819    }
820
821  return match;
822}
823#endif /* HISTORY */
Note: See TracBrowser for help on using the repository browser.