1 /*
2 Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #include "atrt.hpp"
26 #include <portlib/NdbDir.hpp>
27 #include <portlib/NdbSleep.h>
28
29 static bool create_directory(const char * path);
30
31 bool
setup_directories(atrt_config & config,int setup)32 setup_directories(atrt_config& config, int setup)
33 {
34 /**
35 * 0 = validate
36 * 1 = setup
37 * 2 = setup+clean
38 */
39 for (size_t i = 0; i < config.m_clusters.size(); i++)
40 {
41 atrt_cluster& cluster = *config.m_clusters[i];
42 for (size_t j = 0; j<cluster.m_processes.size(); j++)
43 {
44 atrt_process& proc = *cluster.m_processes[j];
45 const char * dir = proc.m_proc.m_cwd.c_str();
46 struct stat sbuf;
47 int exists = 0;
48 if (lstat(dir, &sbuf) == 0)
49 {
50 if (S_ISDIR(sbuf.st_mode))
51 exists = 1;
52 else
53 exists = -1;
54 }
55
56 switch(setup){
57 case 0:
58 switch(exists){
59 case 0:
60 g_logger.error("Could not find directory: %s", dir);
61 return false;
62 case -1:
63 g_logger.error("%s is not a directory!", dir);
64 return false;
65 }
66 break;
67 case 1:
68 if (exists == -1)
69 {
70 g_logger.error("%s is not a directory!", dir);
71 return false;
72 }
73 break;
74 case 2:
75 if (exists == 1)
76 {
77 if (!remove_dir(dir))
78 {
79 g_logger.error("Failed to remove %s!", dir);
80 return false;
81 }
82 exists = 0;
83 break;
84 }
85 else if (exists == -1)
86 {
87 if (!unlink(dir))
88 {
89 g_logger.error("Failed to remove %s!", dir);
90 return false;
91 }
92 exists = 0;
93 }
94 }
95 if (exists != 1)
96 {
97 if (!create_directory(dir))
98 {
99 return false;
100 }
101 }
102 }
103 }
104 return true;
105 }
106
107 static
108 void
printfile(FILE * out,Properties & props,const char * section,...)109 printfile(FILE* out, Properties& props, const char * section, ...)
110 {
111 Properties::Iterator it (&props);
112 const char * name = it.first();
113 if (name)
114 {
115 va_list ap;
116 va_start(ap, section);
117 /* const int ret = */ vfprintf(out, section, ap);
118 va_end(ap);
119 fprintf(out, "\n");
120
121 for (; name; name = it.next())
122 {
123 const char* val;
124 props.get(name, &val);
125 fprintf(out, "%s %s\n", name + 2, val);
126 }
127 fprintf(out, "\n");
128 }
129 fflush(out);
130 }
131
132 bool
setup_files(atrt_config & config,int setup,int sshx)133 setup_files(atrt_config& config, int setup, int sshx)
134 {
135 /**
136 * 0 = validate
137 * 1 = setup
138 * 2 = setup+clean
139 */
140 BaseString mycnf;
141 mycnf.assfmt("%s/my.cnf", g_basedir);
142
143 if (!create_directory(g_basedir))
144 {
145 return false;
146 }
147
148 if (mycnf != g_my_cnf)
149 {
150 struct stat sbuf;
151 int ret = lstat(to_native(mycnf).c_str(), &sbuf);
152
153 if (ret == 0)
154 {
155 if (unlink(to_native(mycnf).c_str()) != 0)
156 {
157 g_logger.error("Failed to remove %s", mycnf.c_str());
158 return false;
159 }
160 }
161
162 BaseString cp;
163 cp.assfmt("cp %s %s", g_my_cnf, mycnf.c_str());
164 to_fwd_slashes(cp);
165 if (sh(cp.c_str()) != 0)
166 {
167 g_logger.error("Failed to '%s'", cp.c_str());
168 return false;
169 }
170 }
171
172 if (setup == 2 || config.m_generated)
173 {
174 /**
175 * Do mysql_install_db
176 */
177 for (size_t i = 0; i < config.m_clusters.size(); i++)
178 {
179 atrt_cluster& cluster = *config.m_clusters[i];
180 for (size_t j = 0; j<cluster.m_processes.size(); j++)
181 {
182 atrt_process& proc = *cluster.m_processes[j];
183 if (proc.m_type == atrt_process::AP_MYSQLD)
184 #ifndef _WIN32
185 {
186 const char * val;
187 require(proc.m_options.m_loaded.get("--datadir=", &val));
188 BaseString tmp;
189 tmp.assfmt("%s/bin/mysql_install_db --defaults-file=%s/my.cnf --datadir=%s > %s/mysql_install_db.log 2>&1",
190 g_prefix, g_basedir, val, proc.m_proc.m_cwd.c_str());
191
192 to_fwd_slashes(tmp);
193 if (sh(tmp.c_str()) != 0)
194 {
195 g_logger.error("Failed to mysql_install_db for %s, cmd: '%s'",
196 proc.m_proc.m_cwd.c_str(),
197 tmp.c_str());
198 }
199 else
200 {
201 g_logger.info("mysql_install_db for %s",
202 proc.m_proc.m_cwd.c_str());
203 }
204 }
205 #else
206 {
207 g_logger.info("not running mysql_install_db for %s",
208 proc.m_proc.m_cwd.c_str());
209 }
210 #endif
211 }
212 }
213 }
214
215 FILE * out = NULL;
216 bool retval = true;
217 if (config.m_generated == false)
218 {
219 g_logger.info("Nothing configured...");
220 }
221 else
222 {
223 out = fopen(mycnf.c_str(), "a+");
224 if (out == 0)
225 {
226 g_logger.error("Failed to open %s for append", mycnf.c_str());
227 return false;
228 }
229 time_t now = time(0);
230 fprintf(out, "#\n# Generated by atrt\n");
231 fprintf(out, "# %s\n", ctime(&now));
232 }
233
234 for (size_t i = 0; i < config.m_clusters.size(); i++)
235 {
236 atrt_cluster& cluster = *config.m_clusters[i];
237 if (out)
238 {
239 Properties::Iterator it(&cluster.m_options.m_generated);
240 printfile(out, cluster.m_options.m_generated,
241 "[mysql_cluster%s]", cluster.m_name.c_str());
242 }
243
244 for (size_t j = 0; j<cluster.m_processes.size(); j++)
245 {
246 atrt_process& proc = *cluster.m_processes[j];
247
248 if (out)
249 {
250 switch(proc.m_type){
251 case atrt_process::AP_NDB_MGMD:
252 printfile(out, proc.m_options.m_generated,
253 "[cluster_config.ndb_mgmd.%d%s]",
254 proc.m_index, proc.m_cluster->m_name.c_str());
255 break;
256 case atrt_process::AP_NDBD:
257 printfile(out, proc.m_options.m_generated,
258 "[cluster_config.ndbd.%d%s]",
259 proc.m_index, proc.m_cluster->m_name.c_str());
260 break;
261 case atrt_process::AP_MYSQLD:
262 printfile(out, proc.m_options.m_generated,
263 "[mysqld.%d%s]",
264 proc.m_index, proc.m_cluster->m_name.c_str());
265 break;
266 case atrt_process::AP_NDB_API:
267 break;
268 case atrt_process::AP_CLIENT:
269 printfile(out, proc.m_options.m_generated,
270 "[client.%d%s]",
271 proc.m_index, proc.m_cluster->m_name.c_str());
272 break;
273 case atrt_process::AP_ALL:
274 case atrt_process::AP_CLUSTER:
275 abort();
276 }
277 }
278
279 /**
280 * Create env.sh
281 */
282 BaseString tmp;
283 tmp.assfmt("%s/env.sh", proc.m_proc.m_cwd.c_str());
284 to_native(tmp);
285 char **env = BaseString::argify(0, proc.m_proc.m_env.c_str());
286 if (env[0] || proc.m_proc.m_path.length())
287 {
288 Vector<BaseString> keys;
289 FILE *fenv = fopen(tmp.c_str(), "w+");
290 if (fenv == 0)
291 {
292 g_logger.error("Failed to open %s for writing", tmp.c_str());
293 retval = false;
294 goto end;
295 }
296 for (size_t k = 0; env[k]; k++)
297 {
298 tmp = env[k];
299 ssize_t pos = tmp.indexOf('=');
300 require(pos > 0);
301 env[k][pos] = 0;
302 fprintf(fenv, "%s=\"%s\"\n", env[k], env[k]+pos+1);
303 keys.push_back(env[k]);
304 free(env[k]);
305 }
306 if (proc.m_proc.m_path.length())
307 {
308 fprintf(fenv, "CMD=\"%s", proc.m_proc.m_path.c_str());
309 if (proc.m_proc.m_args.length())
310 {
311 fprintf(fenv, " %s", proc.m_proc.m_args.c_str());
312 }
313 fprintf(fenv, "\"\nexport CMD\n");
314 }
315
316 fprintf(fenv, "PATH=%s/bin:%s/libexec:$PATH\n", g_prefix, g_prefix);
317 keys.push_back("PATH");
318 for (size_t k = 0; k<keys.size(); k++)
319 fprintf(fenv, "export %s\n", keys[k].c_str());
320 fflush(fenv);
321 fclose(fenv);
322 }
323 free(env);
324
325 {
326 tmp.assfmt("%s/ssh-login.sh", proc.m_proc.m_cwd.c_str());
327 FILE* fenv = fopen(tmp.c_str(), "w+");
328 if (fenv == 0)
329 {
330 g_logger.error("Failed to open %s for writing", tmp.c_str());
331 retval = false;
332 goto end;
333 }
334 fprintf(fenv, "#!/bin/sh\n");
335 fprintf(fenv, "cd %s\n", proc.m_proc.m_cwd.c_str());
336 fprintf(fenv, "[ -f /etc/profile ] && . /etc/profile\n");
337 fprintf(fenv, ". ./env.sh\n");
338 fprintf(fenv, "ulimit -Sc unlimited\n");
339 fprintf(fenv, "bash -i");
340 fflush(fenv);
341 fclose(fenv);
342 }
343 }
344 }
345
346 end:
347 if (out)
348 {
349 fclose(out);
350 }
351
352 return retval;
353 }
354
355
356 static
357 bool
create_directory(const char * path)358 create_directory(const char * path)
359 {
360 BaseString native(path);
361 to_native(native);
362 BaseString tmp(path);
363 Vector<BaseString> list;
364
365 if (tmp.split(list, "/") == 0)
366 {
367 g_logger.error("Failed to create directory: %s", tmp.c_str());
368 return false;
369 }
370
371 BaseString cwd = IF_WIN("","/");
372 for (size_t i = 0; i < list.size(); i++)
373 {
374 cwd.append(list[i].c_str());
375 cwd.append("/");
376 NdbDir::create(cwd.c_str(),
377 NdbDir::u_rwx() | NdbDir::g_r() | NdbDir::g_x(),
378 true);
379 }
380
381 struct stat sbuf;
382 if (lstat(native.c_str(), &sbuf) != 0 ||
383 !S_ISDIR(sbuf.st_mode))
384 {
385 g_logger.error("Failed to create directory: %s (%s)",
386 native.c_str(),
387 cwd.c_str());
388 return false;
389 }
390
391 return true;
392 }
393
394 bool
remove_dir(const char * path,bool inclusive)395 remove_dir(const char * path, bool inclusive)
396 {
397 if (access(path, 0))
398 return true;
399
400 const int max_retries = 20;
401 int attempt = 0;
402
403 while(true)
404 {
405 if (NdbDir::remove_recursive(path, !inclusive))
406 return true;
407
408 attempt++;
409 if (attempt > max_retries)
410 {
411 g_logger.error("Failed to remove directory '%s'!", path);
412 return false;
413 }
414
415 g_logger.warning(" - attempt %d to remove directory '%s' failed "
416 ", retrying...", attempt, path);
417
418 NdbSleep_MilliSleep(100);
419 }
420
421 abort(); // Never reached
422 return false;
423 }
424