1/*
2 Copyright (c) 2011, 2015, 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 Street, Fifth Floor, Boston, MA 02110-1301, USA
16*/
17
18#include <my_global.h>
19#include <m_string.h>
20#include <mysql.h>
21#include <my_getopt.h>
22#include <my_dir.h>
23#include <mysql_version.h>
24
25#define SHOW_VERSION "1.0.0"
26#define PRINT_VERSION do { printf("%s Ver %s Distrib %s\n", \
27 my_progname, SHOW_VERSION, MYSQL_SERVER_VERSION); \
28 } while(0)
29
30/* Global variables. */
31static uint my_end_arg= 0;
32static uint opt_verbose=0;
33static uint opt_no_defaults= 0;
34static uint opt_print_defaults= 0;
35static char *opt_datadir=0, *opt_basedir=0,
36 *opt_plugin_dir=0, *opt_plugin_ini=0,
37 *opt_mysqld=0, *opt_my_print_defaults=0;
38static char bootstrap[FN_REFLEN];
39
40
41/* plugin struct */
42struct st_plugin
43{
44 const char *name; /* plugin name */
45 const char *so_name; /* plugin so (library) name */
46 const char *components[16]; /* components to load */
47} plugin_data;
48
49
50/* Options */
51static struct my_option my_long_options[] =
52{
53 {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
54 0, 0, 0, 0, 0, 0},
55 {"basedir", 'b', "The basedir for the server.",
56 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
57 {"datadir", 'd', "The datadir for the server.",
58 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
59 {"plugin-dir", 'p', "The plugin dir for the server.",
60 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
61 {"plugin-ini", 'i', "Read plugin information from configuration file "
62 "specified instead of from <plugin-dir>/<plugin_name>.ini.",
63 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
64 {"no-defaults", 'n', "Do not read values from configuration file.",
65 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
66 {"print-defaults", 'P', "Show default values from configuration file.",
67 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
68 {"mysqld", 'm', "Path to mysqld executable. Example: /sbin/temp1/mysql/bin",
69 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
70 {"my-print-defaults", 'f', "Path to my_print_defaults executable. "
71 "Example: /source/temp11/extra",
72 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
73 {"verbose", 'v',
74 "More verbose output; you can use this multiple times to get even more "
75 "verbose output.",
76 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
77 {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
78 NO_ARG, 0, 0, 0, 0, 0, 0},
79 {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
80};
81
82
83/* Methods */
84static int process_options(int argc, char *argv[], char *operation);
85static int check_access();
86static int find_tool(const char *tool_name, char *tool_path);
87static int find_plugin(char *tp_path);
88static int build_bootstrap_file(char *operation, char *bootstrap);
89static int dump_bootstrap_file(char *bootstrap_file);
90static int bootstrap_server(char *server_path, char *bootstrap_file);
91
92
93int main(int argc,char *argv[])
94{
95 int error= 0;
96 char tp_path[FN_REFLEN];
97 char server_path[FN_REFLEN];
98 char operation[16];
99
100 MY_INIT(argv[0]);
101 sf_leaking_memory=1; /* don't report memory leaks on early exits */
102 plugin_data.name= 0; /* initialize name */
103
104 /*
105 The following operations comprise the method for enabling or disabling
106 a plugin. We begin by processing the command options then check the
107 directories specified for --datadir, --basedir, --plugin-dir, and
108 --plugin-ini (if specified). If the directories are Ok, we then look
109 for the mysqld executable and the plugin soname. Finally, we build a
110 bootstrap command file for use in bootstraping the server.
111
112 If any step fails, the method issues an error message and the tool exits.
113
114 1) Parse, execute, and verify command options.
115 2) Check access to directories.
116 3) Look for mysqld executable.
117 4) Look for the plugin.
118 5) Build a bootstrap file with commands to enable or disable plugin.
119
120 */
121 if ((error= process_options(argc, argv, operation)) ||
122 (error= check_access()) ||
123 (error= find_tool("mysqld" FN_EXEEXT, server_path)) ||
124 (error= find_plugin(tp_path)) ||
125 (error= build_bootstrap_file(operation, bootstrap)))
126 goto exit;
127
128 /* Dump the bootstrap file if --verbose specified. */
129 if (opt_verbose && ((error= dump_bootstrap_file(bootstrap))))
130 goto exit;
131
132 /* Start the server in bootstrap mode and execute bootstrap commands */
133 error= bootstrap_server(server_path, bootstrap);
134
135exit:
136 /* Remove file */
137 my_delete(bootstrap, MYF(0));
138 if (opt_verbose && error == 0)
139 {
140 printf("# Operation succeeded.\n");
141 }
142
143 my_end(my_end_arg);
144 exit(error ? 1 : 0);
145 return 0; /* No compiler warnings */
146}
147
148
149/**
150 Get a temporary file name.
151
152 @param[out] filename The file name of the temporary file
153 @param[in] ext An extension for the file (optional)
154
155 @retval int error = 1, success = 0
156*/
157
158static int make_tempfile(char *filename, const char *ext)
159{
160 int fd= 0;
161
162 if ((fd= create_temp_file(filename, NullS, ext, 0, MYF(MY_WME))) < 0)
163 {
164 fprintf(stderr, "ERROR: Cannot generate temporary file. Error code: %d.\n",
165 fd);
166 return 1;
167 }
168 my_close(fd, MYF(0));
169 return 0;
170}
171
172
173/**
174 Get the value of an option from a string read from my_print_defaults output.
175
176 @param[in] line The line (string) read from the file
177 @param[in] item The option to search for (e.g. --datadir)
178
179 @returns NULL if not found, string containing value if found
180*/
181
182static char *get_value(char *line, const char *item)
183{
184 char *destination= 0;
185 int item_len= (int)strlen(item);
186 int line_len = (int)strlen(line);
187
188 if ((strncasecmp(line, item, item_len) == 0))
189 {
190 int start= 0;
191 char *s= 0;
192
193 s = line + item_len + 1;
194 destination= my_strndup(s, line_len - start, MYF(MY_FAE));
195 destination[line_len - item_len - 2]= 0;
196 }
197 return destination;
198}
199
200
201/**
202 Run a command in a shell.
203
204 This function will attempt to execute the command specified by using the
205 popen() method to open a shell and execute the command passed and store the
206 output in a result file. If the --verbose option was specified, it will open
207 the result file and print the contents to stdout.
208
209 @param[in] cmd The command to execute.
210 @param[in] mode The mode for popen() (e.g. "r", "w", "rw")
211
212 @return int error code or 0 for success.
213*/
214
215static int run_command(char* cmd, const char *mode)
216{
217 char buf[512]= {0};
218 FILE *res_file;
219 int error;
220
221 if (!(res_file= popen(cmd, mode)))
222 return -1;
223
224 if (opt_verbose)
225 {
226 while (fgets(buf, sizeof(buf), res_file))
227 {
228 fprintf(stdout, "%s", buf);
229 }
230 }
231 error= pclose(res_file);
232 return error;
233}
234
235
236#ifdef __WIN__
237/**
238 Check to see if there are spaces in a path.
239
240 @param[in] path The Windows path to examine.
241
242 @retval int spaces found = 1, no spaces = 0
243*/
244static int has_spaces(const char *path)
245{
246 if (strchr(path, ' ') != NULL)
247 return 1;
248 return 0;
249}
250
251
252/**
253 Convert a Unix path to a Windows path.
254
255 @param[in] path The Windows path to examine.
256
257 @returns string containing path with / changed to \\
258*/
259static char *convert_path(const char *argument)
260{
261 /* Convert / to \\ to make Windows paths */
262 char *winfilename= my_strdup(argument, MYF(MY_FAE));
263 char *pos, *end;
264 size_t length= strlen(argument);
265
266 for (pos= winfilename, end= pos+length ; pos < end ; pos++)
267 {
268 if (*pos == '/')
269 {
270 *pos= '\\';
271 }
272 }
273 return winfilename;
274}
275
276
277/**
278 Add quotes if the path has spaces in it.
279
280 @param[in] path The Windows path to examine.
281
282 @returns string containing excaped quotes if spaces found in path
283*/
284static char *add_quotes(const char *path)
285{
286 char windows_cmd_friendly[FN_REFLEN];
287
288 if (has_spaces(path))
289 snprintf(windows_cmd_friendly, sizeof(windows_cmd_friendly),
290 "\"%s\"", path);
291 else
292 snprintf(windows_cmd_friendly, sizeof(windows_cmd_friendly),
293 "%s", path);
294 return my_strdup(windows_cmd_friendly, MYF(MY_FAE));
295}
296#endif
297
298
299/**
300 Get the default values from the my.cnf file.
301
302 This method gets the default values for the following parameters:
303
304 --datadir
305 --basedir
306 --plugin-dir
307 --plugin-ini
308
309 These values are used if the user has not specified a value.
310
311 @retval int error = 1, success = 0
312*/
313
314static int get_default_values()
315{
316 char tool_path[FN_REFLEN];
317 char defaults_cmd[FN_REFLEN];
318 char defaults_file[FN_REFLEN];
319 char line[FN_REFLEN];
320 int error= 0;
321 int ret= 0;
322 FILE *file= 0;
323
324 bzero(tool_path, FN_REFLEN);
325 if ((error= find_tool("my_print_defaults" FN_EXEEXT, tool_path)))
326 goto exit;
327 else
328 {
329 if ((error= make_tempfile(defaults_file, "txt")))
330 goto exit;
331
332#ifdef __WIN__
333 {
334 char *format_str= 0;
335
336 if (has_spaces(tool_path) || has_spaces(defaults_file))
337 format_str = "\"%s mysqld > %s\"";
338 else
339 format_str = "%s mysqld > %s";
340
341 snprintf(defaults_cmd, sizeof(defaults_cmd), format_str,
342 add_quotes(tool_path), add_quotes(defaults_file));
343 if (opt_verbose)
344 {
345 printf("# my_print_defaults found: %s\n", tool_path);
346 }
347 }
348#else
349 snprintf(defaults_cmd, sizeof(defaults_cmd),
350 "%s mysqld > %s", tool_path, defaults_file);
351#endif
352
353 /* Execute the command */
354 if (opt_verbose)
355 {
356 printf("# Command: %s\n", defaults_cmd);
357 }
358 error= run_command(defaults_cmd, "r");
359 if (error)
360 {
361 fprintf(stderr, "ERROR: my_print_defaults failed. Error code: %d.\n",
362 ret);
363 goto exit;
364 }
365 /* Now open the file and read the defaults we want. */
366 file= fopen(defaults_file, "r");
367 if (file == NULL)
368 {
369 fprintf(stderr, "ERROR: failed to open file %s: %s.\n", defaults_file,
370 strerror(errno));
371 goto exit;
372 }
373 while (fgets(line, FN_REFLEN, file) != NULL)
374 {
375 char *value= 0;
376
377 if ((opt_datadir == 0) && ((value= get_value(line, "--datadir"))))
378 {
379 opt_datadir= my_strdup(value, MYF(MY_FAE));
380 }
381 if ((opt_basedir == 0) && ((value= get_value(line, "--basedir"))))
382 {
383 opt_basedir= my_strdup(value, MYF(MY_FAE));
384 }
385 if ((opt_plugin_dir == 0) && ((value= get_value(line, "--plugin_dir"))))
386 {
387 opt_plugin_dir= my_strdup(value, MYF(MY_FAE));
388 }
389 if ((opt_plugin_ini == 0) && ((value= get_value(line, "--plugin_ini"))))
390 {
391 opt_plugin_ini= my_strdup(value, MYF(MY_FAE));
392 }
393 }
394 }
395exit:
396 if (file)
397 {
398 fclose(file);
399 /* Remove file */
400 my_delete(defaults_file, MYF(0));
401 }
402 return error;
403}
404
405
406/**
407 Print usage.
408*/
409
410static void usage(void)
411{
412 PRINT_VERSION;
413 puts("Copyright (c) 2011, 2015, Oracle and/or its affiliates. "
414 "All rights reserved.\n");
415 puts("Enable or disable plugins.");
416 printf("\nUsage: %s [options] <plugin> ENABLE|DISABLE\n\nOptions:\n",
417 my_progname);
418 my_print_help(my_long_options);
419 puts("\n");
420}
421
422
423/**
424 Print the default values as read from the my.cnf file.
425
426 This method displays the default values for the following parameters:
427
428 --datadir
429 --basedir
430 --plugin-dir
431 --plugin-ini
432
433*/
434
435static void print_default_values(void)
436{
437 printf("%s would have been started with the following arguments:\n",
438 my_progname);
439 get_default_values();
440 if (opt_datadir)
441 {
442 printf("--datadir=%s ", opt_datadir);
443 }
444 if (opt_basedir)
445 {
446 printf("--basedir=%s ", opt_basedir);
447 }
448 if (opt_plugin_dir)
449 {
450 printf("--plugin_dir=%s ", opt_plugin_dir);
451 }
452 if (opt_plugin_ini)
453 {
454 printf("--plugin_ini=%s ", opt_plugin_ini);
455 }
456 if (opt_mysqld)
457 {
458 printf("--mysqld=%s ", opt_mysqld);
459 }
460 if (opt_my_print_defaults)
461 {
462 printf("--my_print_defaults=%s ", opt_my_print_defaults);
463 }
464 printf("\n");
465}
466
467
468/**
469 Process the arguments and identify an option and store its value.
470
471 @param[in] optid The single character shortcut for the argument.
472 @param[in] my_option Structure of legal options.
473 @param[in] argument The argument value to process.
474*/
475
476static my_bool
477get_one_option(int optid,
478 const struct my_option *opt __attribute__((unused)),
479 char *argument)
480{
481 switch(optid) {
482 case 'n':
483 opt_no_defaults++;
484 break;
485 case 'P':
486 opt_print_defaults++;
487 print_default_values();
488 break;
489 case 'v':
490 opt_verbose++;
491 break;
492 case 'V':
493 PRINT_VERSION;
494 exit(0);
495 break;
496 case '?':
497 case 'I': /* Info */
498 usage();
499 exit(0);
500 case 'd':
501 opt_datadir= my_strdup(argument, MYF(MY_FAE));
502 break;
503 case 'b':
504 opt_basedir= my_strdup(argument, MYF(MY_FAE));
505 break;
506 case 'p':
507 opt_plugin_dir= my_strdup(argument, MYF(MY_FAE));
508 break;
509 case 'i':
510 opt_plugin_ini= my_strdup(argument, MYF(MY_FAE));
511 break;
512 case 'm':
513 opt_mysqld= my_strdup(argument, MYF(MY_FAE));
514 break;
515 case 'f':
516 opt_my_print_defaults= my_strdup(argument, MYF(MY_FAE));
517 break;
518 }
519 return 0;
520}
521
522
523/**
524 Check to see if a file exists.
525
526 @param[in] filename File to locate.
527
528 @retval int file not found = 1, file found = 0
529*/
530
531static int file_exists(char * filename)
532{
533 MY_STAT stat_arg;
534
535 if (!my_stat(filename, &stat_arg, MYF(0)))
536 {
537 return 0;
538 }
539 return 1;
540}
541
542
543/**
544 Search a specific path and sub directory for a file name.
545
546 @param[in] base_path Original path to use.
547 @param[in] tool_name Name of the tool to locate.
548 @param[in] subdir The sub directory to search.
549 @param[out] tool_path If tool found, return complete path.
550
551 @retval int error = 1, success = 0
552*/
553
554static int search_dir(const char * base_path, const char *tool_name,
555 const char *subdir, char *tool_path)
556{
557 char new_path[FN_REFLEN];
558 char source_path[FN_REFLEN];
559
560 strcpy(source_path, base_path);
561 strcat(source_path, subdir);
562 fn_format(new_path, tool_name, source_path, "", MY_UNPACK_FILENAME);
563 if (file_exists(new_path))
564 {
565 strcpy(tool_path, new_path);
566 return 1;
567 }
568 return 0;
569}
570
571
572/**
573 Search known common paths and sub directories for a file name.
574
575 @param[in] base_path Original path to use.
576 @param[in] tool_name Name of the tool to locate.
577 @param[out] tool_path If tool found, return complete path.
578
579 @retval int error = 1, success = 0
580*/
581
582static int search_paths(const char *base_path, const char *tool_name,
583 char *tool_path)
584{
585 int i= 0;
586
587 static const char *paths[]= {
588 "", "/share/", "/scripts/", "/bin/", "/sbin/", "/libexec/",
589 "/mysql/", "/sql/",
590 };
591 for (i = 0 ; i < (int)array_elements(paths); i++)
592 {
593 if (search_dir(base_path, tool_name, paths[i], tool_path))
594 {
595 return 1;
596 }
597 }
598 return 0;
599}
600
601
602/**
603 Read the plugin ini file.
604
605 This function attempts to read the plugin config file from the plugin_dir
606 path saving the data in the the st_plugin structure. If the file is not
607 found or the file cannot be read, an error is generated.
608
609 @retval int error = 1, success = 0
610*/
611
612static int load_plugin_data(char *plugin_name, char *config_file)
613{
614 FILE *file_ptr;
615 char path[FN_REFLEN];
616 char line[1024];
617 char *reason= 0;
618 char *res;
619 int i= -1;
620
621 if (opt_plugin_ini == 0)
622 {
623 fn_format(path, config_file, opt_plugin_dir, "", MYF(0));
624 opt_plugin_ini= my_strdup(path, MYF(MY_FAE));
625 }
626 if (!file_exists(opt_plugin_ini))
627 {
628 reason= (char *)"File does not exist.";
629 goto error;
630 }
631
632 file_ptr= fopen(opt_plugin_ini, "r");
633 if (file_ptr == NULL)
634 {
635 reason= (char *)"Cannot open file.";
636 goto error;
637 }
638
639 /* save name */
640 plugin_data.name= my_strdup(plugin_name, MYF(MY_WME));
641
642 /* Read plugin components */
643 while (i < 16)
644 {
645 res= fgets(line, sizeof(line), file_ptr);
646 /* strip /n */
647 if (line[strlen(line)-1] == '\n')
648 {
649 line[strlen(line)-1]= '\0';
650 }
651 if (res == NULL)
652 {
653 if (i < 1)
654 {
655 reason= (char *)"Bad format in plugin configuration file.";
656 fclose(file_ptr);
657 goto error;
658 }
659 break;
660 }
661 if ((line[0] == '#') || (line[0] == '\n')) /* skip comment and blank lines */
662 {
663 continue;
664 }
665 if (i == -1) /* if first pass, read this line as so_name */
666 {
667 /* Add proper file extension for soname */
668 strcat(line, FN_SOEXT);
669 /* save so_name */
670 plugin_data.so_name= my_strdup(line, MYF(MY_WME|MY_ZEROFILL));
671 i++;
672 }
673 else
674 {
675 if (strlen(line) > 0)
676 {
677 plugin_data.components[i]= my_strdup(line, MYF(MY_WME));
678 i++;
679 }
680 else
681 {
682 plugin_data.components[i]= NULL;
683 }
684 }
685 }
686
687 fclose(file_ptr);
688 return 0;
689
690error:
691 fprintf(stderr, "ERROR: Cannot read plugin config file %s. %s\n",
692 plugin_name, reason);
693 return 1;
694}
695
696
697/**
698 Check the options for validity.
699
700 This function checks the arguments for validity issuing the appropriate
701 error message if arguments are missing or invalid. On success, @operation
702 is set to either "ENABLE" or "DISABLE".
703
704 @param[in] argc The number of arguments.
705 @param[in] argv The arguments.
706 @param[out] operation The operation chosen (enable|disable)
707
708 @retval int error = 1, success = 0
709*/
710
711static int check_options(int argc, char **argv, char *operation)
712{
713 int i= 0; /* loop counter */
714 int num_found= 0; /* number of options found (shortcut loop) */
715 char config_file[FN_REFLEN]; /* configuration file name */
716 char plugin_name[FN_REFLEN]; /* plugin name */
717
718 /* Form prefix strings for the options. */
719 const char *basedir_prefix = "--basedir=";
720 size_t basedir_len= strlen(basedir_prefix);
721 const char *datadir_prefix = "--datadir=";
722 size_t datadir_len= strlen(datadir_prefix);
723 const char *plugin_dir_prefix = "--plugin_dir=";
724 size_t plugin_dir_len= strlen(plugin_dir_prefix);
725
726 strcpy(plugin_name, "");
727 for (i = 0; i < argc && num_found < 5; i++)
728 {
729
730 if (!argv[i])
731 {
732 continue;
733 }
734 if ((strcasecmp(argv[i], "ENABLE") == 0) ||
735 (strcasecmp(argv[i], "DISABLE") == 0))
736 {
737 strcpy(operation, argv[i]);
738 num_found++;
739 }
740 else if ((strncasecmp(argv[i], basedir_prefix, basedir_len) == 0) &&
741 !opt_basedir)
742 {
743 opt_basedir= my_strndup(argv[i]+basedir_len,
744 strlen(argv[i])-basedir_len, MYF(MY_FAE));
745 num_found++;
746 }
747 else if ((strncasecmp(argv[i], datadir_prefix, datadir_len) == 0) &&
748 !opt_datadir)
749 {
750 opt_datadir= my_strndup(argv[i]+datadir_len,
751 strlen(argv[i])-datadir_len, MYF(MY_FAE));
752 num_found++;
753 }
754 else if ((strncasecmp(argv[i], plugin_dir_prefix, plugin_dir_len) == 0) &&
755 !opt_plugin_dir)
756 {
757 opt_plugin_dir= my_strndup(argv[i]+plugin_dir_len,
758 strlen(argv[i])-plugin_dir_len, MYF(MY_FAE));
759 num_found++;
760 }
761 /* read the plugin config file and check for match against argument */
762 else
763 {
764 if (strlen(argv[i]) + 4 + 1 > FN_REFLEN)
765 {
766 fprintf(stderr, "ERROR: argument is too long.\n");
767 return 1;
768 }
769 strcpy(plugin_name, argv[i]);
770 strcpy(config_file, argv[i]);
771 strcat(config_file, ".ini");
772 }
773 }
774
775 if (!opt_basedir)
776 {
777 fprintf(stderr, "ERROR: Missing --basedir option.\n");
778 return 1;
779 }
780
781 if (!opt_datadir)
782 {
783 fprintf(stderr, "ERROR: Missing --datadir option.\n");
784 return 1;
785 }
786
787 if (!opt_plugin_dir)
788 {
789 fprintf(stderr, "ERROR: Missing --plugin_dir option.\n");
790 return 1;
791 }
792 /* If a plugin was specified, read the config file. */
793 else if (strlen(plugin_name) > 0)
794 {
795 if (load_plugin_data(plugin_name, config_file))
796 {
797 return 1;
798 }
799 if (strcasecmp(plugin_data.name, plugin_name) != 0)
800 {
801 fprintf(stderr, "ERROR: plugin name requested does not match config "
802 "file data.\n");
803 return 1;
804 }
805 }
806 else
807 {
808 fprintf(stderr, "ERROR: No plugin specified.\n");
809 return 1;
810 }
811
812 if ((strlen(operation) == 0))
813 {
814 fprintf(stderr, "ERROR: missing operation. Please specify either "
815 "'<plugin> ENABLE' or '<plugin> DISABLE'.\n");
816 return 1;
817 }
818
819 return 0;
820}
821
822
823/**
824 Parse, execute, and verify command options.
825
826 This method handles all of the option processing including the optional
827 features for displaying data (--print-defaults, --help ,etc.) that do not
828 result in an attempt to ENABLE or DISABLE of a plugin.
829
830 @param[in] arc Count of arguments
831 @param[in] argv Array of arguments
832 @param[out] operation Operation (ENABLE or DISABLE)
833
834 @retval int error = 1, success = 0, exit program = -1
835*/
836
837static int process_options(int argc, char *argv[], char *operation)
838{
839 int error= 0;
840 int i= 0;
841
842 /* Parse and execute command-line options */
843 if ((error= handle_options(&argc, &argv, my_long_options, get_one_option)))
844 goto exit;
845
846 /* If the print defaults option used, exit. */
847 if (opt_print_defaults)
848 {
849 error= -1;
850 goto exit;
851 }
852
853 /* Add a trailing directory separator if not present */
854 if (opt_basedir)
855 {
856 i= (int)strlength(opt_basedir);
857 if (opt_basedir[i-1] != FN_LIBCHAR || opt_basedir[i-1] != FN_LIBCHAR2)
858 {
859 char buff[FN_REFLEN];
860 memset(buff, 0, sizeof(buff));
861
862 strncpy(buff, opt_basedir, sizeof(buff) - 1);
863#ifdef __WIN__
864 strncat(buff, "/", sizeof(buff) - strlen(buff) - 1);
865#else
866 strncat(buff, FN_DIRSEP, sizeof(buff) - strlen(buff) - 1);
867#endif
868 buff[sizeof(buff) - 1]= 0;
869 my_free(opt_basedir);
870 opt_basedir= my_strdup(buff, MYF(MY_FAE));
871 }
872 }
873
874 /*
875 If the user did not specify the option to skip loading defaults from a
876 config file and the required options are not present or there was an error
877 generated when the defaults were read from the file, exit.
878 */
879 if (!opt_no_defaults && ((error= get_default_values())))
880 {
881 error= -1;
882 goto exit;
883 }
884
885 /*
886 Check to ensure required options are present and validate the operation.
887 Note: this method also validates the plugin specified by attempting to
888 read a configuration file named <plugin_name>.ini from the --plugin-dir
889 or --plugin-ini location if the --plugin-ini option presented.
890 */
891 strcpy(operation, "");
892 if ((error = check_options(argc, argv, operation)))
893 {
894 goto exit;
895 }
896
897 if (opt_verbose)
898 {
899 printf("# basedir = %s\n", opt_basedir);
900 printf("# plugin_dir = %s\n", opt_plugin_dir);
901 printf("# datadir = %s\n", opt_datadir);
902 printf("# plugin_ini = %s\n", opt_plugin_ini);
903 }
904
905exit:
906 return error;
907}
908
909
910/**
911 Check access
912
913 This method checks to ensure all of the directories (opt_basedir,
914 opt_plugin_dir, opt_datadir, and opt_plugin_ini) are accessible by
915 the user.
916
917 @retval int error = 1, success = 0
918*/
919
920static int check_access()
921{
922 int error= 0;
923
924 if ((error= my_access(opt_basedir, F_OK)))
925 {
926 fprintf(stderr, "ERROR: Cannot access basedir at '%s'.\n",
927 opt_basedir);
928 goto exit;
929 }
930 if ((error= my_access(opt_plugin_dir, F_OK)))
931 {
932 fprintf(stderr, "ERROR: Cannot access plugin_dir at '%s'.\n",
933 opt_plugin_dir);
934 goto exit;
935 }
936 if ((error= my_access(opt_datadir, F_OK)))
937 {
938 fprintf(stderr, "ERROR: Cannot access datadir at '%s'.\n",
939 opt_datadir);
940 goto exit;
941 }
942 if (opt_plugin_ini && (error= my_access(opt_plugin_ini, F_OK)))
943 {
944 fprintf(stderr, "ERROR: Cannot access plugin config file at '%s'.\n",
945 opt_plugin_ini);
946 goto exit;
947 }
948 if (opt_mysqld && (error= my_access(opt_mysqld, F_OK)))
949 {
950 fprintf(stderr, "ERROR: Cannot access mysqld path '%s'.\n",
951 opt_mysqld);
952 goto exit;
953 }
954 if (opt_my_print_defaults && (error= my_access(opt_my_print_defaults, F_OK)))
955 {
956 fprintf(stderr, "ERROR: Cannot access my-print-defaults path '%s'.\n",
957 opt_my_print_defaults);
958 goto exit;
959 }
960
961exit:
962 return error;
963}
964
965
966/**
967 Locate the tool and form tool path.
968
969 @param[in] tool_name Name of the tool to locate.
970 @param[out] tool_path If tool found, return complete path.
971
972 @retval int error = 1, success = 0
973*/
974
975static int find_tool(const char *tool_name, char *tool_path)
976{
977 int i= 0;
978
979 const char *paths[]= {
980 opt_mysqld, opt_basedir, opt_my_print_defaults, "/usr",
981 "/usr/local/mysql", "/usr/sbin", "/usr/share", "/extra", "/extra/debug",
982 "/extra/release", "/bin", "/usr/bin", "/mysql/bin"
983 };
984 for (i= 0; i < (int)array_elements(paths); i++)
985 {
986 if (paths[i] && (search_paths(paths[i], tool_name, tool_path)))
987 goto found;
988 }
989 fprintf(stderr, "WARNING: Cannot find %s.\n", tool_name);
990 return 1;
991found:
992 if (opt_verbose)
993 printf("# Found tool '%s' as '%s'.\n", tool_name, tool_path);
994 return 0;
995}
996
997
998/**
999 Find the plugin library.
1000
1001 This function attempts to use the @c plugin_dir option passed on the
1002 command line to locate the plugin.
1003
1004 @param[out] tp_path The actual path to plugin with FN_SOEXT applied.
1005
1006 @retval int error = 1, success = 0
1007*/
1008
1009static int find_plugin(char *tp_path)
1010{
1011 /* Check for existence of plugin */
1012 fn_format(tp_path, plugin_data.so_name, opt_plugin_dir, "", MYF(0));
1013 if (!file_exists(tp_path))
1014 {
1015 fprintf(stderr, "ERROR: The plugin library is missing or in a different"
1016 " location.\n");
1017 return 1;
1018 }
1019 else if (opt_verbose)
1020 {
1021 printf("# Found plugin '%s' as '%s'\n", plugin_data.name, tp_path);
1022 }
1023 return 0;
1024}
1025
1026
1027/**
1028 Build the boostrap file.
1029
1030 Create a new file and populate it with SQL commands to ENABLE or DISABLE
1031 the plugin via REPLACE and DELETE operations on the mysql.plugin table.
1032
1033 param[in] operation The type of operation (ENABLE or DISABLE)
1034 param[out] bootstrap A FILE* pointer
1035
1036 @retval int error = 1, success = 0
1037*/
1038
1039static int build_bootstrap_file(char *operation, char *bootstrap)
1040{
1041 int error= 0;
1042 FILE *file= 0;
1043
1044 /*
1045 Perform plugin operation : ENABLE or DISABLE
1046
1047 The following creates a temporary bootstrap file and populates it with
1048 the appropriate SQL commands for the operation. For ENABLE, REPLACE
1049 statements are created. For DISABLE, DELETE statements are created. The
1050 values for these statements are derived from the plugin_data read from the
1051 <plugin_name>.ini configuration file. Once the file is built, a call to
1052 mysqld is made in read only, bootstrap modes to read the SQL statements
1053 and execute them.
1054
1055 Note: Replace was used so that if a user loads a newer version of a
1056 library with a different library name, the new library name is
1057 used for symbols that match.
1058 */
1059 if ((error= make_tempfile(bootstrap, "sql")))
1060 {
1061 /* Fail if we cannot create a temporary file for the bootstrap commands. */
1062 fprintf(stderr, "ERROR: Cannot create bootstrap file.\n");
1063 goto exit;
1064 }
1065 if ((file= fopen(bootstrap, "w+")) == NULL)
1066 {
1067 fprintf(stderr, "ERROR: Cannot open bootstrap file for writing.\n");
1068 error= 1;
1069 goto exit;
1070 }
1071 if (strcasecmp(operation, "enable") == 0)
1072 {
1073 int i= 0;
1074 fprintf(file, "REPLACE INTO mysql.plugin VALUES ");
1075 for (i= 0; i < (int)array_elements(plugin_data.components); i++)
1076 {
1077 /* stop when we read the end of the symbol list - marked with NULL */
1078 if (plugin_data.components[i] == NULL)
1079 {
1080 break;
1081 }
1082 if (i > 0)
1083 {
1084 fprintf(file, ", ");
1085 }
1086 fprintf(file, "('%s','%s')",
1087 plugin_data.components[i], plugin_data.so_name);
1088 }
1089 fprintf(file, ";\n");
1090 if (opt_verbose)
1091 {
1092 printf("# Enabling %s...\n", plugin_data.name);
1093 }
1094 }
1095 else
1096 {
1097 fprintf(file,
1098 "DELETE FROM mysql.plugin WHERE dl = '%s';", plugin_data.so_name);
1099 if (opt_verbose)
1100 {
1101 printf("# Disabling %s...\n", plugin_data.name);
1102 }
1103 }
1104
1105exit:
1106 fclose(file);
1107 return error;
1108}
1109
1110
1111/**
1112 Dump bootstrap file.
1113
1114 Read the contents of the bootstrap file and print it out.
1115
1116 @param[in] bootstrap_file Name of bootstrap file to read
1117
1118 @retval int error = 1, success = 0
1119*/
1120
1121static int dump_bootstrap_file(char *bootstrap_file)
1122{
1123 char *ret= 0;
1124 int error= 0;
1125 char query_str[512];
1126 FILE *file= 0;
1127
1128 if ((file= fopen(bootstrap_file, "r")) == NULL)
1129 {
1130 fprintf(stderr, "ERROR: Cannot open bootstrap file for reading.\n");
1131 error= 1;
1132 goto exit;
1133 }
1134 ret= fgets(query_str, 512, file);
1135 if (ret == 0)
1136 {
1137 fprintf(stderr, "ERROR: Cannot read bootstrap file.\n");
1138 error= 1;
1139 goto exit;
1140 }
1141 printf("# Query: %s\n", query_str);
1142
1143exit:
1144 if (file)
1145 {
1146 fclose(file);
1147 }
1148 return error;
1149}
1150
1151
1152/**
1153 Bootstrap the server
1154
1155 Create a command line sequence to launch mysqld in bootstrap mode. This
1156 will allow mysqld to launch a minimal server instance to read and
1157 execute SQL commands from a file piped in (the boostrap file). We use
1158 the --no-defaults option to skip reading values from the config file.
1159
1160 The bootstrap mode skips loading of plugins and many other subsystems.
1161 This allows the mysql_plugin tool to insert the correct rows into the
1162 mysql.plugin table (for ENABLE) or delete the rows (for DISABLE). Once
1163 the server is launched in normal mode, the plugin will be loaded
1164 (for ENABLE) or not loaded (for DISABLE). In this way, we avoid the
1165 (sometimes) complicated LOAD PLUGIN commands.
1166
1167 @param[in] server_path Path to server executable
1168 @param[in] bootstrap_file Name of bootstrap file to read
1169
1170 @retval int error = 1, success = 0
1171*/
1172
1173static int bootstrap_server(char *server_path, char *bootstrap_file)
1174{
1175 char bootstrap_cmd[FN_REFLEN];
1176 int error= 0;
1177
1178#ifdef __WIN__
1179 char *format_str= 0;
1180 const char *verbose_str= NULL;
1181
1182
1183 if (opt_verbose)
1184 verbose_str= "--console";
1185 else
1186 verbose_str= "";
1187 if (has_spaces(opt_datadir) || has_spaces(opt_basedir) ||
1188 has_spaces(bootstrap_file))
1189 format_str= "\"%s %s --bootstrap --datadir=%s --basedir=%s < %s\"";
1190 else
1191 format_str= "%s %s --bootstrap --datadir=%s --basedir=%s < %s";
1192
1193 snprintf(bootstrap_cmd, sizeof(bootstrap_cmd), format_str,
1194 add_quotes(convert_path(server_path)), verbose_str,
1195 add_quotes(opt_datadir), add_quotes(opt_basedir),
1196 add_quotes(bootstrap_file));
1197#else
1198 snprintf(bootstrap_cmd, sizeof(bootstrap_cmd),
1199 "%s --no-defaults --bootstrap --datadir=%s --basedir=%s"
1200 " < %s", server_path, opt_datadir, opt_basedir, bootstrap_file);
1201#endif
1202
1203 /* Execute the command */
1204 if (opt_verbose)
1205 {
1206 printf("# Command: %s\n", bootstrap_cmd);
1207 }
1208 error= run_command(bootstrap_cmd, "r");
1209 if (error)
1210 fprintf(stderr,
1211 "ERROR: Unexpected result from bootstrap. Error code: %d.\n",
1212 error);
1213
1214 return error;
1215}
1216