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