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