1#!/bin/sh
2# Copyright (c) 2000, 2013, Oracle and/or its affiliates.
3# Copyright (c) 2009, 2013, Monty Program Ab
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; version 2 of the License.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program; if not, write to the Free Software
16# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1335  USA
17
18# This scripts creates the MariaDB Server system tables
19#
20# All unrecognized arguments to this script are passed to mysqld.
21
22basedir=""
23builddir=""
24ldata="@localstatedir@"
25langdir=""
26srcdir=""
27log_error=""
28
29args=""
30defaults=""
31defaults_group_suffix=""
32mysqld_opt=""
33user=""
34group=""
35silent_startup="--silent-startup"
36
37force=0
38in_rpm=0
39ip_only=0
40cross_bootstrap=0
41auth_root_authentication_method=socket
42auth_root_socket_user=""
43skip_test_db=0
44
45dirname0=`dirname $0 2>/dev/null`
46dirname0=`dirname $dirname0 2>/dev/null`
47
48usage()
49{
50  cat <<EOF
51Usage: $0 [OPTIONS]
52  --auth-root-authentication-method=normal|socket
53                       Chooses the authentication method for the created
54                       initial root user. The historical behavior is 'normal'
55                       to creates a root user that can login without password,
56                       which can be insecure. The default behavior 'socket'
57                       sets an invalid root password but allows the system root
58                       user to login as MariaDB root without a password.
59  --auth-root-socket-user=user
60                       Used with --auth-root-authentication-method=socket. It
61                       specifies the name of the second MariaDB root account,
62                       as well as of the system account allowed to access it.
63                       Defaults to the value of --user.
64  --basedir=path       The path to the MariaDB installation directory.
65  --builddir=path      If using --srcdir with out-of-directory builds, you
66                       will need to set this to the location of the build
67                       directory where built files reside.
68  --cross-bootstrap    For internal use.  Used when building the MariaDB system
69                       tables on a different host than the target.
70  --datadir=path       The path to the MariaDB data directory.
71  --no-defaults        Don't read default options from any option file.
72  --defaults-extra-file=name
73                       Read this file after the global files are read.
74  --defaults-file=name Only read default options from the given file name.
75  --defaults-group-suffix=name
76                       In addition to the given groups, read also groups with
77                       this suffix
78  --force              Causes mysql_install_db to run even if DNS does not
79                       work.  In that case, grant table entries that
80                       normally use hostnames will use IP addresses.
81  --help               Display this help and exit.                     
82  --ldata=path         The path to the MariaDB data directory. Same as
83                       --datadir.
84  --rpm                For internal use.  This option is used by RPM files
85                       during the MariaDB installation process.
86  --skip-name-resolve  Use IP addresses rather than hostnames when creating
87                       grant table entries.  This option can be useful if
88                       your DNS does not work.
89  --skip-test-db       Don't install a test database.
90  --srcdir=path        The path to the MariaDB source directory.  This option
91                       uses the compiled binaries and support files within the
92                       source tree, useful for if you don't want to install
93                       MariaDB yet and just want to create the system tables.
94  --user=user_name     The login username to use for running mysqld.  Files
95                       and directories created by mysqld will be owned by this
96                       user.  You must be root to use this option.  By default
97                       mysqld runs using your current login name and files and
98                       directories that it creates will be owned by you.
99  --group=group_name   The login group to use for running mysqld.  Files and
100                       directories created by mysqld will be owned by this
101                       group. You must be root to use this option.  By default
102                       mysqld runs using your current group and files and
103                       directories that it creates will be owned by you.
104
105All other options are passed to the mysqld program
106
107EOF
108  exit 1
109}
110
111s_echo()
112{
113  if test "$in_rpm" -eq 0 -a "$cross_bootstrap" -eq 0
114  then
115    echo "$1"
116  fi
117}
118
119link_to_help()
120{
121  echo
122  echo "The latest information about mysql_install_db is available at"
123  echo "https://mariadb.com/kb/en/installing-system-tables-mysql_install_db"
124}
125
126parse_arg()
127{
128  echo "$1" | sed -e 's/^[^=]*=//'
129}
130
131parse_arguments()
132{
133  # We only need to pass arguments through to the server if we don't
134  # handle them here.  So, we collect unrecognized options (passed on
135  # the command line) into the args variable.
136  pick_args=
137  if test "$1" = PICK-ARGS-FROM-ARGV
138  then
139    pick_args=1
140    shift
141  fi
142
143  for arg
144  do
145    case "$arg" in
146      --force) force=1 ;;
147      --basedir=*) basedir=`parse_arg "$arg"` ;;
148      --builddir=*) builddir=`parse_arg "$arg"` ;;
149      --srcdir=*)  srcdir=`parse_arg "$arg"` ;;
150      --ldata=*|--datadir=*|--data=*) ldata=`parse_arg "$arg"` ;;
151      --log-error=*)
152       log_error=`parse_arg "$arg"` ;;
153        # Note that the user will be passed to mysqld so that it runs
154        # as 'user' (crucial e.g. if log-bin=/some_other_path/
155        # where a chown of datadir won't help)
156      --user=*) user=`parse_arg "$arg"` ;;
157      --group=*) group=`parse_arg "$arg"` ;;
158      --skip-name-resolve) ip_only=1 ;;
159      --verbose) verbose=1 ; silent_startup="" ;;
160      --rpm) in_rpm=1 ;;
161      --help) usage ;;
162      --no-defaults|--defaults-file=*|--defaults-extra-file=*)
163        defaults="$arg" ;;
164      --defaults-group-suffix=*)
165        defaults_group_suffix="$arg" ;;
166
167      --cross-bootstrap|--windows)
168        # Used when building the MariaDB system tables on a different host than
169        # the target. The platform-independent files that are created in
170        # --datadir on the host can be copied to the target system.
171        #
172        # The most common use for this feature is in the Windows installer
173        # which will take the files from datadir and include them as part of
174        # the install package.  See top-level 'dist-hook' make target.
175        #
176        # --windows is a deprecated alias
177        cross_bootstrap=1 ;;
178      --auth-root-authentication-method=normal)
179	auth_root_authentication_method=normal ;;
180      --auth-root-authentication-method=socket)
181	auth_root_authentication_method=socket ;;
182      --auth-root-authentication-method=*)
183        usage ;;
184      --auth-root-socket-user=*)
185        auth_root_socket_user="$(parse_arg "$arg")" ;;
186      --skip-test-db) skip_test_db=1 ;;
187
188      *)
189        if test -n "$pick_args"
190        then
191          # This sed command makes sure that any special chars are quoted,
192          # so the arg gets passed exactly to the server.
193          # XXX: This is broken; true fix requires using eval and proper
194          # quoting of every single arg ($basedir, $ldata, etc.)
195          #args="$args "`echo "$arg" | sed -e 's,\([^a-zA-Z0-9_.-]\),\\\\\1,g'`
196          args="$args $arg"
197        fi
198        ;;
199    esac
200  done
201}
202
203# Try to find a specific file within --basedir which can either be a binary
204# release or installed source directory and return the path.
205find_in_dirs()
206{
207  case "$1" in
208    --dir)
209      return_dir=1; shift
210      ;;
211  esac
212
213  file=$1; shift
214
215  for dir in "$@"
216  do
217    if test -f "$dir/$file"
218    then
219      if test -n "$return_dir"
220      then
221        echo "$dir"
222      else
223        echo "$dir/$file"
224      fi
225      break
226    fi
227  done
228}
229
230cannot_find_file()
231{
232  echo
233  echo "FATAL ERROR: Could not find $1"
234
235  shift
236  if test $# -ne 0
237  then
238    echo
239    echo "The following directories were searched:"
240    echo
241    for dir in "$@"
242    do
243      echo "    $dir"
244    done
245  fi
246
247  echo
248  echo "If you compiled from source, you need to either run 'make install' to"
249  echo "copy the software into the correct location ready for operation."
250  echo "If you don't want to do a full install, you can use the --srcdir"
251  echo "option to only install the mysql database and privilege tables."
252  echo
253  echo "If you are using a binary release, you must either be at the top"
254  echo "level of the extracted archive, or pass the --basedir option"
255  echo "pointing to that location."
256  link_to_help
257}
258
259# Ok, let's go.  We first need to parse arguments which are required by
260# my_print_defaults so that we can execute it first, then later re-parse
261# the command line to add any extra bits that we need.
262parse_arguments "$@"
263
264#
265# We can now find my_print_defaults.  This script supports:
266#
267#   --srcdir=path pointing to compiled source tree
268#   --basedir=path pointing to installed binary location
269#
270# or default to compiled-in locations.
271#
272if test -n "$srcdir" && test -n "$basedir"
273then
274  echo "ERROR: Specify either --basedir or --srcdir, not both."
275  link_to_help
276  exit 1
277fi
278if test -n "$srcdir"
279then
280  # In an out-of-source build, builddir is not srcdir. Try to guess where
281  # builddir is by looking for my_print_defaults.
282  if test -z "$builddir"
283  then
284    if test -x "$dirname0/extra/my_print_defaults"
285    then
286      builddir="$dirname0"
287    else
288      builddir="$srcdir"
289    fi
290  fi
291  print_defaults="$builddir/extra/my_print_defaults"
292elif test -n "$basedir"
293then
294  print_defaults=`find_in_dirs my_print_defaults $basedir/bin $basedir/extra`
295  if test -z "$print_defaults"
296  then
297    cannot_find_file my_print_defaults $basedir/bin $basedir/extra
298    exit 1
299  fi
300elif test -n "$dirname0" -a -x "$dirname0/@bindir@/my_print_defaults"
301then
302  print_defaults="$dirname0/@bindir@/my_print_defaults"
303elif test -x "./extra/my_print_defaults"
304then
305  srcdir="."
306  builddir="."
307  print_defaults="./extra/my_print_defaults"
308else
309  print_defaults="@bindir@/my_print_defaults"
310fi
311
312if test ! -x "$print_defaults"
313then
314  cannot_find_file "$print_defaults"
315  exit 1
316fi
317
318# Now we can get arguments from the groups [mysqld] and [mysql_install_db]
319# in the my.cfg file, then re-run to merge with command line arguments.
320parse_arguments `"$print_defaults" $defaults $defaults_group_suffix --mysqld mysql_install_db mariadb-install-db`
321
322parse_arguments PICK-ARGS-FROM-ARGV "$@"
323
324rel_mysqld="$dirname0/@INSTALL_SBINDIR@/mysqld"
325
326# Configure paths to support files
327if test -n "$srcdir"
328then
329  basedir="$builddir"
330  bindir="$basedir/client"
331  resolveip="$basedir/extra/resolveip"
332  mysqld="$basedir/sql/mysqld"
333  langdir="$basedir/sql/share/english"
334  srcpkgdatadir="$srcdir/scripts"
335  buildpkgdatadir="$builddir/scripts"
336  plugindir="$builddir/plugin/auth_socket"
337  pamtooldir="$builddir/plugin/auth_pam"
338elif test -n "$basedir"
339then
340  bindir="$basedir/bin" # only used in the help text
341  resolveip=`find_in_dirs resolveip @resolveip_locations@`
342  if test -z "$resolveip"
343  then
344    cannot_find_file resolveip @resolveip_locations@
345    exit 1
346  fi
347  mysqld=`find_in_dirs mysqld @mysqld_locations@`
348  if test -z "$mysqld"
349  then
350    cannot_find_file mysqld @mysqld_locations@
351    exit 1
352  fi
353  langdir=`find_in_dirs --dir errmsg.sys @errmsg_locations@`
354  if test -z "$langdir"
355  then
356    cannot_find_file errmsg.sys @errmsg_locations@
357    exit 1
358  fi
359  srcpkgdatadir=`find_in_dirs --dir fill_help_tables.sql @pkgdata_locations@`
360  buildpkgdatadir=$srcpkgdatadir
361  if test -z "$srcpkgdatadir"
362  then
363    cannot_find_file fill_help_tables.sql @pkgdata_locations@
364    exit 1
365  fi
366  plugindir=`find_in_dirs --dir auth_pam.so $basedir/lib*/plugin $basedir/lib*/mysql/plugin $basedir/lib/*/mariadb19/plugin`
367  pamtooldir=$plugindir
368# relative from where the script was run for a relocatable install
369elif test -n "$dirname0" -a -x "$rel_mysqld" -a ! "$rel_mysqld" -ef "@sbindir@/mysqld"
370then
371  basedir="$dirname0"
372  bindir="$basedir/@INSTALL_BINDIR@"
373  resolveip="$bindir/resolveip"
374  mysqld="$rel_mysqld"
375  srcpkgdatadir="$basedir/@INSTALL_MYSQLSHAREDIR@"
376  buildpkgdatadir="$basedir/@INSTALL_MYSQLSHAREDIR@"
377  plugindir="$basedir/@INSTALL_PLUGINDIR@"
378  pamtooldir=$plugindir
379else
380  basedir="@prefix@"
381  bindir="@bindir@"
382  resolveip="$bindir/resolveip"
383  mysqld="@sbindir@/mysqld"
384  srcpkgdatadir="@pkgdatadir@"
385  buildpkgdatadir="@pkgdatadir@"
386  plugindir="@pkgplugindir@"
387  pamtooldir="@pkgplugindir@"
388fi
389
390# Set up paths to SQL scripts required for bootstrap
391fill_help_tables="$srcpkgdatadir/fill_help_tables.sql"
392create_system_tables="$srcpkgdatadir/mysql_system_tables.sql"
393create_system_tables2="$srcpkgdatadir/mysql_performance_tables.sql"
394fill_system_tables="$srcpkgdatadir/mysql_system_tables_data.sql"
395maria_add_gis_sp="$buildpkgdatadir/maria_add_gis_sp_bootstrap.sql"
396mysql_test_db="$srcpkgdatadir/mysql_test_db.sql"
397
398for f in "$fill_help_tables" "$create_system_tables" "$create_system_tables2" "$fill_system_tables" "$maria_add_gis_sp" "$mysql_test_db"
399do
400  if test ! -f "$f"
401  then
402    cannot_find_file "$f"
403    exit 1
404  fi
405done
406
407if test ! -x "$mysqld"
408then
409  cannot_find_file "$mysqld"
410  exit 1
411fi
412
413if test -n "$langdir"
414then
415  if test ! -f "$langdir/errmsg.sys"
416  then
417    cannot_find_file "$langdir/errmsg.sys"
418    exit 1
419  fi
420  mysqld_opt="--lc-messages-dir=$langdir/.."
421else
422  mysqld_opt="--lc-messages=en_US"
423fi
424
425
426# Try to determine the hostname
427hostname=`@HOSTNAME@`
428
429# Check if hostname is valid
430if test "$cross_bootstrap" -eq 0 -a "$in_rpm" -eq 0 -a "$force" -eq 0
431then
432  resolved=`"$resolveip" $hostname 2>&1`
433  if test $? -ne 0
434  then
435    resolved=`"$resolveip" localhost 2>&1`
436    if test $? -ne 0
437    then
438      echo "Neither host '$hostname' nor 'localhost' could be looked up with"
439      echo "'$resolveip'"
440      echo "Please configure the 'hostname' command to return a correct"
441      echo "hostname."
442      echo "If you want to solve this at a later stage, restart this script"
443      echo "with the --force option"
444      link_to_help
445      exit 1
446    fi
447    echo "WARNING: The host '$hostname' could not be looked up with $resolveip."
448    echo "This probably means that your libc libraries are not 100 % compatible"
449    echo "with this binary MariaDB version. The MariaDB daemon, mysqld, should work"
450    echo "normally with the exception that host name resolving will not work."
451    echo "This means that you should use IP addresses instead of hostnames"
452    echo "when specifying MariaDB privileges !"
453  fi
454fi
455
456if test "$ip_only" -eq 1
457then
458  hostname=`echo "$resolved" | awk '/ /{print $6}'`
459fi
460
461# Create database directories
462for dir in "$ldata"
463do
464  if test ! -d "$dir"
465  then
466    if ! `mkdir -p "$dir"`
467    then
468      echo "Fatal error Can't create database directory '$dir'"
469      link_to_help
470      exit 1
471    fi
472    chmod 700 "$dir"
473  fi
474  if test -n "$user"
475  then
476    if test -z "$group"
477    then
478      chown $user $dir
479    else
480      chown $user:$group $dir
481    fi
482    if test $? -ne 0
483    then
484      echo "Cannot change ownership of the database directories to the '$user'"
485      echo "user.  Check that you have the necessary permissions and try again."
486      exit 1
487    fi
488  fi
489done
490
491if test -n "$user"
492then
493  if test -z "$srcdir" -a "$in_rpm" -eq 0
494  then
495    chown 0 "$pamtooldir/auth_pam_tool_dir/auth_pam_tool" && \
496    chmod 04755 "$pamtooldir/auth_pam_tool_dir/auth_pam_tool"
497    if test $? -ne 0
498    then
499        echo "Couldn't set an owner to '$pamtooldir/auth_pam_tool_dir/auth_pam_tool'."
500        echo "It must be root, the PAM authentication plugin doesn't work otherwise.."
501        echo
502    fi
503    chown $user "$pamtooldir/auth_pam_tool_dir" && \
504    chmod 0700 "$pamtooldir/auth_pam_tool_dir"
505    if test $? -ne 0
506    then
507        echo "Cannot change ownership of the '$pamtooldir/auth_pam_tool_dir' directory"
508        echo "to the '$user' user. Check that you have the necessary permissions and try again."
509        echo
510    fi
511  fi
512  args="$args --user=$user"
513fi
514
515if test -n "$group"
516then
517  args="$args --group=$group"
518fi
519
520if test -f "$ldata/mysql/user.frm"
521then
522    echo "mysql.user table already exists!"
523    echo "Run mysql_upgrade, not mysql_install_db"
524    exit 0
525fi
526
527# When doing a "cross bootstrap" install, no reference to the current
528# host should be added to the system tables.  So we filter out any
529# lines which contain the current host name.
530if test $cross_bootstrap -eq 1
531then
532  filter_cmd_line="sed -e '/@current_hostname/d'"
533else
534  filter_cmd_line="cat"
535fi
536
537# Configure mysqld command line
538mysqld_bootstrap="${MYSQLD_BOOTSTRAP-$mysqld}"
539mysqld_install_cmd_line()
540{
541  "$mysqld_bootstrap" $defaults $defaults_group_suffix "$mysqld_opt" --bootstrap $silent_startup\
542  "--basedir=$basedir" "--datadir=$ldata" --log-warnings=0 --enforce-storage-engine="" \
543  "--plugin-dir=${plugindir}" --loose-disable-plugin-file-key-management \
544  $args --max_allowed_packet=8M \
545  --net_buffer_length=16K
546}
547
548# Use $auth_root_socket_user if explicitly specified.
549# Otherwise use the owner of datadir - ${user:-$USER}
550# Use 'root' as a fallback
551auth_root_socket_user=${auth_root_socket_user:-${user:-${USER:-root}}}
552
553cat_sql()
554{
555  echo "create database if not exists mysql;"
556  echo "use mysql;"
557
558  case "$auth_root_authentication_method" in
559    normal)
560      echo "SET @auth_root_socket=NULL;"
561      ;;
562    socket)
563      echo "SET @auth_root_socket='$auth_root_socket_user';"
564      ;;
565  esac
566
567  cat "$create_system_tables" "$create_system_tables2" "$fill_system_tables" "$fill_help_tables" "$maria_add_gis_sp"
568  if test "$skip_test_db" -eq 0
569  then
570    cat "$mysql_test_db"
571  fi
572}
573
574# Create the system and help tables by passing them to "mysqld --bootstrap"
575s_echo "Installing MariaDB/MySQL system tables in '$ldata' ..."
576if cat_sql | eval "$filter_cmd_line" | mysqld_install_cmd_line > /dev/null
577then
578    printf "@VERSION@-MariaDB" > "$ldata/mysql_upgrade_info"
579  s_echo "OK"
580else
581  log_file_place=$ldata
582  if test -n "$log_error"
583  then
584    log_file_place="$log_error or $log_file_place"
585  fi
586  echo
587  echo "Installation of system tables failed!  Examine the logs in"
588  echo "$log_file_place for more information."
589  echo
590  echo "The problem could be conflicting information in an external"
591  echo "my.cnf files. You can ignore these by doing:"
592  echo
593  echo "    shell> $0 --defaults-file=~/.my.cnf"
594  echo
595  echo "You can also try to start the mysqld daemon with:"
596  echo
597  echo "    shell> $mysqld --skip-grant-tables --general-log &"
598  echo
599  echo "and use the command line tool $bindir/mysql"
600  echo "to connect to the mysql database and look at the grant tables:"
601  echo
602  echo "    shell> $bindir/mysql -u root mysql"
603  echo "    mysql> show tables;"
604  echo
605  echo "Try 'mysqld --help' if you have problems with paths.  Using"
606  echo "--general-log gives you a log in $ldata that may be helpful."
607  link_to_help
608  echo "You can find the latest source at https://downloads.mariadb.org and"
609  echo "the maria-discuss email list at https://launchpad.net/~maria-discuss"
610  echo
611  echo "Please check all of the above before submitting a bug report"
612  echo "at http://mariadb.org/jira"
613  echo
614  exit 1
615fi
616
617# Don't output verbose information if running inside bootstrap or using
618# --srcdir for testing.  In such cases, there's no end user looking at
619# the screen.
620if test "$cross_bootstrap" -eq 0 && test -z "$srcdir"
621then
622  s_echo
623  s_echo "To start mysqld at boot time you have to copy"
624  s_echo "support-files/mysql.server to the right place for your system"
625
626  if test "$auth_root_authentication_method" = normal
627  then
628    echo
629    echo
630    echo "PLEASE REMEMBER TO SET A PASSWORD FOR THE MariaDB root USER !"
631    echo "To do so, start the server, then issue the following command:"
632    echo
633    echo "'$bindir/mysql_secure_installation'"
634    echo
635    echo "which will also give you the option of removing the test"
636    echo "databases and anonymous user created by default.  This is"
637    echo "strongly recommended for production servers."
638  else
639    echo
640    echo
641    echo "Two all-privilege accounts were created."
642    echo "One is root@localhost, it has no password, but you need to"
643    echo "be system 'root' user to connect. Use, for example, sudo mysql"
644    echo "The second is $auth_root_socket_user@localhost, it has no password either, but"
645    echo "you need to be the system '$auth_root_socket_user' user to connect."
646    echo "After connecting you can set the password, if you would need to be"
647    echo "able to connect as any of these users with a password and without sudo"
648  fi
649
650  echo
651  echo "See the MariaDB Knowledgebase at http://mariadb.com/kb"
652
653  if test "$in_rpm" -eq 0
654  then
655    echo
656    echo "You can start the MariaDB daemon with:"
657    echo "cd '$basedir' ; $bindir/mysqld_safe --datadir='$ldata'"
658    echo
659    echo "You can test the MariaDB daemon with mysql-test-run.pl"
660    echo "cd '$basedir/mysql-test' ; perl mysql-test-run.pl"
661  fi
662
663  echo
664  echo "Please report any problems at http://mariadb.org/jira"
665  echo
666  echo "The latest information about MariaDB is available at http://mariadb.org/."
667  echo
668  echo "Consider joining MariaDB's strong and vibrant community:"
669  echo "https://mariadb.org/get-involved/"
670  echo
671fi
672
673exit 0
674