MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mysql_plugin.c
1 /*
2  Copyright (c) 2011, 2012, 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 <m_string.h>
19 #include <mysql.h>
20 #include <my_getopt.h>
21 #include <my_dir.h>
22 #include <my_global.h>
23 #include <stdio.h>
24 #include <string.h>
25 
26 
27 #define SHOW_VERSION "1.0.0"
28 #define PRINT_VERSION do { printf("%s Ver %s Distrib %s\n", \
29  my_progname, SHOW_VERSION, MYSQL_SERVER_VERSION); \
30  } while(0)
31 
32 /* Global variables. */
33 static uint my_end_arg= 0;
34 static uint opt_verbose=0;
35 static uint opt_no_defaults= 0;
36 static uint opt_print_defaults= 0;
37 static char *opt_datadir=0, *opt_basedir=0,
38  *opt_plugin_dir=0, *opt_plugin_ini=0,
39  *opt_mysqld=0, *opt_my_print_defaults=0;
40 static char bootstrap[FN_REFLEN];
41 
42 
43 /* plugin struct */
44 struct st_plugin
45 {
46  const char *name; /* plugin name */
47  const char *so_name; /* plugin so (library) name */
48  const char *components[16]; /* components to load */
49 } plugin_data;
50 
51 
52 /* Options */
53 static struct my_option my_long_options[] =
54 {
55  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
56  0, 0, 0, 0, 0, 0},
57  {"basedir", 'b', "The basedir for the server.",
58  0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
59  {"datadir", 'd', "The datadir for the server.",
60  0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
61  {"plugin-dir", 'p', "The plugin dir for the server.",
62  0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
63  {"plugin-ini", 'i', "Read plugin information from configuration file "
64  "specified instead of from <plugin-dir>/<plugin_name>.ini.",
65  0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
66  {"no-defaults", 'n', "Do not read values from configuration file.",
67  0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
68  {"print-defaults", 'P', "Show default values from configuration file.",
69  0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
70  {"mysqld", 'm', "Path to mysqld executable. Example: /sbin/temp1/mysql/bin",
71  0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
72  {"my-print-defaults", 'f', "Path to my_print_defaults executable. "
73  "Example: /source/temp11/extra",
74  0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
75  {"verbose", 'v',
76  "More verbose output; you can use this multiple times to get even more "
77  "verbose output.",
78  0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
79  {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
80  NO_ARG, 0, 0, 0, 0, 0, 0},
81  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
82 };
83 
84 
85 /* Methods */
86 static int process_options(int argc, char *argv[], char *operation);
87 static int check_access();
88 static int find_tool(const char *tool_name, char *tool_path);
89 static int find_plugin(char *tp_path);
90 static int build_bootstrap_file(char *operation, char *bootstrap);
91 static int dump_bootstrap_file(char *bootstrap_file);
92 static int bootstrap_server(char *server_path, char *bootstrap_file);
93 
94 
95 int main(int argc,char *argv[])
96 {
97  int error= 0;
98  char tp_path[FN_REFLEN];
99  char server_path[FN_REFLEN];
100  char operation[16];
101 
102  MY_INIT(argv[0]);
103  plugin_data.name= 0; // initialize name
104 
105  /*
106  The following operations comprise the method for enabling or disabling
107  a plugin. We begin by processing the command options then check the
108  directories specified for --datadir, --basedir, --plugin-dir, and
109  --plugin-ini (if specified). If the directories are Ok, we then look
110  for the mysqld executable and the plugin soname. Finally, we build a
111  bootstrap command file for use in bootstraping the server.
112 
113  If any step fails, the method issues an error message and the tool exits.
114 
115  1) Parse, execute, and verify command options.
116  2) Check access to directories.
117  3) Look for mysqld executable.
118  4) Look for the plugin.
119  5) Build a bootstrap file with commands to enable or disable plugin.
120 
121  */
122  if ((error= process_options(argc, argv, operation)) ||
123  (error= check_access()) ||
124  (error= find_tool("mysqld" FN_EXEEXT, server_path)) ||
125  (error= find_plugin(tp_path)) ||
126  (error= build_bootstrap_file(operation, bootstrap)))
127  goto exit;
128 
129  /* Dump the bootstrap file if --verbose specified. */
130  if (opt_verbose && ((error= dump_bootstrap_file(bootstrap))))
131  goto exit;
132 
133  /* Start the server in bootstrap mode and execute bootstrap commands */
134  error= bootstrap_server(server_path, bootstrap);
135 
136 exit:
137  /* Remove file */
138  my_delete(bootstrap, MYF(0));
139  if (opt_verbose && error == 0)
140  {
141  printf("# Operation succeeded.\n");
142  }
143 
144  my_end(my_end_arg);
145  exit(error ? 1 : 0);
146  return 0; /* No compiler warnings */
147 }
148 
149 
159 static int make_tempfile(char *filename, const char *ext)
160 {
161  int fd= 0;
162 
163  if ((fd=create_temp_file(filename, NullS, ext, O_CREAT | O_WRONLY,
164  MYF(MY_WME))) < 0)
165  {
166  fprintf(stderr, "ERROR: Cannot generate temporary file. Error code: %d.\n",
167  fd);
168  return 1;
169  }
170  my_close(fd, MYF(0));
171  return 0;
172 }
173 
174 
184 static char *get_value(char *line, const char *item)
185 {
186  char *destination= 0;
187  int item_len= (int)strlen(item);
188  int line_len = (int)strlen(line);
189 
190  if ((strncasecmp(line, item, item_len) == 0))
191  {
192  int start= 0;
193  char *s= 0;
194 
195  s = line + item_len + 1;
196  destination= my_strndup(s, line_len - start, MYF(MY_FAE));
197  destination[line_len - item_len - 2]= 0;
198  }
199  return destination;
200 }
201 
202 
217 static int run_command(char* cmd, const char *mode)
218 {
219  char buf[512]= {0};
220  FILE *res_file;
221  int error;
222 
223  if (!(res_file= popen(cmd, mode)))
224  return -1;
225 
226  if (opt_verbose)
227  {
228  while (fgets(buf, sizeof(buf), res_file))
229  {
230  fprintf(stdout, "%s", buf);
231  }
232  }
233  error= pclose(res_file);
234  return error;
235 }
236 
237 
238 #ifdef __WIN__
239 
246 static int has_spaces(const char *path)
247 {
248  if (strchr(path, ' ') != NULL)
249  return 1;
250  return 0;
251 }
252 
253 
261 static char *convert_path(const char *argument)
262 {
263  /* Convert / to \\ to make Windows paths */
264  char *winfilename= my_strdup(argument, MYF(MY_FAE));
265  char *pos, *end;
266  int length= strlen(argument);
267 
268  for (pos= winfilename, end= pos+length ; pos < end ; pos++)
269  {
270  if (*pos == '/')
271  {
272  *pos= '\\';
273  }
274  }
275  return winfilename;
276 }
277 
278 
286 static char *add_quotes(const char *path)
287 {
288  char windows_cmd_friendly[FN_REFLEN];
289 
290  if (has_spaces(path))
291  snprintf(windows_cmd_friendly, sizeof(windows_cmd_friendly),
292  "\"%s\"", path);
293  else
294  snprintf(windows_cmd_friendly, sizeof(windows_cmd_friendly),
295  "%s", path);
296  return my_strdup(windows_cmd_friendly, MYF(MY_FAE));
297 }
298 #endif
299 
300 
316 static int get_default_values()
317 {
318  char tool_path[FN_REFLEN];
319  char defaults_cmd[FN_REFLEN];
320  char defaults_file[FN_REFLEN];
321  char line[FN_REFLEN];
322  int error= 0;
323  int ret= 0;
324  FILE *file= 0;
325 
326  memset(tool_path, 0, FN_REFLEN);
327  if ((error= find_tool("my_print_defaults" FN_EXEEXT, tool_path)))
328  goto exit;
329  else
330  {
331  if ((error= make_tempfile(defaults_file, "txt")))
332  goto exit;
333 
334 #ifdef __WIN__
335  {
336  char *format_str= 0;
337 
338  if (has_spaces(tool_path) || has_spaces(defaults_file))
339  format_str = "\"%s mysqld > %s\"";
340  else
341  format_str = "%s mysqld > %s";
342 
343  snprintf(defaults_cmd, sizeof(defaults_cmd), format_str,
344  add_quotes(tool_path), add_quotes(defaults_file));
345  if (opt_verbose)
346  {
347  printf("# my_print_defaults found: %s\n", tool_path);
348  }
349  }
350 #else
351  snprintf(defaults_cmd, sizeof(defaults_cmd),
352  "%s mysqld > %s", tool_path, defaults_file);
353 #endif
354 
355  /* Execute the command */
356  if (opt_verbose)
357  {
358  printf("# Command: %s\n", defaults_cmd);
359  }
360  error= run_command(defaults_cmd, "r");
361  if (error)
362  {
363  fprintf(stderr, "ERROR: my_print_defaults failed. Error code: %d.\n",
364  ret);
365  goto exit;
366  }
367  /* Now open the file and read the defaults we want. */
368  file= fopen(defaults_file, "r");
369  while (fgets(line, FN_REFLEN, file) != NULL)
370  {
371  char *value= 0;
372 
373  if ((opt_datadir == 0) && ((value= get_value(line, "--datadir"))))
374  {
375  opt_datadir= my_strdup(value, MYF(MY_FAE));
376  }
377  if ((opt_basedir == 0) && ((value= get_value(line, "--basedir"))))
378  {
379  opt_basedir= my_strdup(value, MYF(MY_FAE));
380  }
381  if ((opt_plugin_dir == 0) && ((value= get_value(line, "--plugin_dir"))))
382  {
383  opt_plugin_dir= my_strdup(value, MYF(MY_FAE));
384  }
385  if ((opt_plugin_ini == 0) && ((value= get_value(line, "--plugin_ini"))))
386  {
387  opt_plugin_ini= my_strdup(value, MYF(MY_FAE));
388  }
389  }
390  }
391 exit:
392  if (file)
393  {
394  fclose(file);
395  /* Remove file */
396  my_delete(defaults_file, MYF(0));
397  }
398  return error;
399 }
400 
401 
406 static void usage(void)
407 {
408  PRINT_VERSION;
409  puts("Copyright (c) 2011, Oracle and/or its affiliates. "
410  "All rights reserved.\n");
411  puts("Enable or disable plugins.");
412  printf("\nUsage: %s [options] <plugin> ENABLE|DISABLE\n\nOptions:\n",
413  my_progname);
414  my_print_help(my_long_options);
415  puts("\n");
416 }
417 
418 
431 static void print_default_values(void)
432 {
433  printf("%s would have been started with the following arguments:\n",
434  my_progname);
435  get_default_values();
436  if (opt_datadir)
437  {
438  printf("--datadir=%s ", opt_datadir);
439  }
440  if (opt_basedir)
441  {
442  printf("--basedir=%s ", opt_basedir);
443  }
444  if (opt_plugin_dir)
445  {
446  printf("--plugin_dir=%s ", opt_plugin_dir);
447  }
448  if (opt_plugin_ini)
449  {
450  printf("--plugin_ini=%s ", opt_plugin_ini);
451  }
452  if (opt_mysqld)
453  {
454  printf("--mysqld=%s ", opt_mysqld);
455  }
456  if (opt_my_print_defaults)
457  {
458  printf("--my_print_defaults=%s ", opt_my_print_defaults);
459  }
460  printf("\n");
461 }
462 
463 
472 static my_bool
473 get_one_option(int optid,
474  const struct my_option *opt __attribute__((unused)),
475  char *argument)
476 {
477  switch(optid) {
478  case 'n':
479  opt_no_defaults++;
480  break;
481  case 'P':
482  opt_print_defaults++;
483  print_default_values();
484  break;
485  case 'v':
486  opt_verbose++;
487  break;
488  case 'V':
489  PRINT_VERSION;
490  exit(0);
491  break;
492  case '?':
493  case 'I': /* Info */
494  usage();
495  exit(0);
496  case 'd':
497  opt_datadir= my_strdup(argument, MYF(MY_FAE));
498  break;
499  case 'b':
500  opt_basedir= my_strdup(argument, MYF(MY_FAE));
501  break;
502  case 'p':
503  opt_plugin_dir= my_strdup(argument, MYF(MY_FAE));
504  break;
505  case 'i':
506  opt_plugin_ini= my_strdup(argument, MYF(MY_FAE));
507  break;
508  case 'm':
509  opt_mysqld= my_strdup(argument, MYF(MY_FAE));
510  break;
511  case 'f':
512  opt_my_print_defaults= my_strdup(argument, MYF(MY_FAE));
513  break;
514  }
515  return 0;
516 }
517 
518 
527 static int file_exists(char * filename)
528 {
529  MY_STAT stat_arg;
530 
531  if (!my_stat(filename, &stat_arg, MYF(0)))
532  {
533  return 0;
534  }
535  return 1;
536 }
537 
538 
550 static int search_dir(const char * base_path, const char *tool_name,
551  const char *subdir, char *tool_path)
552 {
553  char new_path[FN_REFLEN];
554  char source_path[FN_REFLEN];
555 #if __WIN__
556  char win_abs_path[FN_REFLEN];
557  char self_name[FN_REFLEN];
558  const char *last_fn_libchar;
559 #endif
560 
561  if ((strlen(base_path) + strlen(subdir) + 1) > FN_REFLEN)
562  {
563  fprintf(stderr, "WARNING: Search path is too long\n");
564  return 1;
565  }
566  strcpy(source_path, base_path);
567  strcat(source_path, subdir);
568  fn_format(new_path, tool_name, source_path, "", MY_UNPACK_FILENAME);
569  if (file_exists(new_path))
570  {
571  strcpy(tool_path, new_path);
572  return 0;
573  }
574 
575 #if __WIN__
576  /*
577  On Windows above code will not be able to find the file since
578  path names are not absolute and file_exists works only with
579  absolute path names. Try to get the absolute path of current
580  exe and see if the file exists relative to the path of exe.
581  */
582  if (GetModuleFileName(NULL, self_name, FN_REFLEN -1) == 0)
583  strncpy(self_name, my_progname, FN_REFLEN - 1);
584  self_name[FN_REFLEN - 1]= '\0';
585 
586  last_fn_libchar= strrchr(self_name, FN_LIBCHAR);
587  if (NULL != last_fn_libchar)
588  {
589  strncpy(win_abs_path, self_name, last_fn_libchar - self_name + 1 );
590  win_abs_path[(last_fn_libchar - self_name + 1)]= 0;
591  strncat(win_abs_path, new_path,
592  sizeof(win_abs_path) - strlen(win_abs_path) - 1);
593  if (file_exists(win_abs_path))
594  {
595  strcpy(tool_path, win_abs_path);
596  return 0;
597  }
598  }
599 #endif
600  return 1;
601 }
602 
603 
614 static int search_paths(const char *base_path, const char *tool_name,
615  char *tool_path)
616 {
617  int i= 0;
618 
619  static const char *paths[]= {
620  "", "/share/", "/scripts/", "/bin/", "/sbin/", "/libexec/",
621  "/mysql/", "/sql/",
622  };
623  for (i = 0 ; i < (int)array_elements(paths); i++)
624  {
625  if (!search_dir(base_path, tool_name, paths[i], tool_path))
626  {
627  return 0;
628  }
629  }
630  return 1;
631 }
632 
633 
644 static int load_plugin_data(char *plugin_name, char *config_file)
645 {
646  FILE *file_ptr;
647  char path[FN_REFLEN];
648  char line[1024];
649  char *reason= 0;
650  char *res;
651  int i= -1;
652 
653  if (opt_plugin_ini == 0)
654  {
655  fn_format(path, config_file, opt_plugin_dir, "", MYF(0));
656  opt_plugin_ini= my_strdup(path, MYF(MY_FAE));
657  }
658  if (!file_exists(opt_plugin_ini))
659  {
660  reason= (char *)"File does not exist.";
661  goto error;
662  }
663 
664  file_ptr= fopen(opt_plugin_ini, "r");
665  if (file_ptr == NULL)
666  {
667  reason= (char *)"Cannot open file.";
668  goto error;
669  }
670 
671  /* save name */
672  plugin_data.name= my_strdup(plugin_name, MYF(MY_WME));
673 
674  /* Read plugin components */
675  while (i < 16)
676  {
677  res= fgets(line, sizeof(line), file_ptr);
678  /* strip /n */
679  if (line[strlen(line)-1] == '\n')
680  {
681  line[strlen(line)-1]= '\0';
682  }
683  if (res == NULL)
684  {
685  if (i < 1)
686  {
687  reason= (char *)"Bad format in plugin configuration file.";
688  fclose(file_ptr);
689  goto error;
690  }
691  break;
692  }
693  if ((line[0] == '#') || (line[0] == '\n')) // skip comment and blank lines
694  {
695  continue;
696  }
697  if (i == -1) // if first pass, read this line as so_name
698  {
699  /* Add proper file extension for soname */
700  strcat(line, FN_SOEXT);
701  /* save so_name */
702  plugin_data.so_name= my_strdup(line, MYF(MY_WME|MY_ZEROFILL));
703  i++;
704  }
705  else
706  {
707  if (strlen(line) > 0)
708  {
709  plugin_data.components[i]= my_strdup(line, MYF(MY_WME));
710  i++;
711  }
712  else
713  {
714  plugin_data.components[i]= NULL;
715  }
716  }
717  }
718 
719  fclose(file_ptr);
720  return 0;
721 
722 error:
723  fprintf(stderr, "ERROR: Cannot read plugin config file %s. %s\n",
724  plugin_name, reason);
725  return 1;
726 }
727 
728 
743 static int check_options(int argc, char **argv, char *operation)
744 {
745  int i= 0; // loop counter
746  int num_found= 0; // number of options found (shortcut loop)
747  char config_file[FN_REFLEN]; // configuration file name
748  char plugin_name[FN_REFLEN]; // plugin name
749 
750  /* Form prefix strings for the options. */
751  const char *basedir_prefix = "--basedir=";
752  int basedir_len= strlen(basedir_prefix);
753  const char *datadir_prefix = "--datadir=";
754  int datadir_len= strlen(datadir_prefix);
755  const char *plugin_dir_prefix = "--plugin_dir=";
756  int plugin_dir_len= strlen(plugin_dir_prefix);
757 
758  strcpy(plugin_name, "");
759  for (i = 0; i < argc && num_found < 5; i++)
760  {
761 
762  if (!argv[i])
763  {
764  continue;
765  }
766  if ((strcasecmp(argv[i], "ENABLE") == 0) ||
767  (strcasecmp(argv[i], "DISABLE") == 0))
768  {
769  strcpy(operation, argv[i]);
770  num_found++;
771  }
772  else if ((strncasecmp(argv[i], basedir_prefix, basedir_len) == 0) &&
773  !opt_basedir)
774  {
775  opt_basedir= my_strndup(argv[i]+basedir_len,
776  strlen(argv[i])-basedir_len, MYF(MY_FAE));
777  num_found++;
778  }
779  else if ((strncasecmp(argv[i], datadir_prefix, datadir_len) == 0) &&
780  !opt_datadir)
781  {
782  opt_datadir= my_strndup(argv[i]+datadir_len,
783  strlen(argv[i])-datadir_len, MYF(MY_FAE));
784  num_found++;
785  }
786  else if ((strncasecmp(argv[i], plugin_dir_prefix, plugin_dir_len) == 0) &&
787  !opt_plugin_dir)
788  {
789  opt_plugin_dir= my_strndup(argv[i]+plugin_dir_len,
790  strlen(argv[i])-plugin_dir_len, MYF(MY_FAE));
791  num_found++;
792  }
793  /* read the plugin config file and check for match against argument */
794  else
795  {
796  strcpy(plugin_name, argv[i]);
797  strcpy(config_file, argv[i]);
798  strcat(config_file, ".ini");
799  }
800  }
801 
802  if (!opt_basedir)
803  {
804  fprintf(stderr, "ERROR: Missing --basedir option.\n");
805  return 1;
806  }
807 
808  if (!opt_datadir)
809  {
810  fprintf(stderr, "ERROR: Missing --datadir option.\n");
811  return 1;
812  }
813 
814  if (!opt_plugin_dir)
815  {
816  fprintf(stderr, "ERROR: Missing --plugin_dir option.\n");
817  return 1;
818  }
819  /* If a plugin was specified, read the config file. */
820  else if (strlen(plugin_name) > 0)
821  {
822  if (load_plugin_data(plugin_name, config_file))
823  {
824  return 1;
825  }
826  if (strcasecmp(plugin_data.name, plugin_name) != 0)
827  {
828  fprintf(stderr, "ERROR: plugin name requested does not match config "
829  "file data.\n");
830  return 1;
831  }
832  }
833  else
834  {
835  fprintf(stderr, "ERROR: No plugin specified.\n");
836  return 1;
837  }
838 
839  if ((strlen(operation) == 0))
840  {
841  fprintf(stderr, "ERROR: missing operation. Please specify either "
842  "'<plugin> ENABLE' or '<plugin> DISABLE'.\n");
843  return 1;
844  }
845 
846  return 0;
847 }
848 
849 
864 static int process_options(int argc, char *argv[], char *operation)
865 {
866  int error= 0;
867  int i= 0;
868 
869  /* Parse and execute command-line options */
870  if ((error= handle_options(&argc, &argv, my_long_options, get_one_option)))
871  goto exit;
872 
873  /* If the print defaults option used, exit. */
874  if (opt_print_defaults)
875  {
876  error= -1;
877  goto exit;
878  }
879 
880  /* Add a trailing directory separator if not present */
881  if (opt_basedir)
882  {
883  i= (int)strlength(opt_basedir);
884  if (opt_basedir[i-1] != FN_LIBCHAR || opt_basedir[i-1] != FN_LIBCHAR2)
885  {
886  char buff[FN_REFLEN];
887 
888  strncpy(buff, opt_basedir, sizeof(buff) - 1);
889 #ifdef __WIN__
890  strncat(buff, "/", sizeof(buff) - strlen(buff) - 1);
891 #else
892  strncat(buff, FN_DIRSEP, sizeof(buff) - strlen(buff) - 1);
893 #endif
894  buff[sizeof(buff) - 1]= 0;
895  my_delete(opt_basedir, MYF(0));
896  opt_basedir= my_strdup(buff, MYF(MY_FAE));
897  }
898  }
899 
900  /*
901  If the user did not specify the option to skip loading defaults from a
902  config file and the required options are not present or there was an error
903  generated when the defaults were read from the file, exit.
904  */
905  if (!opt_no_defaults && ((error= get_default_values())))
906  {
907  error= -1;
908  goto exit;
909  }
910 
911  /*
912  Check to ensure required options are present and validate the operation.
913  Note: this method also validates the plugin specified by attempting to
914  read a configuration file named <plugin_name>.ini from the --plugin-dir
915  or --plugin-ini location if the --plugin-ini option presented.
916  */
917  strcpy(operation, "");
918  if ((error = check_options(argc, argv, operation)))
919  {
920  goto exit;
921  }
922 
923  if (opt_verbose)
924  {
925  printf("# basedir = %s\n", opt_basedir);
926  printf("# plugin_dir = %s\n", opt_plugin_dir);
927  printf("# datadir = %s\n", opt_datadir);
928  printf("# plugin_ini = %s\n", opt_plugin_ini);
929  }
930 
931 exit:
932  return error;
933 }
934 
935 
946 static int check_access()
947 {
948  int error= 0;
949 
950  if ((error= my_access(opt_basedir, F_OK)))
951  {
952  fprintf(stderr, "ERROR: Cannot access basedir at '%s'.\n",
953  opt_basedir);
954  goto exit;
955  }
956  if ((error= my_access(opt_plugin_dir, F_OK)))
957  {
958  fprintf(stderr, "ERROR: Cannot access plugin_dir at '%s'.\n",
959  opt_plugin_dir);
960  goto exit;
961  }
962  if ((error= my_access(opt_datadir, F_OK)))
963  {
964  fprintf(stderr, "ERROR: Cannot access datadir at '%s'.\n",
965  opt_datadir);
966  goto exit;
967  }
968  if (opt_plugin_ini && (error= my_access(opt_plugin_ini, F_OK)))
969  {
970  fprintf(stderr, "ERROR: Cannot access plugin config file at '%s'.\n",
971  opt_plugin_ini);
972  goto exit;
973  }
974  if (opt_mysqld && (error= my_access(opt_mysqld, F_OK)))
975  {
976  fprintf(stderr, "ERROR: Cannot access mysqld path '%s'.\n",
977  opt_mysqld);
978  goto exit;
979  }
980  if (opt_my_print_defaults && (error= my_access(opt_my_print_defaults, F_OK)))
981  {
982  fprintf(stderr, "ERROR: Cannot access my-print-defaults path '%s'.\n",
983  opt_my_print_defaults);
984  goto exit;
985  }
986 
987 exit:
988  return error;
989 }
990 
991 
1001 static int find_tool(const char *tool_name, char *tool_path)
1002 {
1003  int i= 0;
1004 
1005  const char *paths[]= {
1006  opt_mysqld, opt_basedir, opt_my_print_defaults, "",
1007  "/usr", "/usr/local/mysql", "/usr/sbin", "/usr/share",
1008  "/extra", "/extra/debug", "/../../extra/debug",
1009  "/release/", "/extra/release", "/../../extra/release",
1010  "/bin", "/usr/bin", "/mysql/bin"
1011  };
1012  for (i= 0; i < (int)array_elements(paths); i++)
1013  {
1014  if (paths[i] && !(search_paths(paths[i], tool_name, tool_path)))
1015  goto found;
1016  }
1017  fprintf(stderr, "WARNING: Cannot find %s.\n", tool_name);
1018  return 1;
1019 found:
1020  if (opt_verbose)
1021  printf("# Found tool '%s' as '%s'.\n", tool_name, tool_path);
1022  return 0;
1023 }
1024 
1025 
1037 static int find_plugin(char *tp_path)
1038 {
1039  /* Check for existance of plugin */
1040  fn_format(tp_path, plugin_data.so_name, opt_plugin_dir, "", MYF(0));
1041  if (!file_exists(tp_path))
1042  {
1043  fprintf(stderr, "ERROR: The plugin library is missing or in a different"
1044  " location.\n");
1045  return 1;
1046  }
1047  else if (opt_verbose)
1048  {
1049  printf("# Found plugin '%s' as '%s'\n", plugin_data.name, tp_path);
1050  }
1051  return 0;
1052 }
1053 
1054 
1067 static int build_bootstrap_file(char *operation, char *bootstrap)
1068 {
1069  int error= 0;
1070  FILE *file= 0;
1071 
1072  /*
1073  Perform plugin operation : ENABLE or DISABLE
1074 
1075  The following creates a temporary bootstrap file and populates it with
1076  the appropriate SQL commands for the operation. For ENABLE, REPLACE
1077  statements are created. For DISABLE, DELETE statements are created. The
1078  values for these statements are derived from the plugin_data read from the
1079  <plugin_name>.ini configuration file. Once the file is built, a call to
1080  mysqld is made in read only, bootstrap modes to read the SQL statements
1081  and execute them.
1082 
1083  Note: Replace was used so that if a user loads a newer version of a
1084  library with a different library name, the new library name is
1085  used for symbols that match.
1086  */
1087  if ((error= make_tempfile(bootstrap, "sql")))
1088  {
1089  /* Fail if we cannot create a temporary file for the bootstrap commands. */
1090  fprintf(stderr, "ERROR: Cannot create bootstrap file.\n");
1091  goto exit;
1092  }
1093  if ((file= fopen(bootstrap, "w+")) == NULL)
1094  {
1095  fprintf(stderr, "ERROR: Cannot open bootstrap file for writing.\n");
1096  error= 1;
1097  goto exit;
1098  }
1099  if (strcasecmp(operation, "enable") == 0)
1100  {
1101  int i= 0;
1102  fprintf(file, "REPLACE INTO mysql.plugin VALUES ");
1103  for (i= 0; i < (int)array_elements(plugin_data.components); i++)
1104  {
1105  /* stop when we read the end of the symbol list - marked with NULL */
1106  if (plugin_data.components[i] == NULL)
1107  {
1108  break;
1109  }
1110  if (i > 0)
1111  {
1112  fprintf(file, ", ");
1113  }
1114  fprintf(file, "('%s','%s')",
1115  plugin_data.components[i], plugin_data.so_name);
1116  }
1117  fprintf(file, ";\n");
1118  if (opt_verbose)
1119  {
1120  printf("# Enabling %s...\n", plugin_data.name);
1121  }
1122  }
1123  else
1124  {
1125  fprintf(file,
1126  "DELETE FROM mysql.plugin WHERE dl = '%s';", plugin_data.so_name);
1127  if (opt_verbose)
1128  {
1129  printf("# Disabling %s...\n", plugin_data.name);
1130  }
1131  }
1132 
1133 exit:
1134  fclose(file);
1135  return error;
1136 }
1137 
1138 
1149 static int dump_bootstrap_file(char *bootstrap_file)
1150 {
1151  char *ret= 0;
1152  int error= 0;
1153  char query_str[512];
1154  FILE *file= 0;
1155 
1156  if ((file= fopen(bootstrap_file, "r")) == NULL)
1157  {
1158  fprintf(stderr, "ERROR: Cannot open bootstrap file for reading.\n");
1159  error= 1;
1160  goto exit;
1161  }
1162  ret= fgets(query_str, 512, file);
1163  if (ret == 0)
1164  {
1165  fprintf(stderr, "ERROR: Cannot read bootstrap file.\n");
1166  error= 1;
1167  goto exit;
1168  }
1169  printf("# Query: %s\n", query_str);
1170 
1171 exit:
1172  if (file)
1173  {
1174  fclose(file);
1175  }
1176  return error;
1177 }
1178 
1179 
1201 static int bootstrap_server(char *server_path, char *bootstrap_file)
1202 {
1203  char bootstrap_cmd[FN_REFLEN];
1204  int error= 0;
1205 
1206 #ifdef __WIN__
1207  char *format_str= 0;
1208  const char *verbose_str= NULL;
1209 
1210 
1211  if (opt_verbose)
1212  verbose_str= "--console";
1213  else
1214  verbose_str= "";
1215  if (has_spaces(opt_datadir) || has_spaces(opt_basedir) ||
1216  has_spaces(bootstrap_file))
1217  format_str= "\"%s %s --bootstrap --datadir=%s --basedir=%s < %s\"";
1218  else
1219  format_str= "%s %s --bootstrap --datadir=%s --basedir=%s < %s";
1220 
1221  snprintf(bootstrap_cmd, sizeof(bootstrap_cmd), format_str,
1222  add_quotes(convert_path(server_path)), verbose_str,
1223  add_quotes(opt_datadir), add_quotes(opt_basedir),
1224  add_quotes(bootstrap_file));
1225 #else
1226  snprintf(bootstrap_cmd, sizeof(bootstrap_cmd),
1227  "%s --no-defaults --bootstrap --datadir=%s --basedir=%s"
1228  " < %s", server_path, opt_datadir, opt_basedir, bootstrap_file);
1229 #endif
1230 
1231  /* Execute the command */
1232  if (opt_verbose)
1233  {
1234  printf("# Command: %s\n", bootstrap_cmd);
1235  }
1236  error= run_command(bootstrap_cmd, "r");
1237  if (error)
1238  fprintf(stderr,
1239  "ERROR: Unexpected result from bootstrap. Error code: %d.\n",
1240  error);
1241 
1242  return error;
1243 }