1 /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software Foundation,
21    51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22 
23 
24 /**
25   @file
26 
27   @brief
28   Read language depeneded messagefile
29 */
30 
31 #include "sql_priv.h"
32 #include "unireg.h"
33 #include "derror.h"
34 #include "mysys_err.h"
35 #include "mysqld.h"                             // lc_messages_dir
36 #include "derror.h"                             // read_texts
37 #include "sql_class.h"                          // THD
38 
39 static void init_myfunc_errs(void);
40 
41 
42 C_MODE_START
get_server_errmsgs()43 static const char **get_server_errmsgs()
44 {
45   if (!current_thd)
46     return DEFAULT_ERRMSGS;
47   return CURRENT_THD_ERRMSGS;
48 }
49 C_MODE_END
50 
51 /**
52   Read messages from errorfile.
53 
54   This function can be called multiple times to reload the messages.
55   If it fails to load the messages, it will fail softly by initializing
56   the errmesg pointer to an array of empty strings or by keeping the
57   old array if it exists.
58 
59   @retval
60     FALSE       OK
61   @retval
62     TRUE        Error
63 */
64 
init_errmessage(void)65 bool init_errmessage(void)
66 {
67   const char **errmsgs, **ptr;
68   DBUG_ENTER("init_errmessage");
69 
70   /*
71     Get a pointer to the old error messages pointer array.
72     read_texts() tries to free it.
73   */
74   errmsgs= my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST);
75 
76   /* Read messages from file. */
77   if (read_texts(ERRMSG_FILE, my_default_lc_messages->errmsgs->language,
78                  &errmsgs, ER_ERROR_LAST - ER_ERROR_FIRST + 1) &&
79       !errmsgs)
80   {
81     if (!(errmsgs= (const char**) my_malloc((ER_ERROR_LAST-ER_ERROR_FIRST+1)*
82                                             sizeof(char*), MYF(0))))
83       DBUG_RETURN(TRUE);
84     for (ptr= errmsgs; ptr < errmsgs + ER_ERROR_LAST - ER_ERROR_FIRST; ptr++)
85 	  *ptr= "";
86   }
87 
88   /* Register messages for use with my_error(). */
89   if (my_error_register(get_server_errmsgs, ER_ERROR_FIRST, ER_ERROR_LAST))
90   {
91     my_free(errmsgs);
92     DBUG_RETURN(TRUE);
93   }
94 
95   DEFAULT_ERRMSGS= errmsgs;             /* Init global variable */
96   init_myfunc_errs();			/* Init myfunc messages */
97   DBUG_RETURN(FALSE);
98 }
99 
100 
101 /**
102   Read text from packed textfile in language-directory.
103 
104   If we can't read messagefile then it's panic- we can't continue.
105 */
106 
read_texts(const char * file_name,const char * language,const char *** point,uint error_messages)107 bool read_texts(const char *file_name, const char *language,
108                 const char ***point, uint error_messages)
109 {
110   register uint i;
111   uint count,funktpos,textcount;
112   size_t length;
113   File file;
114   char name[FN_REFLEN];
115   char lang_path[FN_REFLEN];
116   uchar *buff;
117   uchar head[32],*pos;
118   DBUG_ENTER("read_texts");
119 
120   LINT_INIT(buff);
121   funktpos=0;
122   convert_dirname(lang_path, language, NullS);
123   (void) my_load_path(lang_path, lang_path, lc_messages_dir);
124   if ((file= mysql_file_open(key_file_ERRMSG,
125                              fn_format(name, file_name, lang_path, "", 4),
126                              O_RDONLY | O_SHARE | O_BINARY,
127                              MYF(0))) < 0)
128   {
129     /*
130       Trying pre-5.4 sematics of the --language parameter.
131       It included the language-specific part, e.g.:
132 
133       --language=/path/to/english/
134     */
135     if ((file= mysql_file_open(key_file_ERRMSG,
136                                fn_format(name, file_name, lc_messages_dir, "", 4),
137                                O_RDONLY | O_SHARE | O_BINARY,
138                                MYF(0))) < 0)
139       goto err;
140 
141     sql_print_warning("Using pre 5.5 semantics to load error messages from %s.",
142                       lc_messages_dir);
143 
144     sql_print_warning("If this is not intended, refer to the documentation for "
145                       "valid usage of --lc-messages-dir and --language "
146                       "parameters.");
147   }
148 
149   funktpos=1;
150   if (mysql_file_read(file, (uchar*) head, 32, MYF(MY_NABP)))
151     goto err;
152   if (head[0] != (uchar) 254 || head[1] != (uchar) 254 ||
153       head[2] != 3 || head[3] != 1)
154     goto err; /* purecov: inspected */
155   textcount=head[4];
156 
157   error_message_charset_info= system_charset_info;
158   length=uint4korr(head+6); count=uint4korr(head+10);
159 
160   if (count < error_messages)
161   {
162     sql_print_error("\
163 Error message file '%s' had only %d error messages,\n\
164 but it should contain at least %d error messages.\n\
165 Check that the above file is the right version for this program!",
166 		    name,count,error_messages);
167     (void) mysql_file_close(file, MYF(MY_WME));
168     DBUG_RETURN(1);
169   }
170 
171   /* Free old language */
172   my_free(*point);
173   if (!(*point= (const char**)
174 	my_malloc((size_t) (length+count*sizeof(char*)),MYF(0))))
175   {
176     funktpos=2;					/* purecov: inspected */
177     goto err;					/* purecov: inspected */
178   }
179   buff= (uchar*) (*point + count);
180 
181   if (mysql_file_read(file, buff, (size_t) count*4, MYF(MY_NABP)))
182     goto err;
183   for (i=0, pos= buff ; i< count ; i++)
184   {
185     (*point)[i]= (char*) buff+uint4korr(pos);
186     pos+=4;
187   }
188   if (mysql_file_read(file, buff, length, MYF(MY_NABP)))
189     goto err;
190 
191   for (i=1 ; i < textcount ; i++)
192   {
193     point[i]= *point +uint2korr(head+10+i+i);
194   }
195   (void) mysql_file_close(file, MYF(0));
196   DBUG_RETURN(0);
197 
198 err:
199   sql_print_error((funktpos == 2) ? "Not enough memory for messagefile '%s'" :
200                   ((funktpos == 1) ? "Can't read from messagefile '%s'" :
201                    "Can't find messagefile '%s'"), name);
202   if (file != FERR)
203     (void) mysql_file_close(file, MYF(MY_WME));
204   DBUG_RETURN(1);
205 } /* read_texts */
206 
207 
208 /**
209   Initiates error-messages used by my_func-library.
210 */
211 
init_myfunc_errs()212 static void init_myfunc_errs()
213 {
214   init_glob_errs();			/* Initiate english errors */
215   if (!(specialflag & SPECIAL_ENGLISH))
216   {
217     EE(EE_FILENOTFOUND)   = ER(ER_FILE_NOT_FOUND);
218     EE(EE_CANTCREATEFILE) = ER(ER_CANT_CREATE_FILE);
219     EE(EE_READ)           = ER(ER_ERROR_ON_READ);
220     EE(EE_WRITE)          = ER(ER_ERROR_ON_WRITE);
221     EE(EE_BADCLOSE)       = ER(ER_ERROR_ON_CLOSE);
222     EE(EE_OUTOFMEMORY)    = ER(ER_OUTOFMEMORY);
223     EE(EE_DELETE)         = ER(ER_CANT_DELETE_FILE);
224     EE(EE_LINK)           = ER(ER_ERROR_ON_RENAME);
225     EE(EE_EOFERR)         = ER(ER_UNEXPECTED_EOF);
226     EE(EE_CANTLOCK)       = ER(ER_CANT_LOCK);
227     EE(EE_DIR)            = ER(ER_CANT_READ_DIR);
228     EE(EE_STAT)           = ER(ER_CANT_GET_STAT);
229     EE(EE_GETWD)          = ER(ER_CANT_GET_WD);
230     EE(EE_SETWD)          = ER(ER_CANT_SET_WD);
231     EE(EE_DISK_FULL)      = ER(ER_DISK_FULL);
232   }
233 }
234