1 /* Copyright (C) 2010-2011 Monty Program Ab & Vladislav Vaintroub
2
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; version 2 of the License.
6
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
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
15
16 /*
17 mysql_install_db creates a new database instance (optionally as service)
18 on Windows.
19 */
20 #define DONT_DEFINE_VOID
21 #include "mariadb.h"
22 #include <my_getopt.h>
23 #include <m_string.h>
24
25 #include <windows.h>
26 #include <shellapi.h>
27 #include <accctrl.h>
28 #include <aclapi.h>
29 struct IUnknown;
30 #include <shlwapi.h>
31
32 #define USAGETEXT \
33 "mysql_install_db.exe Ver 1.00 for Windows\n" \
34 "Copyright (C) 2010-2011 Monty Program Ab & Vladislav Vaintroub\n" \
35 "This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n" \
36 "and you are welcome to modify and redistribute it under the GPL v2 license\n" \
37 "Usage: mysql_install_db.exe [OPTIONS]\n" \
38 "OPTIONS:"
39
40 extern "C" const char* mysql_bootstrap_sql[];
41
42 static char default_os_user[]= "NT AUTHORITY\\NetworkService";
43 static char default_datadir[MAX_PATH];
44 static int create_db_instance();
45 static uint opt_silent;
46 static char datadir_buffer[FN_REFLEN];
47 static char mysqld_path[FN_REFLEN];
48 static char *opt_datadir;
49 static char *opt_service;
50 static char *opt_password;
51 static int opt_port;
52 static int opt_innodb_page_size;
53 static char *opt_socket;
54 static char *opt_os_user;
55 static char *opt_os_password;
56 static my_bool opt_default_user;
57 static my_bool opt_allow_remote_root_access;
58 static my_bool opt_skip_networking;
59 static my_bool opt_verbose_bootstrap;
60 static my_bool verbose_errors;
61
62 #define DEFAULT_INNODB_PAGE_SIZE 16*1024
63
64 static struct my_option my_long_options[]=
65 {
66 {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
67 NO_ARG, 0, 0, 0, 0, 0, 0},
68 {"datadir", 'd', "Data directory of the new database",
69 &opt_datadir, &opt_datadir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
70 {"service", 'S', "Name of the Windows service",
71 &opt_service, &opt_service, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
72 {"password", 'p', "Root password",
73 &opt_password, &opt_password, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
74 {"port", 'P', "mysql port",
75 &opt_port, &opt_port, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
76 {"socket", 'W',
77 "named pipe name (if missing, it will be set the same as service)",
78 &opt_socket, &opt_socket, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
79 {"default-user", 'D', "Create default user",
80 &opt_default_user, &opt_default_user, 0 , GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
81 {"allow-remote-root-access", 'R',
82 "Allows remote access from network for user root",
83 &opt_allow_remote_root_access, &opt_allow_remote_root_access, 0 , GET_BOOL,
84 OPT_ARG, 0, 0, 0, 0, 0, 0},
85 {"skip-networking", 'N', "Do not use TCP connections, use pipe instead",
86 &opt_skip_networking, &opt_skip_networking, 0 , GET_BOOL, OPT_ARG, 0, 0, 0, 0,
87 0, 0},
88 { "innodb-page-size", 'i', "Page size for innodb",
89 &opt_innodb_page_size, &opt_innodb_page_size, 0, GET_INT, REQUIRED_ARG, DEFAULT_INNODB_PAGE_SIZE, 1*1024, 64*1024, 0, 0, 0 },
90 {"silent", 's', "Print less information", &opt_silent,
91 &opt_silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
92 {"verbose-bootstrap", 'o', "Include mysqld bootstrap output",&opt_verbose_bootstrap,
93 &opt_verbose_bootstrap, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
94 {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
95 };
96
97
98 static my_bool
get_one_option(const struct my_option * opt,const char *,const char *)99 get_one_option(const struct my_option *opt, const char *, const char *)
100 {
101 DBUG_ENTER("get_one_option");
102 switch (opt->id) {
103 case '?':
104 printf("%s\n", USAGETEXT);
105 my_print_help(my_long_options);
106 exit(0);
107 break;
108 }
109 DBUG_RETURN(0);
110 }
111
112
die(const char * fmt,...)113 ATTRIBUTE_NORETURN static void die(const char *fmt, ...)
114 {
115 va_list args;
116 DBUG_ENTER("die");
117
118 /* Print the error message */
119 va_start(args, fmt);
120 fprintf(stderr, "FATAL ERROR: ");
121 vfprintf(stderr, fmt, args);
122 fputc('\n', stderr);
123 if (verbose_errors)
124 {
125 fprintf(stderr,
126 "https://mariadb.com/kb/en/installation-issues-on-windows contains some help\n"
127 "for solving the most common problems. If this doesn't help you, please\n"
128 "leave a comment in the Knowledge Base or file a bug report at\n"
129 "https://jira.mariadb.org");
130 }
131 fflush(stderr);
132 va_end(args);
133 my_end(0);
134 exit(1);
135 }
136
137
verbose(const char * fmt,...)138 static void verbose(const char *fmt, ...)
139 {
140 va_list args;
141
142 if (opt_silent)
143 return;
144
145 /* Print the verbose message */
146 va_start(args, fmt);
147 vfprintf(stdout, fmt, args);
148 fputc('\n', stdout);
149 fflush(stdout);
150 va_end(args);
151 }
152
153
main(int argc,char ** argv)154 int main(int argc, char **argv)
155 {
156 int error;
157 char self_name[FN_REFLEN];
158 char *p;
159
160 MY_INIT(argv[0]);
161 GetModuleFileName(NULL, self_name, FN_REFLEN);
162 strcpy(mysqld_path,self_name);
163 p= strrchr(mysqld_path, FN_LIBCHAR);
164 if (p)
165 {
166 strcpy(p, "\\mysqld.exe");
167 }
168
169 if ((error= handle_options(&argc, &argv, my_long_options, get_one_option)))
170 exit(error);
171 if (!opt_datadir)
172 {
173 /*
174 Figure out default data directory. It "data" directory, next to "bin" directory, where
175 mysql_install_db.exe resides.
176 */
177 strcpy(default_datadir, self_name);
178 p = strrchr(default_datadir, FN_LIBCHAR);
179 if (p)
180 {
181 *p= 0;
182 p= strrchr(default_datadir, FN_LIBCHAR);
183 if (p)
184 *p= 0;
185 }
186 if (!p)
187 {
188 die("--datadir option not provided, and default datadir not found");
189 my_print_help(my_long_options);
190 }
191 strcat_s(default_datadir, "\\data");
192 opt_datadir= default_datadir;
193 printf("Default data directory is %s\n",opt_datadir);
194 }
195
196 /* Print some help on errors */
197 verbose_errors= TRUE;
198
199 if (!opt_os_user)
200 {
201 opt_os_user= default_os_user;
202 opt_os_password= NULL;
203 }
204 /* Workaround WiX bug (strip possible quote character at the end of path) */
205 size_t len= strlen(opt_datadir);
206 if (len > 0)
207 {
208 if (opt_datadir[len-1] == '"')
209 {
210 opt_datadir[len-1]= 0;
211 }
212 }
213 GetFullPathName(opt_datadir, FN_REFLEN, datadir_buffer, NULL);
214 opt_datadir= datadir_buffer;
215
216 if (create_db_instance())
217 {
218 die("database creation failed");
219 }
220
221 printf("Creation of the database was successful\n");
222 return 0;
223 }
224
225
226
227 /**
228 Convert slashes in paths into MySQL-compatible form
229 */
230
convert_slashes(char * s)231 static void convert_slashes(char *s)
232 {
233 for (; *s ; s++)
234 if (*s == '\\')
235 *s= '/';
236 }
237
238
239 /**
240 Calculate basedir from mysqld.exe path.
241 Basedir assumed to be is one level up from the mysqld.exe directory location.
242 E.g basedir for C:\my\bin\mysqld.exe would be C:\my
243 */
244
get_basedir(char * basedir,int size,const char * mysqld_path)245 static void get_basedir(char *basedir, int size, const char *mysqld_path)
246 {
247 strcpy_s(basedir, size, mysqld_path);
248 convert_slashes(basedir);
249 char *p= strrchr(basedir,'/');
250 if (p)
251 {
252 *p = 0;
253 p= strrchr(basedir, '/');
254 if (p)
255 *p= 0;
256 }
257 }
258
259 #define STR(s) _STR(s)
260 #define _STR(s) #s
261
get_plugindir()262 static char *get_plugindir()
263 {
264 static char plugin_dir[2*MAX_PATH];
265 get_basedir(plugin_dir, sizeof(plugin_dir), mysqld_path);
266 strcat(plugin_dir, "/" STR(INSTALL_PLUGINDIR));
267
268 if (access(plugin_dir, 0) == 0)
269 return plugin_dir;
270
271 return NULL;
272 }
273
274 /**
275 Allocate and initialize command line for mysqld --bootstrap.
276 The resulting string is passed to popen, so it has a lot of quoting
277 quoting around the full string plus quoting around parameters with spaces.
278 */
279
init_bootstrap_command_line(char * cmdline,size_t size)280 static char *init_bootstrap_command_line(char *cmdline, size_t size)
281 {
282 char basedir[MAX_PATH];
283 get_basedir(basedir, sizeof(basedir), mysqld_path);
284
285 my_snprintf(cmdline, size - 1,
286 "\"\"%s\" --no-defaults %s --innodb-page-size=%d --bootstrap"
287 " \"--lc-messages-dir=%s/share\""
288 " --basedir=. --datadir=. --default-storage-engine=myisam"
289 " --max_allowed_packet=9M "
290 " --net-buffer-length=16k\"", mysqld_path,
291 opt_verbose_bootstrap ? "--console" : "", opt_innodb_page_size, basedir);
292 return cmdline;
293 }
294
295
296 /**
297 Create my.ini in current directory (this is assumed to be
298 data directory as well).
299 */
300
create_myini()301 static int create_myini()
302 {
303 my_bool enable_named_pipe= FALSE;
304 printf("Creating my.ini file\n");
305
306 char path_buf[MAX_PATH];
307 GetCurrentDirectory(MAX_PATH, path_buf);
308
309 /* Create ini file. */
310 FILE *myini= fopen("my.ini","wt");
311 if (!myini)
312 {
313 die("Can't create my.ini in data directory");
314 }
315
316 /* Write out server settings. */
317 fprintf(myini, "[mysqld]\n");
318 convert_slashes(path_buf);
319 fprintf(myini, "datadir=%s\n", path_buf);
320 if (opt_skip_networking)
321 {
322 fprintf(myini,"skip-networking\n");
323 if (!opt_socket)
324 opt_socket= opt_service;
325 }
326 enable_named_pipe= (my_bool)
327 ((opt_socket && opt_socket[0]) || opt_skip_networking);
328
329 if (enable_named_pipe)
330 {
331 fprintf(myini,"named-pipe=ON\n");
332 }
333
334 if (opt_socket && opt_socket[0])
335 {
336 fprintf(myini, "socket=%s\n", opt_socket);
337 }
338 if (opt_port)
339 {
340 fprintf(myini,"port=%d\n", opt_port);
341 }
342 if (opt_innodb_page_size != DEFAULT_INNODB_PAGE_SIZE)
343 {
344 fprintf(myini, "innodb-page-size=%d\n", opt_innodb_page_size);
345 }
346 /* Write out client settings. */
347 fprintf(myini, "[client]\n");
348
349 /* Used for named pipes */
350 if (opt_socket && opt_socket[0])
351 fprintf(myini,"socket=%s\n",opt_socket);
352 if (opt_skip_networking)
353 fprintf(myini,"protocol=pipe\n");
354 else if (opt_port)
355 fprintf(myini,"port=%d\n",opt_port);
356
357 char *plugin_dir = get_plugindir();
358 if (plugin_dir)
359 fprintf(myini, "plugin-dir=%s\n", plugin_dir);
360 fclose(myini);
361 return 0;
362 }
363
364
365 static const char update_root_passwd_part1[]=
366 "UPDATE mysql.global_priv SET priv=json_set(priv,"
367 "'$.password_last_changed', UNIX_TIMESTAMP(),"
368 "'$.plugin','mysql_native_password',"
369 "'$.authentication_string',PASSWORD(";
370 static const char update_root_passwd_part2[]=
371 ")) where User='root';\n";
372 static const char remove_default_user_cmd[]=
373 "DELETE FROM mysql.user where User='';\n";
374 static const char allow_remote_root_access_cmd[]=
375 "CREATE TEMPORARY TABLE tmp_user LIKE global_priv;\n"
376 "INSERT INTO tmp_user SELECT * from global_priv where user='root' "
377 " AND host='localhost';\n"
378 "UPDATE tmp_user SET host='%';\n"
379 "INSERT INTO global_priv SELECT * FROM tmp_user;\n"
380 "DROP TABLE tmp_user;\n";
381 static const char end_of_script[]="-- end.";
382
383 /* Register service. Assume my.ini is in datadir */
384
register_service()385 static int register_service()
386 {
387 char buf[3*MAX_PATH +32]; /* path to mysqld.exe, to my.ini, service name */
388 SC_HANDLE sc_manager, sc_service;
389
390 size_t datadir_len= strlen(opt_datadir);
391 const char *backslash_after_datadir= "\\";
392
393 if (datadir_len && opt_datadir[datadir_len-1] == '\\')
394 backslash_after_datadir= "";
395
396 verbose("Registering service '%s'", opt_service);
397 my_snprintf(buf, sizeof(buf)-1,
398 "\"%s\" \"--defaults-file=%s%smy.ini\" \"%s\"" , mysqld_path, opt_datadir,
399 backslash_after_datadir, opt_service);
400
401 /* Get a handle to the SCM database. */
402 sc_manager= OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS);
403 if (!sc_manager)
404 {
405 die("OpenSCManager failed (%u)\n", GetLastError());
406 }
407
408 /* Create the service. */
409 sc_service= CreateService(sc_manager, opt_service, opt_service,
410 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START,
411 SERVICE_ERROR_NORMAL, buf, NULL, NULL, NULL, opt_os_user, opt_os_password);
412
413 if (!sc_service)
414 {
415 CloseServiceHandle(sc_manager);
416 die("CreateService failed (%u)", GetLastError());
417 }
418 char description[] = "MariaDB database server";
419 SERVICE_DESCRIPTION sd= { description };
420 ChangeServiceConfig2(sc_service, SERVICE_CONFIG_DESCRIPTION, &sd);
421 CloseServiceHandle(sc_service);
422 CloseServiceHandle(sc_manager);
423 return 0;
424 }
425
426
clean_directory(const char * dir)427 static void clean_directory(const char *dir)
428 {
429 char dir2[MAX_PATH + 4]= {};
430 snprintf(dir2, MAX_PATH+2, "%s\\*", dir);
431
432 SHFILEOPSTRUCT fileop;
433 fileop.hwnd= NULL; /* no status display */
434 fileop.wFunc= FO_DELETE; /* delete operation */
435 fileop.pFrom= dir2; /* source file name as double null terminated string */
436 fileop.pTo= NULL; /* no destination needed */
437 fileop.fFlags= FOF_NOCONFIRMATION|FOF_SILENT; /* do not prompt the user */
438
439
440 fileop.fAnyOperationsAborted= FALSE;
441 fileop.lpszProgressTitle= NULL;
442 fileop.hNameMappings= NULL;
443
444 SHFileOperation(&fileop);
445 }
446
447
448 /*
449 Define directory permission to have inheritable all access for a user
450 (defined as username or group string or as SID)
451 */
452
set_directory_permissions(const char * dir,const char * os_user)453 static int set_directory_permissions(const char *dir, const char *os_user)
454 {
455
456 struct{
457 TOKEN_USER tokenUser;
458 BYTE buffer[SECURITY_MAX_SID_SIZE];
459 } tokenInfoBuffer;
460
461 HANDLE hDir= CreateFile(dir,READ_CONTROL|WRITE_DAC,0,NULL,OPEN_EXISTING,
462 FILE_FLAG_BACKUP_SEMANTICS,NULL);
463 if (hDir == INVALID_HANDLE_VALUE)
464 return -1;
465 ACL* pOldDACL;
466 SECURITY_DESCRIPTOR* pSD= NULL;
467 EXPLICIT_ACCESS ea={0};
468 WELL_KNOWN_SID_TYPE wellKnownSidType = WinNullSid;
469 PSID pSid= NULL;
470
471 GetSecurityInfo(hDir, SE_FILE_OBJECT , DACL_SECURITY_INFORMATION,NULL, NULL,
472 &pOldDACL, NULL, (void**)&pSD);
473
474 if (os_user)
475 {
476 /* Check for 3 predefined service users
477 They might have localized names in non-English Windows, thus they need
478 to be handled using well-known SIDs.
479 */
480 if (stricmp(os_user, "NT AUTHORITY\\NetworkService") == 0)
481 {
482 wellKnownSidType= WinNetworkServiceSid;
483 }
484 else if (stricmp(os_user, "NT AUTHORITY\\LocalService") == 0)
485 {
486 wellKnownSidType= WinLocalServiceSid;
487 }
488 else if (stricmp(os_user, "NT AUTHORITY\\LocalSystem") == 0)
489 {
490 wellKnownSidType= WinLocalSystemSid;
491 }
492
493 if (wellKnownSidType != WinNullSid)
494 {
495 DWORD size= SECURITY_MAX_SID_SIZE;
496 pSid= (PSID)tokenInfoBuffer.buffer;
497 if (!CreateWellKnownSid(wellKnownSidType, NULL, pSid,
498 &size))
499 {
500 return 1;
501 }
502 ea.Trustee.TrusteeForm= TRUSTEE_IS_SID;
503 ea.Trustee.ptstrName= (LPTSTR)pSid;
504 }
505 else
506 {
507 ea.Trustee.TrusteeForm= TRUSTEE_IS_NAME;
508 ea.Trustee.ptstrName= (LPSTR)os_user;
509 }
510 }
511 else
512 {
513 HANDLE token;
514 if (OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY, &token))
515 {
516
517 DWORD length= (DWORD) sizeof(tokenInfoBuffer);
518 if (GetTokenInformation(token, TokenUser, &tokenInfoBuffer,
519 length, &length))
520 {
521 pSid= tokenInfoBuffer.tokenUser.User.Sid;
522 }
523 }
524 if (!pSid)
525 return 0;
526 ea.Trustee.TrusteeForm= TRUSTEE_IS_SID;
527 ea.Trustee.ptstrName= (LPTSTR)pSid;
528 }
529 ea.grfAccessMode= GRANT_ACCESS;
530 ea.grfAccessPermissions= GENERIC_ALL;
531 ea.grfInheritance= CONTAINER_INHERIT_ACE|OBJECT_INHERIT_ACE;
532 ea.Trustee.TrusteeType= TRUSTEE_IS_UNKNOWN;
533 ACL* pNewDACL= 0;
534 SetEntriesInAcl(1,&ea,pOldDACL,&pNewDACL);
535 if (pNewDACL)
536 {
537 SetSecurityInfo(hDir,SE_FILE_OBJECT,DACL_SECURITY_INFORMATION,NULL, NULL,
538 pNewDACL, NULL);
539 }
540 if (pSD != NULL)
541 LocalFree((HLOCAL) pSD);
542 if (pNewDACL != NULL)
543 LocalFree((HLOCAL) pNewDACL);
544 CloseHandle(hDir);
545 return 0;
546 }
547
548
549
550 /* Create database instance (including registering as service etc) .*/
551
create_db_instance()552 static int create_db_instance()
553 {
554 int ret= 0;
555 char cwd[MAX_PATH];
556 DWORD cwd_len= MAX_PATH;
557 char cmdline[3*MAX_PATH];
558 FILE *in;
559 bool created_datadir= false;
560 DWORD last_error;
561
562 verbose("Running bootstrap");
563
564 GetCurrentDirectory(cwd_len, cwd);
565
566 /* Create datadir and datadir/mysql, if they do not already exist. */
567
568 if (CreateDirectory(opt_datadir, NULL))
569 {
570 created_datadir= true;
571 }
572 else if (GetLastError() != ERROR_ALREADY_EXISTS)
573 {
574 last_error = GetLastError();
575 switch(last_error)
576 {
577 case ERROR_ACCESS_DENIED:
578 die("Can't create data directory '%s' (access denied)\n",
579 opt_datadir);
580 break;
581 case ERROR_PATH_NOT_FOUND:
582 die("Can't create data directory '%s' "
583 "(one or more intermediate directories do not exist)\n",
584 opt_datadir);
585 break;
586 default:
587 die("Can't create data directory '%s', last error %u\n",
588 opt_datadir, last_error);
589 break;
590 }
591 }
592
593 if (!SetCurrentDirectory(opt_datadir))
594 {
595 last_error = GetLastError();
596 switch (last_error)
597 {
598 case ERROR_DIRECTORY:
599 die("Can't set current directory to '%s', the path is not a valid directory \n",
600 opt_datadir);
601 break;
602 default:
603 die("Can' set current directory to '%s', last error %u\n",
604 opt_datadir, last_error);
605 break;
606 }
607 }
608
609 if (!PathIsDirectoryEmpty(opt_datadir))
610 {
611 fprintf(stderr,"ERROR : Data directory %s is not empty."
612 " Only new or empty existing directories are accepted for --datadir\n",opt_datadir);
613 exit(1);
614 }
615
616 if (!CreateDirectory("mysql",NULL))
617 {
618 last_error = GetLastError();
619 DWORD attributes;
620 switch(last_error)
621 {
622 case ERROR_ACCESS_DENIED:
623 die("Can't create subdirectory 'mysql' in '%s' (access denied)\n",opt_datadir);
624 break;
625 case ERROR_ALREADY_EXISTS:
626 attributes = GetFileAttributes("mysql");
627
628 if (attributes == INVALID_FILE_ATTRIBUTES)
629 die("GetFileAttributes() failed for existing file '%s\\mysql', last error %u",
630 opt_datadir, GetLastError());
631 else if (!(attributes & FILE_ATTRIBUTE_DIRECTORY))
632 die("File '%s\\mysql' exists, but it is not a directory", opt_datadir);
633
634 break;
635 }
636 }
637
638 /*
639 Set data directory permissions for both current user and
640 default_os_user (the one who runs services).
641 */
642 set_directory_permissions(opt_datadir, NULL);
643 set_directory_permissions(opt_datadir, default_os_user);
644
645 /* Do mysqld --bootstrap. */
646 init_bootstrap_command_line(cmdline, sizeof(cmdline));
647
648 if(opt_verbose_bootstrap)
649 printf("Executing %s\n", cmdline);
650
651 in= popen(cmdline, "wt");
652 if (!in)
653 goto end;
654
655 if (setvbuf(in, NULL, _IONBF, 0))
656 {
657 verbose("WARNING: Can't disable buffering on mysqld's stdin");
658 }
659 if (fwrite("use mysql;\n",11,1, in) != 1)
660 {
661 verbose("ERROR: Can't write to mysqld's stdin");
662 ret= 1;
663 goto end;
664 }
665
666 int i;
667 for (i=0; mysql_bootstrap_sql[i]; i++)
668 {
669 /* Write the bootstrap script to stdin. */
670 if (fwrite(mysql_bootstrap_sql[i], strlen(mysql_bootstrap_sql[i]), 1, in) != 1)
671 {
672 verbose("ERROR: Can't write to mysqld's stdin");
673 ret= 1;
674 goto end;
675 }
676 }
677
678 /* Remove default user, if requested. */
679 if (!opt_default_user)
680 {
681 verbose("Removing default user",remove_default_user_cmd);
682 fputs(remove_default_user_cmd, in);
683 fflush(in);
684 }
685
686 if (opt_allow_remote_root_access)
687 {
688 verbose("Allowing remote access for user root",remove_default_user_cmd);
689 fputs(allow_remote_root_access_cmd,in);
690 fflush(in);
691 }
692
693 /* Change root password if requested. */
694 if (opt_password && opt_password[0])
695 {
696 verbose("Setting root password",remove_default_user_cmd);
697 fputs(update_root_passwd_part1, in);
698
699 /* Use hex encoding for password, to avoid escaping problems.*/
700 fputc('0', in);
701 fputc('x', in);
702 for(int i= 0; opt_password[i]; i++)
703 {
704 fprintf(in,"%02x",opt_password[i]);
705 }
706
707 fputs(update_root_passwd_part2, in);
708 fflush(in);
709 }
710
711 /*
712 On some reason, bootstrap chokes if last command sent via stdin ends with
713 newline, so we supply a dummy comment, that does not end with newline.
714 */
715 fputs(end_of_script, in);
716 fflush(in);
717
718 /* Check if bootstrap has completed successfully. */
719 ret= pclose(in);
720 if (ret)
721 {
722 verbose("mysqld returned error %d in pclose",ret);
723 goto end;
724 }
725
726
727 /* Create my.ini file in data directory.*/
728 ret= create_myini();
729 if (ret)
730 goto end;
731
732 /* Register service if requested. */
733 if (opt_service && opt_service[0])
734 {
735 ret= register_service();
736 if (ret)
737 goto end;
738 }
739
740 end:
741 if (ret)
742 {
743 SetCurrentDirectory(cwd);
744 clean_directory(opt_datadir);
745 if (created_datadir)
746 RemoveDirectory(opt_datadir);
747 }
748 return ret;
749 }
750