X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=error.c;h=417c902e9124777f6e46dc4c9b285452009d8850;hb=16c907aa3bb427618733e5a6f2f4e2fc5a3488d3;hp=a80810fb7e9abd974953238ff97a4903049684a5;hpb=ccc6cda312fea9f0468ee65b8f368e9653e1380b;p=thirdparty%2Fbash.git diff --git a/error.c b/error.c index a80810fb7..417c902e9 100644 --- a/error.c +++ b/error.c @@ -1,26 +1,26 @@ /* error.c -- Functions for handling errors. */ -/* Copyright (C) 1993 Free Software Foundation, Inc. + +/* Copyright (C) 1993-2009 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. + Bash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. + Bash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + You should have received a copy of the GNU General Public License + along with Bash. If not, see . +*/ #include "config.h" -#include -#include +#include "bashtypes.h" #include #if defined (HAVE_UNISTD_H) @@ -30,53 +30,89 @@ #if defined (PREFER_STDARG) # include #else -# if defined (PREFER_VARARGS) -# include -# endif +# include #endif +#include + #include #if !defined (errno) extern int errno; #endif /* !errno */ #include "bashansi.h" +#include "bashintl.h" + +#include "shell.h" +#include "execute_cmd.h" #include "flags.h" -#include "error.h" -#include "command.h" -#include "general.h" -#include "externs.h" #include "input.h" #if defined (HISTORY) # include "bashhist.h" #endif -extern int interactive_shell, interactive; -extern char *dollar_vars[]; -extern char *shell_name; +extern int executing_line_number __P((void)); + #if defined (JOB_CONTROL) extern pid_t shell_pgrp; -extern int give_terminal_to (); +extern int give_terminal_to __P((pid_t, int)); #endif /* JOB_CONTROL */ +#if defined (ARRAY_VARS) +extern const char * const bash_badsub_errmsg; +#endif + +static void error_prolog __P((int)); + /* The current maintainer of the shell. You change this in the Makefile. */ #if !defined (MAINTAINER) -#define MAINTAINER "bash-maintainers@prep.ai.mit.edu" +#define MAINTAINER "bash-maintainers@gnu.org" #endif -char *the_current_maintainer = MAINTAINER; +const char * const the_current_maintainer = MAINTAINER; + +int gnu_error_format = 0; + +static void +error_prolog (print_lineno) + int print_lineno; +{ + char *ename; + int line; + + ename = get_name_for_error (); + line = (print_lineno && interactive_shell == 0) ? executing_line_number () : -1; + + if (line > 0) + fprintf (stderr, "%s:%s%d: ", ename, gnu_error_format ? "" : _(" line "), line); + else + fprintf (stderr, "%s: ", ename); +} /* Return the name of the shell or the shell script for error reporting. */ char * get_name_for_error () { char *name; +#if defined (ARRAY_VARS) + SHELL_VAR *bash_source_v; + ARRAY *bash_source_a; +#endif name = (char *)NULL; if (interactive_shell == 0) - name = dollar_vars[0]; + { +#if defined (ARRAY_VARS) + bash_source_v = find_variable ("BASH_SOURCE"); + if (bash_source_v && array_p (bash_source_v) && + (bash_source_a = array_cell (bash_source_v))) + name = array_reference (bash_source_a, 0); + if (name == 0 || *name == '\0') /* XXX - was just name == 0 */ +#endif + name = dollar_vars[0]; + } if (name == 0 && shell_name && *shell_name) name = base_pathname (shell_name); if (name == 0) @@ -94,224 +130,163 @@ get_name_for_error () format string. */ void file_error (filename) - char *filename; + const char *filename; { report_error ("%s: %s", filename, strerror (errno)); } -#if !defined (USE_VARARGS) void -programming_error (reason, arg1, arg2, arg3, arg4, arg5) - char *reason; +#if defined (PREFER_STDARG) +programming_error (const char *format, ...) +#else +programming_error (format, va_alist) + const char *format; + va_dcl +#endif { + va_list args; char *h; #if defined (JOB_CONTROL) - give_terminal_to (shell_pgrp); + give_terminal_to (shell_pgrp, 0); #endif /* JOB_CONTROL */ - report_error (reason, arg1, arg2); + SH_VA_START (args, format); + + vfprintf (stderr, format, args); + fprintf (stderr, "\n"); + va_end (args); #if defined (HISTORY) if (remember_on_history) { h = last_history_line (); - fprintf (stderr, "last command: %s\n", h ? h : "(null)"); + fprintf (stderr, _("last command: %s\n"), h ? h : "(null)"); } #endif +#if 0 fprintf (stderr, "Report this to %s\n", the_current_maintainer); - fprintf (stderr, "Stopping myself..."); +#endif + + fprintf (stderr, _("Aborting...")); fflush (stderr); abort (); } +/* Print an error message and, if `set -e' has been executed, exit the + shell. Used in this file by file_error and programming_error. Used + outside this file mostly to report substitution and expansion errors, + and for bad invocation options. */ void -report_error (format, arg1, arg2, arg3, arg4, arg5) - char *format; -{ - fprintf (stderr, "%s: ", get_name_for_error ()); - - fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); - fprintf (stderr, "\n"); - if (exit_immediately_on_error) - exit (1); -} - -void -parser_error (lineno, format, arg1, arg2, arg3, arg4, arg5); - int lineno; - char *format; +#if defined (PREFER_STDARG) +report_error (const char *format, ...) +#else +report_error (format, va_alist) + const char *format; va_dcl +#endif { - char *ename, *iname; + va_list args; - ename = get_name_for_error (); - iname = bash_input.name ? bash_input.name : "stdin"; + error_prolog (1); - if (interactive) - fprintf (stderr, "%s: ", ename); - else if (interactive_shell) - fprintf (stderr, "%s: %s: line %d: ", ename, iname, lineno); - else if (STREQ (ename, iname)) - fprintf (stderr, "%s: line %d: ", ename, lineno); - else - fprintf (stderr, "%s: %s: line %d: ", ename, iname, lineno); + SH_VA_START (args, format); - fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); + vfprintf (stderr, format, args); fprintf (stderr, "\n"); + va_end (args); if (exit_immediately_on_error) - exit (2); -} - -void -fatal_error (format, arg1, arg2, arg3, arg4, arg5) - char *format; -{ - fprintf (stderr, "%s: ", get_name_for_error ()); - - fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); - fprintf (stderr, "\n"); - - exit (2); -} - -void -internal_error (format, arg1, arg2, arg3, arg4, arg5) - char *format; -{ - fprintf (stderr, "%s: ", get_name_for_error ()); - - fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); - fprintf (stderr, "\n"); -} - -void -sys_error (format, arg1, arg2, arg3, arg4, arg5) - char *format; -{ - fprintf (stderr, "%s: ", get_name_for_error ()); - - fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); - fprintf (stderr, ": %s\n", strerror (errno)); + { + if (last_command_exit_value == 0) + last_command_exit_value = 1; + exit_shell (last_command_exit_value); + } } -#else /* We have VARARGS support, so use it. */ - void #if defined (PREFER_STDARG) -programming_error (const char *format, ...) +fatal_error (const char *format, ...) #else -programming_error (format, va_alist) +fatal_error (format, va_alist) const char *format; va_dcl #endif { va_list args; - char *h; -#if defined (JOB_CONTROL) - give_terminal_to (shell_pgrp); -#endif /* JOB_CONTROL */ + error_prolog (0); -#if defined (PREFER_STDARG) - va_start (args, format); -#else - va_start (args); -#endif + SH_VA_START (args, format); vfprintf (stderr, format, args); fprintf (stderr, "\n"); - va_end (args); - -#if defined (HISTORY) - if (remember_on_history) - { - h = last_history_line (); - fprintf (stderr, "last command: %s\n", h ? h : "(null)"); - } -#endif - - fprintf (stderr, "Tell %s to fix this someday.\n", the_current_maintainer); - fprintf (stderr, "Stopping myself..."); - fflush (stderr); - abort (); + va_end (args); + sh_exit (2); } void #if defined (PREFER_STDARG) -report_error (const char *format, ...) +internal_error (const char *format, ...) #else -report_error (format, va_alist) +internal_error (format, va_alist) const char *format; va_dcl #endif { va_list args; - fprintf (stderr, "%s: ", get_name_for_error ()); + error_prolog (1); -#if defined (PREFER_STDARG) - va_start (args, format); -#else - va_start (args); -#endif + SH_VA_START (args, format); vfprintf (stderr, format, args); fprintf (stderr, "\n"); va_end (args); - if (exit_immediately_on_error) - exit (1); } void #if defined (PREFER_STDARG) -fatal_error (const char *format, ...) +internal_warning (const char *format, ...) #else -fatal_error (format, va_alist) +internal_warning (format, va_alist) const char *format; va_dcl #endif { va_list args; - fprintf (stderr, "%s: ", get_name_for_error ()); + error_prolog (1); + fprintf (stderr, _("warning: ")); -#if defined (PREFER_STDARG) - va_start (args, format); -#else - va_start (args); -#endif + SH_VA_START (args, format); vfprintf (stderr, format, args); fprintf (stderr, "\n"); va_end (args); - exit (2); } void #if defined (PREFER_STDARG) -internal_error (const char *format, ...) +internal_inform (const char *format, ...) #else -internal_error (format, va_alist) +internal_inform (format, va_alist) const char *format; va_dcl #endif { va_list args; - fprintf (stderr, "%s: ", get_name_for_error ()); + error_prolog (1); + /* TRANSLATORS: this is a prefix for informational messages. */ + fprintf (stderr, _("INFORM: ")); -#if defined (PREFER_STDARG) - va_start (args, format); -#else - va_start (args); -#endif + SH_VA_START (args, format); vfprintf (stderr, format, args); fprintf (stderr, "\n"); @@ -328,18 +303,16 @@ sys_error (format, va_alist) va_dcl #endif { + int e; va_list args; - fprintf (stderr, "%s: ", get_name_for_error ()); + e = errno; + error_prolog (0); -#if defined (PREFER_STDARG) - va_start (args, format); -#else - va_start (args); -#endif + SH_VA_START (args, format); vfprintf (stderr, format, args); - fprintf (stderr, ": %s\n", strerror (errno)); + fprintf (stderr, ": %s\n", strerror (e)); va_end (args); } @@ -366,22 +339,18 @@ parser_error (lineno, format, va_alist) char *ename, *iname; ename = get_name_for_error (); - iname = bash_input.name ? bash_input.name : "stdin"; + iname = yy_input_name (); if (interactive) fprintf (stderr, "%s: ", ename); else if (interactive_shell) - fprintf (stderr, "%s: %s: line %d: ", ename, iname, lineno); + fprintf (stderr, "%s: %s:%s%d: ", ename, iname, gnu_error_format ? "" : _(" line "), lineno); else if (STREQ (ename, iname)) - fprintf (stderr, "%s: line %d: ", ename, lineno); + fprintf (stderr, "%s:%s%d: ", ename, gnu_error_format ? "" : _(" line "), lineno); else - fprintf (stderr, "%s: %s: line %d: ", ename, iname, lineno); + fprintf (stderr, "%s: %s:%s%d: ", ename, iname, gnu_error_format ? "" : _(" line "), lineno); -#if defined (PREFER_STDARG) - va_start (args, format); -#else - va_start (args); -#endif + SH_VA_START (args, format); vfprintf (stderr, format, args); fprintf (stderr, "\n"); @@ -389,7 +358,38 @@ parser_error (lineno, format, va_alist) va_end (args); if (exit_immediately_on_error) - exit (2); + exit_shell (last_command_exit_value = 2); +} + +#ifdef DEBUG +/* This assumes ASCII and is suitable only for debugging */ +char * +strescape (str) + const char *str; +{ + char *r, *result; + unsigned char *s; + + r = result = (char *)xmalloc (strlen (str) * 2 + 1); + + for (s = (unsigned char *)str; s && *s; s++) + { + if (*s < ' ') + { + *r++ = '^'; + *r++ = *s+64; + } + else if (*s == 127) + { + *r++ = '^'; + *r++ = '?'; + } + else + *r++ = *s; + } + + *r = '\0'; + return result; } void @@ -403,13 +403,9 @@ itrace (format, va_alist) { va_list args; - fprintf(stderr, "TRACE: pid %d: ", (int)getpid()); + fprintf(stderr, "TRACE: pid %ld: ", (long)getpid()); -#if defined (PREFER_STDARG) - va_start (args, format); -#else - va_start (args); -#endif + SH_VA_START (args, format); vfprintf (stderr, format, args); fprintf (stderr, "\n"); @@ -419,7 +415,6 @@ itrace (format, va_alist) fflush(stderr); } -#if 0 /* A trace function for silent debugging -- doesn't require a control terminal. */ void @@ -435,20 +430,16 @@ trace (format, va_alist) static FILE *tracefp = (FILE *)NULL; if (tracefp == NULL) - tracefp = fopen("/usr/tmp/bash-trace.log", "a+"); + tracefp = fopen("/tmp/bash-trace.log", "a+"); if (tracefp == NULL) tracefp = stderr; else fcntl (fileno (tracefp), F_SETFD, 1); /* close-on-exec */ - fprintf(tracefp, "TRACE: pid %d: ", getpid()); + fprintf(tracefp, "TRACE: pid %ld: ", (long)getpid()); -#if defined (PREFER_STDARG) - va_start (args, format); -#else - va_start (args); -#endif + SH_VA_START (args, format); vfprintf (tracefp, format, args); fprintf (tracefp, "\n"); @@ -457,6 +448,64 @@ trace (format, va_alist) fflush(tracefp); } -#endif /* 0 */ -#endif /* USE_VARARGS */ +#endif /* DEBUG */ + +/* **************************************************************** */ +/* */ +/* Common error reporting */ +/* */ +/* **************************************************************** */ + + +static const char * const cmd_error_table[] = { + N_("unknown command error"), /* CMDERR_DEFAULT */ + N_("bad command type"), /* CMDERR_BADTYPE */ + N_("bad connector"), /* CMDERR_BADCONN */ + N_("bad jump"), /* CMDERR_BADJUMP */ + 0 +}; + +void +command_error (func, code, e, flags) + const char *func; + int code, e, flags; /* flags currently unused */ +{ + if (code > CMDERR_LAST) + code = CMDERR_DEFAULT; + + programming_error ("%s: %s: %d", func, _(cmd_error_table[code]), e); +} + +char * +command_errstr (code) + int code; +{ + if (code > CMDERR_LAST) + code = CMDERR_DEFAULT; + + return (_(cmd_error_table[code])); +} + +#ifdef ARRAY_VARS +void +err_badarraysub (s) + const char *s; +{ + report_error ("%s: %s", s, _(bash_badsub_errmsg)); +} +#endif + +void +err_unboundvar (s) + const char *s; +{ + report_error (_("%s: unbound variable"), s); +} + +void +err_readonly (s) + const char *s; +{ + report_error (_("%s: readonly variable"), s); +}