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