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