You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

750 lines
16 KiB

  1. /*
  2. Copyright (c) 2003 Novell, Inc. All Rights Reserved.
  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; either version 2 of the License, or
  6. (at your option) any later version.
  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. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  14. */
  15. #include <stdlib.h>
  16. #include <stdio.h>
  17. #include <netdb.h>
  18. #include <sys/stat.h>
  19. #include <monitor.h>
  20. #include <strings.h>
  21. #include <getopt.h>
  22. #include <screen.h>
  23. #include <dirent.h>
  24. #include "my_config.h"
  25. #include "my_manage.h"
  26. /******************************************************************************
  27. global variables
  28. ******************************************************************************/
  29. char autoclose;
  30. char basedir[PATH_MAX];
  31. char checktables;
  32. char datadir[PATH_MAX];
  33. char pid_file[PATH_MAX];
  34. char address[PATH_MAX];
  35. char port[PATH_MAX];
  36. char err_log[PATH_MAX];
  37. char safe_log[PATH_MAX];
  38. char mysqld[PATH_MAX];
  39. char hostname[PATH_MAX];
  40. char default_option[PATH_MAX];
  41. FILE *log_fd= NULL;
  42. /******************************************************************************
  43. prototypes
  44. ******************************************************************************/
  45. void usage(void);
  46. void vlog(char *, va_list);
  47. void log(char *, ...);
  48. void start_defaults(int, char *[]);
  49. void finish_defaults();
  50. void read_defaults(arg_list_t *);
  51. void parse_args(int, char *[]);
  52. void get_options(int, char *[]);
  53. void check_data_vol();
  54. void check_setup();
  55. void check_tables();
  56. void mysql_start(int, char *[]);
  57. void parse_setvar(char *arg);
  58. /******************************************************************************
  59. functions
  60. ******************************************************************************/
  61. /******************************************************************************
  62. usage()
  63. Show usage.
  64. ******************************************************************************/
  65. void usage(void)
  66. {
  67. // keep the screen up
  68. setscreenmode(SCR_NO_MODE);
  69. puts("\
  70. \n\
  71. usage: mysqld_safe [options]\n\
  72. \n\
  73. Program to start the MySQL daemon and restart it if it dies unexpectedly.\n\
  74. All options, besides those listed below, are passed on to the MySQL daemon.\n\
  75. \n\
  76. options:\n\
  77. \n\
  78. --autoclose Automatically close the mysqld_safe screen.\n\
  79. \n\
  80. --check-tables Check the tables before starting the MySQL daemon.\n\
  81. \n\
  82. --err-log=<file> Send the MySQL daemon error output to <file>.\n\
  83. \n\
  84. --help Show this help information.\n\
  85. \n\
  86. --mysqld=<file> Use the <file> MySQL daemon.\n\
  87. \n\
  88. ");
  89. exit(-1);
  90. }
  91. /******************************************************************************
  92. vlog()
  93. Log the message.
  94. ******************************************************************************/
  95. void vlog(char *format, va_list ap)
  96. {
  97. vfprintf(stdout, format, ap);
  98. fflush(stdout);
  99. if (log_fd)
  100. {
  101. vfprintf(log_fd, format, ap);
  102. fflush(log_fd);
  103. }
  104. }
  105. /******************************************************************************
  106. log()
  107. Log the message.
  108. ******************************************************************************/
  109. void log(char *format, ...)
  110. {
  111. va_list ap;
  112. va_start(ap, format);
  113. vlog(format, ap);
  114. va_end(ap);
  115. }
  116. /******************************************************************************
  117. start_defaults()
  118. Start setting the defaults.
  119. ******************************************************************************/
  120. void start_defaults(int argc, char *argv[])
  121. {
  122. struct stat buf;
  123. int i;
  124. // default options
  125. static char *default_options[]=
  126. {
  127. "--no-defaults",
  128. "--defaults-file=",
  129. "--defaults-extra-file=",
  130. NULL
  131. };
  132. // autoclose
  133. autoclose= FALSE;
  134. // basedir
  135. get_basedir(argv[0], basedir);
  136. // check-tables
  137. checktables= FALSE;
  138. // hostname
  139. if (gethostname(hostname, PATH_MAX) < 0)
  140. {
  141. // default
  142. strcpy(hostname, "mysql");
  143. }
  144. // address
  145. snprintf(address, PATH_MAX, "0.0.0.0");
  146. // port
  147. snprintf(port, PATH_MAX, "3306");
  148. // default option
  149. default_option[0]= NULL;
  150. for (i= 0; (argc > 1) && default_options[i]; i++)
  151. {
  152. if (!strnicmp(argv[1], default_options[i], strlen(default_options[i])))
  153. {
  154. strncpy(default_option, argv[1], PATH_MAX);
  155. break;
  156. }
  157. }
  158. // set after basedir is established
  159. datadir[0]= NULL;
  160. pid_file[0]= NULL;
  161. err_log[0]= NULL;
  162. safe_log[0]= NULL;
  163. mysqld[0]= NULL;
  164. }
  165. /******************************************************************************
  166. finish_defaults()
  167. Finish settig the defaults.
  168. ******************************************************************************/
  169. void finish_defaults()
  170. {
  171. struct stat buf;
  172. int i;
  173. // datadir
  174. if (!datadir[0])
  175. snprintf(datadir, PATH_MAX, "%s/data", basedir);
  176. // pid-file
  177. if (!pid_file[0])
  178. snprintf(pid_file, PATH_MAX, "%s/%s.pid", datadir, hostname);
  179. // err-log
  180. if (!err_log[0])
  181. snprintf(err_log, PATH_MAX, "%s/%s.err", datadir, hostname);
  182. // safe-log
  183. if (!safe_log[0])
  184. snprintf(safe_log, PATH_MAX, "%s/%s.safe", datadir, hostname);
  185. // mysqld
  186. if (!mysqld[0])
  187. snprintf(mysqld, PATH_MAX, "%s/bin/mysqld-max", basedir);
  188. if (stat(mysqld, &buf))
  189. {
  190. snprintf(mysqld, PATH_MAX, "%s/bin/mysqld", basedir);
  191. }
  192. }
  193. /******************************************************************************
  194. read_defaults()
  195. Read the defaults.
  196. ******************************************************************************/
  197. void read_defaults(arg_list_t *pal)
  198. {
  199. arg_list_t al;
  200. char defaults_file[PATH_MAX];
  201. char mydefaults[PATH_MAX];
  202. char line[PATH_MAX];
  203. FILE *fp;
  204. // defaults output file
  205. snprintf(defaults_file, PATH_MAX, "%s/bin/defaults.out", basedir);
  206. remove(defaults_file);
  207. // mysqladmin file
  208. snprintf(mydefaults, PATH_MAX, "%s/bin/my_print_defaults", basedir);
  209. // args
  210. init_args(&al);
  211. add_arg(&al, mydefaults);
  212. if (default_option[0])
  213. add_arg(&al, default_option);
  214. add_arg(&al, "mysqld");
  215. add_arg(&al, "server");
  216. add_arg(&al, "mysqld_safe");
  217. add_arg(&al, "safe_mysqld");
  218. spawn(mydefaults, &al, TRUE, NULL, defaults_file, NULL);
  219. free_args(&al);
  220. // gather defaults
  221. if ((fp= fopen(defaults_file, "r")) != NULL)
  222. {
  223. while (fgets(line, PATH_MAX, fp))
  224. {
  225. char *p;
  226. // remove end-of-line character
  227. if ((p= strrchr(line, '\n')) != NULL)
  228. *p= '\0';
  229. // add the option as an argument
  230. add_arg(pal, line);
  231. }
  232. fclose(fp);
  233. }
  234. // remove file
  235. remove(defaults_file);
  236. }
  237. /******************************************************************************
  238. parse_args()
  239. Get the options.
  240. ******************************************************************************/
  241. void parse_args(int argc, char *argv[])
  242. {
  243. int index= 0;
  244. int c;
  245. // parse options
  246. enum opts
  247. {
  248. OPT_BASEDIR= 0xFF,
  249. OPT_DATADIR,
  250. OPT_PID_FILE,
  251. OPT_BIND_ADDRESS,
  252. OPT_PORT,
  253. OPT_ERR_LOG,
  254. OPT_SAFE_LOG,
  255. OPT_MYSQLD,
  256. OPT_HELP,
  257. OPT_SETVAR
  258. };
  259. static struct option options[]=
  260. {
  261. {"autoclose", no_argument, &autoclose, TRUE},
  262. {"basedir", required_argument, 0, OPT_BASEDIR},
  263. {"check-tables", no_argument, &checktables, TRUE},
  264. {"datadir", required_argument, 0, OPT_DATADIR},
  265. {"pid-file", required_argument, 0, OPT_PID_FILE},
  266. {"bind-address", required_argument, 0, OPT_BIND_ADDRESS},
  267. {"port", required_argument, 0, OPT_PORT},
  268. {"err-log", required_argument, 0, OPT_ERR_LOG},
  269. {"safe-log", required_argument, 0, OPT_SAFE_LOG},
  270. {"mysqld", required_argument, 0, OPT_MYSQLD},
  271. {"help", no_argument, 0, OPT_HELP},
  272. {"set-variable", required_argument, 0, OPT_SETVAR},
  273. {0, 0, 0, 0}
  274. };
  275. // we have to reset getopt_long because we use it multiple times
  276. optind= 1;
  277. // turn off error reporting
  278. opterr= 0;
  279. while ((c= getopt_long(argc, argv, "b:h:P:", options, &index)) >= 0)
  280. {
  281. switch (c) {
  282. case OPT_BASEDIR:
  283. case 'b':
  284. strcpy(basedir, optarg);
  285. break;
  286. case OPT_DATADIR:
  287. case 'h':
  288. strcpy(datadir, optarg);
  289. break;
  290. case OPT_PID_FILE:
  291. strcpy(pid_file, optarg);
  292. break;
  293. case OPT_BIND_ADDRESS:
  294. strcpy(address, optarg);
  295. break;
  296. case OPT_PORT:
  297. case 'P':
  298. strcpy(port, optarg);
  299. break;
  300. case OPT_ERR_LOG:
  301. strcpy(err_log, optarg);
  302. break;
  303. case OPT_SAFE_LOG:
  304. strcpy(safe_log, optarg);
  305. break;
  306. case OPT_MYSQLD:
  307. strcpy(mysqld, optarg);
  308. break;
  309. case OPT_SETVAR:
  310. parse_setvar(optarg);
  311. break;
  312. case OPT_HELP:
  313. usage();
  314. break;
  315. default:
  316. // ignore
  317. break;
  318. }
  319. }
  320. }
  321. /*
  322. parse_setvar(char *arg)
  323. Pasrsing for port just to display the port num on the mysqld_safe screen
  324. */
  325. void parse_setvar(char *arg)
  326. {
  327. char *pos;
  328. if ((pos= strindex(arg, "port")))
  329. {
  330. for (; *pos && *pos != '='; pos++);
  331. if (*pos)
  332. strcpy(port, pos + 1);
  333. }
  334. }
  335. /******************************************************************************
  336. /******************************************************************************
  337. get_options()
  338. Get the options.
  339. ******************************************************************************/
  340. void get_options(int argc, char *argv[])
  341. {
  342. arg_list_t al;
  343. // start defaults
  344. start_defaults(argc, argv);
  345. // default file arguments
  346. init_args(&al);
  347. add_arg(&al, "ignore");
  348. read_defaults(&al);
  349. parse_args(al.argc, al.argv);
  350. free_args(&al);
  351. // command-line arguments
  352. parse_args(argc, argv);
  353. // finish defaults
  354. finish_defaults();
  355. }
  356. /******************************************************************************
  357. check_data_vol()
  358. Check the database volume.
  359. ******************************************************************************/
  360. void check_data_vol()
  361. {
  362. // warn if the data is on a Traditional volume
  363. struct volume_info vol;
  364. char buff[PATH_MAX];
  365. char *p;
  366. // clear struct
  367. memset(&vol, 0, sizeof(vol));
  368. // find volume name
  369. strcpy(buff, datadir);
  370. if (p= strchr(buff, ':'))
  371. {
  372. // terminate after volume name
  373. *p= 0;
  374. }
  375. else
  376. {
  377. // assume SYS volume
  378. strcpy(buff, "SYS");
  379. }
  380. // retrieve information
  381. netware_vol_info_from_name(&vol, buff);
  382. if ((vol.flags & VOL_NSS_PRESENT) == 0)
  383. {
  384. log("Error: Either the data directory does not exist or is not on an NSS volume!\n\n");
  385. exit(-1);
  386. }
  387. }
  388. /******************************************************************************
  389. check_setup()
  390. Check the current setup.
  391. ******************************************************************************/
  392. void check_setup()
  393. {
  394. struct stat info;
  395. char temp[PATH_MAX];
  396. // remove any current pid_file
  397. if (!stat(pid_file, &info) && (remove(pid_file) < 0))
  398. {
  399. log("ERROR: Unable to remove current pid file!\n\n");
  400. exit(-1);
  401. }
  402. // check the data volume
  403. check_data_vol();
  404. // check for a database
  405. snprintf(temp, PATH_MAX, "%s/mysql/host.frm", datadir);
  406. if (stat(temp, &info))
  407. {
  408. log("ERROR: No database found in the data directory!\n\n");
  409. exit(-1);
  410. }
  411. }
  412. /******************************************************************************
  413. check_tables()
  414. Check the database tables.
  415. ******************************************************************************/
  416. void check_tables()
  417. {
  418. arg_list_t al;
  419. char mycheck[PATH_MAX];
  420. char table[PATH_MAX];
  421. char db[PATH_MAX];
  422. DIR *datadir_entry, *db_entry, *table_entry;
  423. // status
  424. log("checking tables...\n");
  425. // list databases
  426. if ((datadir_entry= opendir(datadir)) == NULL)
  427. {
  428. return;
  429. }
  430. while ((db_entry= readdir(datadir_entry)) != NULL)
  431. {
  432. if (db_entry->d_name[0] == '.')
  433. {
  434. // Skip
  435. }
  436. else if (S_ISDIR(db_entry->d_type))
  437. {
  438. // create long db name
  439. snprintf(db, PATH_MAX, "%s/%s", datadir, db_entry->d_name);
  440. // list tables
  441. if ((db_entry= opendir(db)) == NULL)
  442. {
  443. continue;
  444. }
  445. while ((table_entry= readdir(db_entry)) != NULL)
  446. {
  447. // create long table name
  448. snprintf(table, PATH_MAX, "%s/%s", db, strlwr(table_entry->d_name));
  449. if (strindex(table, ".myi"))
  450. {
  451. // ** myisamchk
  452. // mysqladmin file
  453. snprintf(mycheck, PATH_MAX, "%s/bin/myisamchk", basedir);
  454. // args
  455. init_args(&al);
  456. add_arg(&al, mycheck);
  457. add_arg(&al, "--silent");
  458. add_arg(&al, "--force");
  459. add_arg(&al, "--fast");
  460. add_arg(&al, "--medium-check");
  461. add_arg(&al, "-O");
  462. add_arg(&al, "key_buffer=64M");
  463. add_arg(&al, "-O");
  464. add_arg(&al, "sort_buffer=64M");
  465. add_arg(&al, table);
  466. spawn(mycheck, &al, TRUE, NULL, NULL, NULL);
  467. free_args(&al);
  468. }
  469. else if (strindex(table, ".ism"))
  470. {
  471. // ** isamchk
  472. // mysqladmin file
  473. snprintf(mycheck, PATH_MAX, "%s/bin/isamchk", basedir);
  474. // args
  475. init_args(&al);
  476. add_arg(&al, mycheck);
  477. add_arg(&al, "--silent");
  478. add_arg(&al, "--force");
  479. add_arg(&al, "-O");
  480. add_arg(&al, "sort_buffer=64M");
  481. add_arg(&al, table);
  482. spawn(mycheck, &al, TRUE, NULL, NULL, NULL);
  483. free_args(&al);
  484. }
  485. }
  486. }
  487. }
  488. }
  489. /******************************************************************************
  490. mysql_start()
  491. Start the mysql server.
  492. ******************************************************************************/
  493. void mysql_start(int argc, char *argv[])
  494. {
  495. arg_list_t al;
  496. int i, j, err;
  497. struct stat info;
  498. time_t cal;
  499. struct tm lt;
  500. char stamp[PATH_MAX];
  501. char skip;
  502. // private options
  503. static char *private_options[]=
  504. {
  505. "--autoclose",
  506. "--check-tables",
  507. "--help",
  508. "--err-log=",
  509. "--mysqld=",
  510. NULL
  511. };
  512. // args
  513. init_args(&al);
  514. add_arg(&al, "%s", mysqld);
  515. // parent args
  516. for (i= 1; i < argc; i++)
  517. {
  518. skip= FALSE;
  519. // skip private arguments
  520. for (j= 0; private_options[j]; j++)
  521. {
  522. if (!strnicmp(argv[i], private_options[j], strlen(private_options[j])))
  523. {
  524. skip= TRUE;
  525. break;
  526. }
  527. }
  528. if (!skip)
  529. {
  530. add_arg(&al, "%s", argv[i]);
  531. }
  532. }
  533. // spawn
  534. do
  535. {
  536. // check the database tables
  537. if (checktables)
  538. check_tables();
  539. // status
  540. time(&cal);
  541. localtime_r(&cal, &lt);
  542. strftime(stamp, PATH_MAX, "%d %b %Y %H:%M:%S", &lt);
  543. log("mysql started : %s\n", stamp);
  544. // spawn mysqld
  545. spawn(mysqld, &al, TRUE, NULL, NULL, err_log);
  546. }
  547. while (!stat(pid_file, &info));
  548. // status
  549. time(&cal);
  550. localtime_r(&cal, &lt);
  551. strftime(stamp, PATH_MAX, "%d %b %Y %H:%M:%S", &lt);
  552. log("mysql stopped : %s\n\n", stamp);
  553. // free args
  554. free_args(&al);
  555. }
  556. /******************************************************************************
  557. main()
  558. ******************************************************************************/
  559. int main(int argc, char **argv)
  560. {
  561. char temp[PATH_MAX];
  562. // get the options
  563. get_options(argc, argv);
  564. // keep the screen up
  565. if (!autoclose)
  566. setscreenmode(SCR_NO_MODE);
  567. // create log file
  568. log_fd= fopen(safe_log, "w+");
  569. // header
  570. log("MySQL Server %s, for %s (%s)\n\n", VERSION, SYSTEM_TYPE, MACHINE_TYPE);
  571. // status
  572. log("address : %s\n", address);
  573. log("port : %s\n", port);
  574. log("daemon : %s\n", mysqld);
  575. log("base directory : %s\n", basedir);
  576. log("data directory : %s\n", datadir);
  577. log("pid file : %s\n", pid_file);
  578. log("error file : %s\n", err_log);
  579. log("log file : %s\n", safe_log);
  580. log("\n");
  581. // check setup
  582. check_setup();
  583. // start the MySQL server
  584. mysql_start(argc, argv);
  585. // close log file
  586. if (log_fd)
  587. fclose(log_fd);
  588. return 0;
  589. }