1 package Install; #assumes Install.pm
4 # Copyright 2000-2002 Katipo Communications
6 # This file is part of Koha.
8 # Koha is free software; you can redistribute it and/or modify it under the
9 # terms of the GNU General Public License as published by the Free Software
10 # Foundation; either version 2 of the License, or (at your option) any later
13 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
14 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License along with
18 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
19 # Suite 330, Boston, MA 02111-1307 USA
25 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
29 Install.pm - Perl module containing the bulk of the installation logic
33 The Install.pm module contains the bulk
34 of the code to do installation;
35 this code is used by installer.pl
36 to perform an actual installation.
38 =head2 Internal functions (not meant to be used outside of Install.pm)
44 # set the version for version checking
48 @EXPORT = qw( &checkperlmodules
52 &releasecandidatewarning
53 &getinstallationdirectories
70 $messages->{'WelcomeToKohaInstaller'
71 = heading('Welcome to the Koha Installer') . qq|...|;
73 The heading function takes one string, the text to be displayed as
74 the heading, and returns a formatted heading (currently formatted
75 in the "traditional Koha installer" style, i.e., surrounded by a
78 This reduces the likelihood of pod2man(1) etc. misinterpreting
79 a line of equal signs as POD directives.
85 my $n = length($s) + 4;
86 my $line = ('=' x $n) . "\n";
87 "\n$line= $s =\n$line\n";
91 $messages->{'continuing'}->{en}="Great! Continuing setup.\n\n";
92 $messages->{'WelcomeToKohaInstaller'}->{en} =
93 heading('Welcome to the Koha Installer') . qq|
94 Welcome to the Koha install script! This script will prompt you for some
95 basic information about your desired setup, then install Koha according to
96 your specifications. To accept the default value for any question, simply hit
99 Please be sure to read the documentation, or visit the Koha website at
100 http://www.koha.org for more information.
102 Are you ready to begin the installation? (Y/[N]): |;
103 $messages->{'ReleaseCandidateWarning'}->{en} =
104 heading('RELEASE CANDIDATE') . qq|
105 WARNING WARNING WARNING WARNING WARNING
107 You are about to install Koha version %s. This version of Koha is a
108 release candidate. It is not intended to be installed on production systems.
109 It is being released so that users can test it before we release a final
112 Are you sure you want to install Koha %s? (Y/[N]): |;
113 $messages->{'WatchForReleaseAnnouncements'}->{en}=qq|
115 Watch for announcements of Koha releases on the Koha mailing list or the Koha
116 web site (http://www.koha.org/).
120 $messages->{'NETZ3950Missing'}->{en}=qq|
122 The Net::Z3950 module is missing. This module is necessary if you want to use
123 Koha's Z39.50 client to download bibliographic records from other libraries.
124 To install this module, you will need the yaz client installed from
125 http://www.indexdata.dk/yaz/ and then you can install the perl module with the
128 perl -MCPAN -e 'install Net::Z3950'
130 Press the <ENTER> key to continue: |;
132 $messages->{'CheckingPerlModules'}->{en} = heading('PERL & MODULES') . qq|
133 Checking perl modules ...
136 $messages->{'PerlVersionFailure'}->{en}="Sorry, you need at least Perl %s\n";
138 $messages->{'MissingPerlModules'}->{en} = heading('MISSING PERL MODULES') . qq|
139 You are missing some Perl modules which are required by Koha.
140 Once these modules have been installed, rerun this installer.
141 They can be installed by running (as root) the following:
146 $messages->{'AllPerlModulesInstalled'}->{en} =
147 heading('ALL PERL MODULES INSTALLED') . qq|
148 All mandatory perl modules are installed.
150 Press <ENTER> to continue: |;
151 $messages->{'KohaVersionInstalled'}->{en}="You currently have Koha %s on your system.";
152 $messages->{'KohaUnknownVersionInstalled'}->{en}="I am not able to determine what version of Koha is installed now.";
153 $messages->{'KohaAlreadyInstalled'}->{en} =
154 heading('Koha already installed') . qq|
155 It looks like Koha is already installed on your system (%s/koha.conf exists
156 already). If you would like to upgrade your system to %s, please use
157 the koha.upgrade script in this directory.
162 $messages->{'GetOpacDir'}->{en} = heading('OPAC DIRECTORY') . qq|
163 Please supply the directory you want Koha to store its OPAC files in. This
164 directory will be auto-created for you if it doesn't exist.
166 OPAC Directory [%s]: |;
168 $messages->{'GetIntranetDir'}->{en} =
169 heading('INTRANET/LIBRARIANS DIRECTORY') . qq|
170 Please supply the directory you want Koha to store its Intranet/Librarians
171 files in. This directory will be auto-created for you if it doesn't exist.
173 Intranet Directory [%s]: |;
175 $messages->{'GetKohaLogDir'}->{en} = heading('KOHA LOG DIRECTORY') . qq|
176 Specify a log directory where any Koha daemons can create log files.
178 Koha Log Directory [%s]: |;
180 $messages->{'AuthenticationWarning'}->{en} = heading('Authentication') . qq|
181 This release of Koha has a new authentication module. If you are not already
182 using basic authentication on your intranet, you will be required to log in to
183 access some of the features of the intranet. You can log in using the userid
184 and password from the %s/koha.conf configuration file at any time. Use the
185 "Members" module to add passwords for other accounts and set their permissions.
187 Press the <ENTER> key to continue: |;
189 $messages->{'Completed'}->{en} = heading('KOHA INSTALLATION COMPLETE') . qq|
190 Congratulations ... your Koha installation is complete!
192 You will be able to connect to your Librarian interface at:
196 and the OPAC interface at :
200 Be sure to read the INSTALL, and Hints files.
202 For more information visit http://www.koha.org
204 Press <ENTER> to exit the installer: |;
206 sub releasecandidatewarning {
207 my $message=getmessage('ReleaseCandidateWarning', [$::newversion, $::newversion]);
208 my $answer=showmessage($message, 'yn', 'n');
210 if ($answer =~ /y/i) {
211 print getmessage('continuing');
213 my $message=getmessage('WatchForReleaseAnnouncements');
222 =head2 Miscellaneous utility functions
232 Does the equivalent of dirname(1). Given a path $path, return the
233 parent directory of $path (best guess), except when $path seems to
234 be the same as /, in which case $path itself is returned unchanged.
240 if ($path =~ /[^\/]/s) {
242 $path =~ s/\/+[^\/]+\/*$//s;
253 mkdir_parents $path, $mode;
255 Does the equivalent of mkdir -p, or mkdir --parents. Given a path $path,
256 create the directory $path, recursively creating any intermediate
257 directories. If $mode is given, the directory will be created with
260 WARNING: If $path already exists, mkdir_parents will just return
261 successfully (just like mkdir -p), whether the mode of $path conforms
262 to $mode or not. (This is the behaviour of the mkdir -p command.)
266 sub mkdir_parents ($;$) {
267 my($path, $mode) = @_;
268 my $ok = -d($path)? 1: defined $mode? mkdir($path, $mode): mkdir($path);
270 if (!$ok && $! == ENOENT) {
271 my $parent = dirname($path);
272 $ok = mkdir_parents($parent, $mode);
274 # retry and at the same time make sure that $! is set correctly
275 $ok = defined $mode? mkdir($path, $mode): mkdir($path);
282 =head2 Subtasks of doing an installation
288 =item checkabortedinstall
292 Checks whether a previous installation process has been abnormally
293 aborted, by checking whether $::etcidr/koha.conf is a symlink or not.
294 If an aborted installation is detected, gives the user a chance to
295 abort, before trying to recover the aborted installation.
297 (Assuming that Koha will be installed on a modern Unix with symlinks,
298 it is possible to code the installer so that aborted installs can be
299 detected. In case of such an event we can do our best to "roll back"
300 the aborted install.)
302 FIXME: The "roll back" is not complete!
306 sub checkabortedinstall () {
307 if (-l("$::etcdir/koha.conf")
308 && readlink("$::etcdir/koha.conf") =~ /\.tmp$/
311 I have detected that you tried to install Koha before, but the installation
312 was aborted. I will try to continue, but there might be problems if the
313 database is already created.
316 print "Please press <ENTER> to continue: ";
319 # Remove the symlink after the <STDIN>, so the user can back out
320 unlink "$::etcdir/koha.conf"
321 || die "Failed to remove incomplete $::etcdir/koha.conf: $!\n";
326 =item checkperlmodules
330 Test whether the version of Perl is new enough, whether Perl is
331 found at the expected location, and whether all required modules
336 sub checkperlmodules {
338 # Test for Perl and Modules
341 my $message = getmessage('CheckingPerlModules');
342 showmessage($message, 'none');
344 # FIXME: Perl 5.6 is BUGGY!!! IT SHOULD NOT BE USED in production!!!
345 unless (eval "require 5.006_000") {
346 die getmessage('PerlVersionFailure', ['5.6.0']);
350 unless (eval {require DBI}) { push @missing,"DBI" };
351 unless (eval {require Date::Manip}) { push @missing,"Date::Manip" };
352 unless (eval {require DBD::mysql}) { push @missing,"DBD::mysql" };
353 unless (eval {require HTML::Template}) { push @missing,"HTML::Template" };
354 unless (eval {require Set::Scalar}) { push @missing,"Set::Scalar" };
355 unless (eval {require Digest::MD5}) { push @missing,"Digest::MD5" };
356 unless (eval {require MARC::Record}) { push @missing,"MARC::Record" };
357 unless (eval {require Net::Z3950}) {
358 my $message = getmessage('NETZ3950Missing');
359 showmessage($message, 'PressEnter', '', 1);
361 push @missing, "Net::Z3950";
366 # Print out a list of any missing modules
371 foreach my $module (@missing) {
372 $missing.=" perl -MCPAN -e 'install \"$module\"'\n";
374 my $message=getmessage('MissingPerlModules', [$missing]);
375 showmessage($message, 'none');
378 showmessage(getmessage('AllPerlModulesInstalled'), 'PressEnter', '', 1);
382 unless (-x "/usr/bin/perl") {
383 my $realperl=`which perl`;
385 $realperl = showmessage(getmessage('NoUsrBinPerl'), 'none');
386 until (-x $realperl) {
387 $realperl=showmessage(getmessage('AskLocationOfPerlExecutable', $realperl), 'free', $realperl, 1);
389 my $response=showmessage(getmessage('ConfirmPerlExecutableSymlink', $realperl), 'yn', 'y', 1);
390 unless ($response eq 'n') {
391 system("ln -s $realperl /usr/bin/perl");
398 $messages->{'NoUsrBinPerl'}->{en} =
399 heading('Perl is not located in /usr/bin/perl') . qq|
400 The Koha perl scripts expect to find the perl executable in the /usr/bin
401 directory. It is not there on your system.
405 $messages->{'AskLocationOfPerlExecutable'}->{en}=qq|Location of Perl Executable: [%s]: |;
406 $messages->{'ConfirmPerlExecutableSymlink'}->{en}=qq|
407 The Koha scripts will _not_ work without a symlink from %s to /usr/bin/perl
409 May I create this symlink? ([Y]/N):
416 getmessage($msgid, $variables);
418 Gets a localized message (format string) with message id $msgid,
419 and, if an array reference of variables $variables is given,
420 substitutes variables in the format string with @$variables.
421 Returns the found message string, with variable substitutions
424 $msgid must be the message identifier corresponding to a defined
425 message string (a valid key to the $messages hash in the Installer
426 package). getmessage throws an exception if the message cannot be
432 my $messagename=shift;
434 my $message=$messages->{$messagename}->{$::language} || $messages->{$messagename}->{en} || "Error: No message named $messagename in Install.pm\n";
435 if (defined($variables)) {
436 $message=sprintf $message, @$variables;
444 showmessage($message, 'none');
445 showmessage($message, 'none', undef, $noclear);
447 $result = showmessage($message, 'yn');
448 $result = showmessage($message, 'yn', $defaultresponse);
449 $result = showmessage($message, 'yn', $defaultresponse, $noclear);
451 $result = showmessage($message, 'restrictchar CHARS');
452 $result = showmessage($message, 'free');
453 $result = showmessage($message, 'numerical');
454 $result = showmessage($message, 'email');
455 $result = showmessage($message, 'PressEnter');
457 Shows a message and optionally gets a response from the user.
459 The first two arguments, the message and the response type,
460 are mandatory. The message must be the actual string to
461 display. The caller is responsible for calling getmessage if
464 The response type must be one of "none", "yn", "free",
465 "numerical", "email", "PressEnter", or a string consisting
466 of "restrictchar " followed by a list of allowed characters
467 (space can be specified). (Case is not significant, but case is
468 significant in the list of allowed characters.) If a response
469 type other than the above-listed is specified, the result is
472 If a response type other than "none" or "PressEnter" is
473 specified, a third argument, specifying the default value, can
474 be specified: If this default response is not specified, the
475 default response is the first allowed character if the response
476 type is "restrictchar", otherwise the default response is the
477 empty string. This default response is used when the user does
478 not specify a value (i.e., presses Enter without typing in
479 anything), showmessage will assume that the default response is
482 The screen is normally cleared before the message is displayed;
483 if a fourth argument is specified and is nonzero, this
484 screen-clearing is not done.
486 FIXME: A default response of "0" cannot be specified. This is
487 wrong; the default response should be checked for undef, not
490 FIXME: If $noclear is not specified or specified as undef, we
491 just test it for a non-zero value without testing it for being
498 my $responsetype=shift;
499 my $defaultresponse=shift;
501 ($noclear) || (system('clear'));
502 if ($responsetype =~ /^yn$/) {
503 $responsetype='restrictchar yn';
507 if ($responsetype =~/^restrictchar (.*)/i) {
510 until ($options=~/$response/) {
511 ($defaultresponse) || ($defaultresponse=substr($options,0,1));
514 (length($response)) || ($response=$defaultresponse);
515 unless ($options=~/$response/) {
516 ($noclear) || (system('clear'));
517 print "Invalid Response. Choose from [$options].\n\n";
523 if ($responsetype =~/^free$/i) {
524 (defined($defaultresponse)) || ($defaultresponse='');
525 my $response=<STDIN>;
527 ($response) || ($response=$defaultresponse);
530 if ($responsetype =~/^numerical$/i) {
531 (defined($defaultresponse)) || ($defaultresponse='');
533 until ($response=~/^\d+$/) {
536 ($response) || ($response=$defaultresponse);
537 unless ($response=~/^\d+$/) {
538 ($noclear) || (system('clear'));
539 print "Invalid Response ($response). Response must be a number.\n\n";
545 if ($responsetype =~/^email$/i) {
546 (defined($defaultresponse)) || ($defaultresponse='');
548 until ($response=~/.*\@.*\..*/) {
551 ($response) || ($response=$defaultresponse);
552 unless ($response=~/.*\@.*\..*/) {
553 ($noclear) || (system('clear'));
554 print "Invalid Response ($response). Response must be a valid email address.\n\n";
560 if ($responsetype =~/^PressEnter$/i) {
564 if ($responsetype =~/^none$/i) {
571 =item getinstallationdirectories
573 getinstallationdirectories;
575 Get the various installation directories from the user, and then
576 create those directories (if they do not already exist).
578 These pieces of information are saved to global variables; the
579 function does not return any values.
583 sub getinstallationdirectories {
584 $::opacdir = '/usr/local/koha/opac';
585 $::intranetdir = '/usr/local/koha/intranet';
587 while ($getdirinfo) {
588 # Loop until opac directory and koha directory are different
589 my $message=getmessage('GetOpacDir', [$::opacdir]);
590 $::opacdir=showmessage($message, 'free', $::opacdir);
592 $message=getmessage('GetIntranetDir', [$::intranetdir]);
593 $::intranetdir=showmessage($message, 'free', $::intranetdir);
595 if ($::intranetdir eq $::opacdir) {
598 You must specify different directories for the OPAC and INTRANET files!
599 :: $::intranetdir :: $::opacdir ::
606 $::kohalogdir='/var/log/koha';
607 my $message=getmessage('GetKohaLogDir', [$::kohalogdir]);
608 $::kohalogdir=showmessage($message, 'free', $::kohalogdir);
611 # FIXME: Missing error handling for all mkdir calls here
612 unless ( -d $::intranetdir ) {
613 mkdir_parents (dirname($::intranetdir), 0775);
614 mkdir ($::intranetdir, 0770);
615 chown (oct(0), (getgrnam($::httpduser))[2], "$::intranetdir");
616 chmod (oct(770), "$::intranetdir");
618 mkdir_parents ("$::intranetdir/htdocs", 0750);
619 mkdir_parents ("$::intranetdir/cgi-bin", 0750);
620 mkdir_parents ("$::intranetdir/modules", 0750);
621 mkdir_parents ("$::intranetdir/scripts", 0750);
622 unless ( -d $::opacdir ) {
623 mkdir_parents (dirname($::opacdir), 0775);
624 mkdir ($::opacdir, 0770);
625 chown (oct(0), (getgrnam($::httpduser))[2], "$::opacdir");
626 chmod (oct(770), "$::opacdir");
628 mkdir_parents ("$::opacdir/htdocs", 0750);
629 mkdir_parents ("$::opacdir/cgi-bin", 0750);
632 unless ( -d $::kohalogdir ) {
633 mkdir_parents (dirname($::kohalogdir), 0775);
634 mkdir ($::kohalogdir, 0770);
635 chown (oct(0), (getgrnam($::httpduser))[2,3], "$::kohalogdir");
636 chmod (oct(770), "$::kohalogdir");
642 =item getdatabaseinfo
646 Get various pieces of information related to the Koha database:
647 the name of the database, the host on which the SQL server is
648 running, and the database user name.
650 These pieces of information are saved to global variables; the
651 function does not return any values.
655 $messages->{'DatabaseName'}->{en} = heading('Name of MySQL database') . qq|
656 Please provide the name of the mysql database for your koha installation.
658 Database name [%s]: |;
660 $messages->{'DatabaseHost'}->{en} = heading('Database Host') . qq|
661 Please provide the hostname for mysql. Unless the database is located on
662 another machine this will be "localhost".
664 Database host [%s]: |;
666 $messages->{'DatabaseUser'}->{en} = heading('Database User') . qq|
667 Please provide the name of the user, who will have full administrative rights
668 to the %s database, when authenticating from %s.
670 This user will also be used to access Koha's INTRANET interface.
672 Database user [%s]: |;
674 $messages->{'DatabasePassword'}->{en} = heading('Database Password') . qq|
675 Please provide a good password for the user %s.
677 Database Password: |;
679 $messages->{'BlankPassword'}->{en} = heading('BLANK PASSWORD') . qq|
680 You must not use a blank password for your MySQL user!
682 Press <ENTER> to try again:
685 sub getdatabaseinfo {
688 $::hostname = 'localhost';
689 $::user = 'kohaadmin';
692 #Get the database name
694 my $message=getmessage('DatabaseName', [$::dbname]);
695 $::dbname=showmessage($message, 'free', $::dbname);
697 #Get the hostname for the database
699 $message=getmessage('DatabaseHost', [$::hostname]);
700 $::hostname=showmessage($message, 'free', $::hostname);
702 #Get the username for the database
704 $message=getmessage('DatabaseUser', [$::dbname, $::hostname, $::user]);
705 $::user=showmessage($message, 'free', $::user);
707 #Get the password for the database user
709 while ($::pass eq '') {
710 my $message=getmessage('DatabasePassword', [$::user]);
711 $::pass=showmessage($message, 'free', $::pass);
713 my $message=getmessage('BlankPassword');
714 showmessage($message,'PressEnter');
725 Get various pieces of information related to the Apache server:
726 the location of the configuration file and, if needed, the Unix
727 user that the Koha CGI will be run under.
729 These pieces of information are saved to global variables; the
730 function does not return any values.
734 $messages->{'FoundMultipleApacheConfFiles'}->{en} =
735 heading('MULTIPLE APACHE CONFIG FILES') . qq|
736 I found more than one possible Apache configuration file:
740 Choose the correct file [1]: |;
742 $messages->{'NoApacheConfFiles'}->{en} =
743 heading('NO APACHE CONFIG FILE FOUND') . qq|
744 I was not able to find your Apache configuration file.
746 The file is usually called httpd.conf or apache.conf.
748 Please specify the location of your config file: |;
750 $messages->{'NotAFile'}->{en} = heading('FILE DOES NOT EXIST') . qq|
751 The file %s does not exist.
753 Please press <ENTER> to continue: |;
755 $messages->{'EnterApacheUser'}->{en} = heading('NEED APACHE USER') . qq|
756 I was not able to determine the user that Apache is running as. This
757 information is necessary in order to set the access privileges correctly on
758 %s/koha.conf. This user should be set in one of the Apache configuration
759 files using the "User" directive.
761 Enter the Apache userid: |;
763 $messages->{'InvalidUserid'}->{en} = heading('INVALID USERID') . qq|
764 The userid %s is not a valid userid on this system.
766 Press <ENTER> to continue: |;
769 my @confpossibilities;
771 foreach my $httpdconf (qw(/usr/local/apache/conf/httpd.conf
772 /usr/local/etc/apache/httpd.conf
773 /usr/local/etc/apache/apache.conf
774 /var/www/conf/httpd.conf
775 /etc/apache/conf/httpd.conf
776 /etc/apache/conf/apache.conf
777 /etc/apache-ssl/conf/apache.conf
778 /etc/apache-ssl/httpd.conf
779 /etc/httpd/conf/httpd.conf
780 /etc/httpd/httpd.conf)) {
781 if ( -f $httpdconf ) {
782 push @confpossibilities, $httpdconf;
786 if ($#confpossibilities==-1) {
787 my $message=getmessage('NoApacheConfFiles');
789 until (-f $::realhttpdconf) {
790 $choice=showmessage($message, "free", 1);
792 $::realhttpdconf=$choice;
794 showmessage(getmessage('NotAFile', [$choice]),'PressEnter', '', 1);
797 } elsif ($#confpossibilities>0) {
801 foreach (@confpossibilities) {
802 $conffiles.=" $counter: $_\n";
803 $options.="$counter";
806 my $message=getmessage('FoundMultipleApacheConfFiles', [$conffiles]);
807 my $choice=showmessage($message, "restrictchar $options", 1);
808 $::realhttpdconf=$confpossibilities[$choice-1];
810 $::realhttpdconf=$confpossibilities[0];
812 unless (open (HTTPDCONF, "<$::realhttpdconf")) {
813 warn "Insufficient privileges to open $::realhttpdconf for reading.\n";
817 while (<HTTPDCONF>) {
818 if (/^\s*User\s+"?([-\w]+)"?\s*$/) {
827 unless ($::httpduser) {
828 my $message=getmessage('EnterApacheUser', [$::etcdir]);
829 until (length($::httpduser) && getpwnam($::httpduser)) {
830 $::httpduser=showmessage($message, "free", '');
831 if (length($::httpduser)>0) {
832 unless (getpwnam($::httpduser)) {
833 my $message=getmessage('InvalidUserid', [$::httpduser]);
834 showmessage($message,'PressEnter');
839 print "AU: $::httpduser\n";
844 $messages->{'ApacheConfigIntroduction'}->{en} =
845 heading('APACHE CONFIGURATION') . qq|
846 Koha needs to setup your Apache configuration file for the
847 OPAC and LIBRARIAN virtual hosts. By default this installer
848 will do this by using one ip address and two different ports
849 for the virtual hosts. There are other ways to set this up,
850 and the installer will leave comments in httpd.conf detailing
851 what these other options are.
854 Press <ENTER> to continue: |;
856 $messages->{'GetVirtualHostEmail'}->{en} =
857 heading('WEB SERVER E-MAIL CONTACT') . qq|
858 Enter the e-mail address to be used as a contact for the virtual hosts (this
859 address is displayed if any errors are encountered).
861 E-mail contact [%s]: |;
863 $messages->{'GetServerName'}->{en} =
864 heading('WEB SERVER HOST NAME OR IP ADDRESS') . qq|
865 Please enter the domain name or ip address of your computer.
867 Host name or IP Address [%s]: |;
869 $messages->{'GetOpacPort'}->{en} = heading('OPAC VIRTUAL HOST PORT') . qq|
870 Please enter the port for your OPAC interface. This defaults to port 80, but
871 if you are already serving web content from this server, you should change it
872 to a different port (8000 might be a good choice).
874 Enter the OPAC Port [%s]: |;
876 $messages->{'GetIntranetPort'}->{en} =
877 heading('INTRANET VIRTUAL HOST PORT') . qq|
878 Please enter the port for your Intranet interface. This must be different from
881 Enter the Intranet Port [%s]: |;
884 sub getapachevhostinfo {
886 $::svr_admin = "webmaster\@$::domainname";
887 $::servername=`hostname`;
890 $::intranetport=8080;
892 showmessage(getmessage('ApacheConfigIntroduction'), 'PressEnter');
894 $::svr_admin=showmessage(getmessage('GetVirtualHostEmail', [$::svr_admin]), 'email', $::svr_admin);
895 $::servername=showmessage(getmessage('GetServerName', [$::servername]), 'free', $::servername);
898 $::opacport=showmessage(getmessage('GetOpacPort', [$::opacport]), 'numerical', $::opacport);
899 $::intranetport=showmessage(getmessage('GetIntranetPort', [$::opacport, $::intranetport]), 'numerical', $::intranetport);
903 $messages->{'StartUpdateApache'}->{en} =
904 heading('UPDATING APACHE CONFIGURATION') . qq|
905 Checking for modules that need to be loaded...
908 $messages->{'LoadingApacheModuleModEnv'}->{en}="Loading SetEnv Apache module.\n";
910 $messages->{'LoadingApacheModuleModInc'}->{en}="Loading Includes Apache module.\n";
912 $messages->{'ApacheConfigBackupFailed'}->{en} =
913 heading('APACHE CONFIGURATION BACKUP FAILED') . qq|
914 An error occurred while trying to make a backup copy of %s.
918 No changes will be made to the apache configuration file at this time.
920 Press <ENTER> to continue: |;
923 $messages->{'ApacheAlreadyConfigured'}->{en} =
924 heading('APACHE ALREADY CONFIGURED') . qq|
925 %s appears to already have an entry for Koha
926 Virtual Hosts. You may need to edit %s
927 f anything has changed since it was last set up. This
928 script will not attempt to modify an existing Koha apache
931 Press <ENTER> to continue: |;
933 sub updateapacheconf {
934 my $logfiledir=`grep ^ErrorLog "$::realhttpdconf"`;
938 $logfiledir=~m#ErrorLog (.*)/[^/]*$#
939 or die "Can't parse ErrorLog directive\n";
943 unless ($logfiledir) {
947 showmessage(getmessage('StartUpdateApache'), 'none');
951 my $includesmodule=0;
952 open HC, "<$::realhttpdconf";
954 if (/^\s*#\s*LoadModule env_module /) {
956 showmessage(getmessage('LoadingApacheModuleModEnv'));
959 if (/^\s*#\s*LoadModule includes_module /) {
961 showmessage(getmessage('LoadingApacheModuleModInc'));
963 if (/\s*LoadModule includes_module / ) {
970 $backupfailed=`cp -f $::realhttpdconf $::realhttpdconf\.prekoha`;
972 showmessage(getmessage('ApacheConfigBackupFailed', [$::realhttpdconf,$backupfailed ]), 'PressEnter');
976 if ($envmodule || $includesmodule) {
977 open HC, ">$::realhttpdconf";
984 if (`grep 'VirtualHost $::servername' "$::realhttpdconf"`) {
985 showmessage(getmessage('ApacheAlreadyConfigured', [$::realhttpdconf, $::realhttpdconf]), 'PressEnter');
988 my $includesdirectives='';
989 if ($includesmodule) {
990 $includesdirectives.="Options +Includes\n";
991 $includesdirectives.=" AddHandler server-parsed .html\n";
993 open(SITE,">>$::realhttpdconf") or warn "Insufficient priveleges to open $::realhttpdconf for writing.\n";
995 if ($::opacport != 80) {
996 $opaclisten="Listen $::opacport";
998 my $intranetlisten = '';
999 if ($::intranetport != 80) {
1000 $intranetlisten="Listen $::intranetport";
1004 # Ports to listen to for Koha
1008 # NameVirtualHost is used by one of the optional configurations detailed below
1010 #NameVirtualHost 11.22.33.44
1012 # KOHA's OPAC Configuration
1013 <VirtualHost $::servername\:$::opacport>
1014 ServerAdmin $::svr_admin
1015 DocumentRoot $::opacdir/htdocs
1016 ServerName $::servername
1017 ScriptAlias /cgi-bin/koha/ $::opacdir/cgi-bin/
1018 ErrorLog $logfiledir/opac-error_log
1019 TransferLog $logfiledir/opac-access_log
1020 SetEnv PERL5LIB "$::intranetdir/modules"
1024 # KOHA's INTRANET Configuration
1025 <VirtualHost $::servername\:$::intranetport>
1026 ServerAdmin $::svr_admin
1027 DocumentRoot $::intranetdir/htdocs
1028 ServerName $::servername
1029 ScriptAlias /cgi-bin/koha/ "$::intranetdir/cgi-bin/"
1030 ErrorLog $logfiledir/koha-error_log
1031 TransferLog $logfiledir/koha-access_log
1032 SetEnv PERL5LIB "$::intranetdir/modules"
1036 # If you want to use name based Virtual Hosting:
1037 # 1. remove the two Listen lines
1038 # 2. replace $::servername\:$::opacport wih your.opac.domain.name
1039 # 3. replace ServerName $::servername wih ServerName your.opac.domain.name
1040 # 4. replace $::servername\:$::intranetport wih your intranet domain name
1041 # 5. replace ServerName $::servername wih ServerName your.intranet.domain.name
1043 # If you want to use NameVirtualHost'ing (using two names on one ip address):
1044 # 1. Follow steps 1-5 above
1045 # 2. Uncomment the NameVirtualHost line and set the correct ip address
1053 $messages->{'IntranetAuthenticationQuestion'}->{en} =
1054 heading('INTRANET AUTHENTICATION') . qq|
1055 I can set it up so that the Intranet/Librarian site is password protected using
1056 Apache's Basic Authorization.
1058 This is going to be phased out very soon. However, setting this up can provide
1059 an extra layer of security before the new authentication system is completely
1062 Would you like to do this ([Y]/N): |;
1064 $messages->{'BasicAuthUsername'}->{en}="Please enter a userid for intranet access [%s]: ";
1065 $messages->{'BasicAuthPassword'}->{en}="Please enter a password for %s: ";
1066 $messages->{'BasicAuthPasswordWasBlank'}->{en}="\nYou cannot use a blank password!\n\n";
1068 sub basicauthentication {
1069 my $message=getmessage('IntranetAuthenticationQuestion');
1070 my $answer=showmessage($message, 'yn', 'y');
1072 my $apacheauthusername='librarian';
1073 my $apacheauthpassword='';
1074 if ($answer=~/^y/i) {
1075 ($apacheauthusername) = showmessage(getmessage('BasicAuthUsername', [ $apacheauthusername]), 'free', $apacheauthusername, 1);
1076 $apacheauthusername=~s/[^a-zA-Z0-9]//g;
1077 while (! $apacheauthpassword) {
1078 ($apacheauthpassword) = showmessage(getmessage('BasicAuthPassword', [ $apacheauthusername]), 'free', 1);
1079 if (!$apacheauthpassword) {
1080 ($apacheauthpassword) = showmessage(getmessage('BasicAuthPasswordWasBlank'), 'none', '', 1);
1083 open AUTH, ">$::etcdir/kohaintranet.pass";
1084 my $chars='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
1085 my $salt=substr($chars, int(rand(length($chars))),1);
1086 $salt.=substr($chars, int(rand(length($chars))),1);
1087 print AUTH $apacheauthusername.":".crypt($apacheauthpassword, $salt)."\n";
1089 open(SITE,">>$::realhttpdconf") or warn "Insufficient priveleges to open $::realhttpdconf for writing.\n";
1092 <Directory $::intranetdir>
1093 AuthUserFile $::etcdir/kohaintranet.pass
1095 AuthName "Koha Intranet (for librarians only)"
1103 $messages->{'InstallFiles'}->{en} = heading('INSTALLING FILES') . qq|
1104 Copying files to installation directories:
1109 $messages->{'CopyingFiles'}->{en}="Copying %s to %s.\n";
1116 showmessage(getmessage('InstallFiles'),'none');
1117 print getmessage('CopyingFiles', ['intranet-html', "$::intranetdir/htdocs" ]);
1118 system("cp -R intranet-html/* $::intranetdir/htdocs/");
1119 print getmessage('CopyingFiles', ['intranet-cgi', "$::intranetdir/cgi-bin" ]);
1120 system("cp -R intranet-cgi/* $::intranetdir/cgi-bin/");
1121 print getmessage('CopyingFiles', ['stand-alone scripts', "$::intranetdir/scripts" ]);
1122 system("cp -R scripts/* $::intranetdir/scripts/");
1123 print getmessage('CopyingFiles', ['perl modules', "$::intranetdir/modules" ]);
1124 system("cp -R modules/* $::intranetdir/modules/");
1125 print getmessage('CopyingFiles', ['opac-html', "$::opacdir/htdocs" ]);
1126 system("cp -R opac-html/* $::opacdir/htdocs/");
1127 print getmessage('CopyingFiles', ['opac-cgi', "$::opacdir/cgi-bin" ]);
1128 system("cp -R opac-cgi/* $::opacdir/cgi-bin/");
1129 system("touch $::opacdir/cgi-bin/opac");
1131 system("chown -R root:$::httpduser $::opacdir");
1132 system("chown -R root:$::httpduser $::intranetdir");
1134 # Create /etc/koha.conf
1136 my $old_umask = umask(027); # make sure koha.conf is never world-readable
1137 open(SITES,">$::etcdir/koha.conf.tmp") or warn "Couldn't create file at $::etcdir. Must have write capability.\n";
1140 hostname=$::hostname
1143 includes=$::opacdir/htdocs/includes
1144 intranetdir=$::intranetdir
1146 kohalogdir=$::kohalogdir
1147 kohaversion=$::kohaversion
1148 httpduser=$::httpduser
1149 intrahtdocs=$::intranetdir/htdocs/intranet-tmpl
1150 opachtdocs=$::opacdir/htdocs/opac-tmpl
1155 chown((getpwnam($::httpduser)) [2,3], "$::etcdir/koha.conf.tmp") or warn "can't chown koha.conf: $!";
1156 chmod 0440, "$::etcdir/koha.conf.tmp";
1158 chmod 0750, "$::intranetdir/scripts/z3950daemon/z3950-daemon-launch.sh";
1159 chmod 0750, "$::intranetdir/scripts/z3950daemon/z3950-daemon-shell.sh";
1160 chmod 0750, "$::intranetdir/scripts/z3950daemon/processz3950queue";
1161 chown(0, (getpwnam($::httpduser)) [3], "$::intranetdir/scripts/z3950daemon/z3950-daemon-shell.sh") or warn "can't chown $::intranetdir/scripts/z3950daemon/z3950-daemon-shell.sh: $!";
1162 chown(0, (getpwnam($::httpduser)) [3], "$::intranetdir/scripts/z3950daemon/processz3950queue") or warn "can't chown $::intranetdir/scripts/z3950daemon/processz3950queue: $!";
1166 $messages->{'MysqlRootPassword'}->{en} =
1167 heading('MYSQL ROOT USER PASSWORD') . qq|
1168 To allow us to create the koha database please supply your
1169 mysql server's root user password:
1171 Enter MySQL root user password: |;
1173 $messages->{'InvalidMysqlRootPassword'}->{en}="Invalid Password. Please try again.";
1175 $messages->{'CreatingDatabase'}->{en} = heading('CREATING DATABASE') . qq|
1176 Creating the MySQL database for Koha...
1180 $messages->{'CreatingDatabaseError'}->{en} =
1181 heading('ERROR CREATING DATABASE') . qq|
1182 Couldn't connect to the MySQL server for the reason given above.
1183 This is a serious problem, the database will not get installed.
\a
1185 Press <ENTER> to continue: |;
1187 $messages->{'SampleData'}->{en} = heading('SAMPLE DATA') . qq|
1188 If you are installing Koha for evaluation purposes, I have a batch of sample
1189 data that you can install now.
1191 If you are installing Koha with the intention of populating it with your own
1192 data, you probably don't want this sample data installed.
1194 Would you like to install the sample data? Y/[N]: |;
1196 $messages->{'SampleDataInstalled'}->{en} =
1197 heading('SAMPLE DATA INSTALLED') . qq|
1198 Sample data has been installed. For some suggestions on testing Koha, please
1199 read the file doc/HOWTO-Testing. If you find any bugs, please submit them at
1200 http://bugs.koha.org/. If you need help with testing Koha, you can post a
1201 question through the koha-devel mailing list, or you can check for a developer
1202 online at +irc.katipo.co.nz:6667 channel #koha.
1204 You can find instructions for subscribing to the Koha mailing lists at:
1209 Press <ENTER> to continue: |;
1211 $messages->{'AddBranchPrinter'}->{en} = heading('Add Branch and Printer') . qq|
1212 Would you like to install an initial branch and printer? [Y]/N: |;
1214 $messages->{'BranchName'}->{en}="Branch Name [%s]: ";
1215 $messages->{'BranchCode'}->{en}="Branch Code (4 letters or numbers) [%s]: ";
1216 $messages->{'PrinterQueue'}->{en}="Printer Queue [%s]: ";
1217 $messages->{'PrinterName'}->{en}="Printer Name [%s]: ";
1218 $messages->{'BlankMysqlPassword'}->{en} = heading('Blank MySQL Password') . qq|
1219 Do not leave your MySQL root password blank unless you know exactly what you
1220 are doing. To change your MySQL root password use the mysqladmin command:
1222 mysqladmin password NEWPASSWORDHERE
1224 Press <ENTER> to continue:
1228 $::mysqluser = 'root';
1231 foreach my $mysql (qw(/usr/local/mysql
1235 if ( -d $mysql && -f "$mysql/bin/mysqladmin") {
1240 print "I don't see mysql in the usual places.\n";
1242 print "Where have you installed mysql? ";
1243 chomp($::mysqldir = <STDIN>);
1244 last if -f "$::mysqldir/bin/mysqladmin";
1247 I can't find it there either. If you compiled mysql yourself,
1248 please give the value of --prefix when you ran configure.
1250 The file mysqladmin should be in bin/mysqladmin under the directory that you
1259 while ($needpassword) {
1260 $::mysqlpass=showmessage(getmessage('MysqlRootPassword'), 'free');
1261 $::mysqlpass_quoted = $::mysqlpass;
1262 $::mysqlpass_quoted =~ s/"/\\"/g;
1263 $::mysqlpass_quoted="-p\"$::mysqlpass_quoted\"";
1264 $::mysqlpass eq '' and $::mysqlpass_quoted='';
1265 my $result=system("$::mysqldir/bin/mysqladmin -u$::mysqluser $::mysqlpass_quoted proc > /dev/null 2>&1");
1267 print getmessage('InvalidMysqlRootPassword');
1269 if ($::mysqlpass eq '') {
1270 showmessage(getmessage('BlankMysqlPassword'), 'PressEnter');
1276 showmessage(getmessage('CreatingDatabase'),'none');
1278 my $result=system("$::mysqldir/bin/mysqladmin", "-u$::mysqluser", "-p$::mysqlpass", "create", "$::dbname");
1280 showmessage(getmessage('CreatingDatabaseError'),'PressEnter', '', 1);
1282 # Populate the Koha database
1283 system("$::mysqldir/bin/mysql -u$::mysqluser $::mysqlpass_quoted $::dbname < koha.mysql");
1284 # Set up permissions
1285 system("$::mysqldir/bin/mysql -u$::mysqluser $::mysqlpass_quoted mysql -e \"insert into user (Host,User,Password) values ('$::hostname','$::user',password('$::pass'))\"\;");
1286 system("$::mysqldir/bin/mysql -u$::mysqluser $::mysqlpass_quoted mysql -e \"insert into db (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv, index_priv, alter_priv) values ('%','$::dbname','$::user','Y','Y','Y','Y','Y','Y','Y','Y')\"");
1287 system("$::mysqldir/bin/mysqladmin -u$::mysqluser $::mysqlpass_quoted reload");
1297 $messages->{'UpdateMarcTables'}->{en} =
1298 heading('UPDATING MARC FIELD DEFINITION TABLES') . qq|
1299 You can import marc parameters for :
1305 Please choose which parameter you want to install. Note if you choose 3,
1306 nothing will be added, and it can be a BIG job to manually create those tables
1308 Choose MARC definition [1]: |;
1310 $messages->{'Language'}->{en} = heading('CHOOSE LANGUAGES') . qq|
1311 This version of koha supports a few languages.
1312 Enter you languages preferences : either en, fr, es or pl.
1313 Note that the en is always choosen when the system does not finds the
1314 language you choose in a specific screen.
1315 fr : opac is translated (except pictures)
1316 es : a few intranet is translated (including pictures)
1317 pl : opac is translated (UNTESTED in this release)
1320 sub updatedatabase {
1321 # At this point, $::etcdir/koha.conf must exist, for C4::Context
1322 # We must somehow temporarily enable $::etcdir/koha.conf. A symlink can
1323 # do this & at the same time facilitate detection of aborted installs.
1324 my $result=system ("perl -I $::intranetdir/modules scripts/updater/updatedatabase");
1326 print "Problem updating database...\n";
1330 my $response=showmessage(getmessage('UpdateMarcTables'), 'restrictchar 123', '1');
1332 if ($response == 1) {
1333 system("cat scripts/misc/marc_datas/marc21_en/structure_def.sql | $::mysqldir/bin/mysql -u$::mysqluser $::mysqlpass_quoted $::dbname");
1335 if ($response == 2) {
1336 system("cat scripts/misc/marc_datas/unimarc_fr/structure_def.sql | $::mysqldir/bin/mysql -u$::mysqluser $::mysqlpass_quoted $::dbname");
1337 system("cat scripts/misc/lang-datas/fr/stopwords.sql | $::mysqldir/bin/mysql -u$::mysqluser $::mysqlpass_quoted $::dbname");
1340 $result = system ("perl -I $::intranetdir/modules scripts/marc/updatedb2marc.pl");
1342 print "Problem updating database to MARC...\n";
1346 print "\n\nFinished updating of database. Press <ENTER> to continue...";
1350 sub populatedatabase {
1351 my $response=showmessage(getmessage('SampleData'), 'yn', 'n');
1352 if ($response =~/^y/i) {
1353 system("gunzip -d < sampledata-1.2.gz | $::mysqldir/bin/mysql -u$::mysqluser $::mysqlpass_quoted $::dbname");
1354 system("$::mysqldir/bin/mysql -u$::mysqluser $::mysqlpass_quoted $::dbname -e \"insert into branches (branchcode,branchname,issuing) values ('MAIN', 'Main Library', 1)\"");
1355 system("$::mysqldir/bin/mysql -u$::mysqluser $::mysqlpass_quoted $::dbname -e \"insert into branchrelations (branchcode,categorycode) values ('MAIN', 'IS')\"");
1356 system("$::mysqldir/bin/mysql -u$::mysqluser $::mysqlpass_quoted $::dbname -e \"insert into branchrelations (branchcode,categorycode) values ('MAIN', 'CU')\"");
1357 system("$::mysqldir/bin/mysql -u$::mysqluser $::mysqlpass_quoted $::dbname -e \"insert into printers (printername,printqueue,printtype) values ('Circulation Desk Printer', 'lp', 'hp')\"");
1358 showmessage(getmessage('SampleDataInstalled'), 'PressEnter','',1);
1361 my $response=showmessage(getmessage('AddBranchPrinter'), 'yn', 'y');
1363 unless ($response =~/^n/i) {
1364 my $branch='Main Library';
1365 $branch=showmessage(getmessage('BranchName', [$branch]), 'free', $branch, 1);
1366 $branch=~s/[^A-Za-z0-9\s]//g;
1368 my $branchcode=$branch;
1369 $branchcode=~s/[^A-Za-z0-9]//g;
1370 $branchcode=uc($branchcode);
1371 $branchcode=substr($branchcode,0,4);
1372 $branchcode=showmessage(getmessage('BranchCode', [$branchcode]), 'free', $branchcode, 1);
1373 $branchcode=~s/[^A-Za-z0-9]//g;
1374 $branchcode=uc($branchcode);
1375 $branchcode=substr($branchcode,0,4);
1376 $branchcode or $branchcode='DEF';
1378 system("$::mysqldir/bin/mysql -u$::mysqluser $::mysqlpass_quoted $::dbname -e \"insert into branches (branchcode,branchname,issuing) values ('$branchcode', '$branch', 1)\"");
1379 system("$::mysqldir/bin/mysql -u$::mysqluser $::mysqlpass_quoted $::dbname -e \"insert into branchrelations (branchcode,categorycode) values ('MAIN', 'IS')\"");
1380 system("$::mysqldir/bin/mysql -u$::mysqluser $::mysqlpass_quoted $::dbname -e \"insert into branchrelations (branchcode,categorycode) values ('MAIN', 'CU')\"");
1382 my $printername='Library Printer';
1383 $printername=showmessage(getmessage('PrinterName', [$printername]), 'free', $printername, 1);
1384 $printername=~s/[^A-Za-z0-9\s]//g;
1386 my $printerqueue='lp';
1387 $printerqueue=showmessage(getmessage('PrinterQueue', [$printerqueue]), 'free', $printerqueue, 1);
1388 $printerqueue=~s/[^A-Za-z0-9]//g;
1389 system("$::mysqldir/bin/mysql -u$::mysqluser $::mysqlpass_quoted $::dbname -e \"insert into printers (printername,printqueue,printtype) values ('$printername', '$printerqueue', '')\"");
1391 my $language=showmessage(getmessage('Language'), 'free', 'en');
1392 system("$::mysqldir/bin/mysql -u$::mysqluser $::mysqlpass_quoted $::dbname -e \"update systempreferences set value='$language' where variable='opaclanguages'\"");
1396 $messages->{'RestartApache'}->{en} = heading('RESTART APACHE') . qq|
1397 Apache needs to be restarted to load the new configuration for Koha.
1399 Would you like to restart Apache now? [Y]/N: |;
1403 my $response=showmessage(getmessage('RestartApache'), 'yn', 'y');
1407 unless ($response=~/^n/i) {
1408 # Need to support other init structures here?
1409 if (-e "/etc/rc.d/init.d/httpd") {
1410 system('/etc/rc.d/init.d/httpd restart');
1411 } elsif (-e "/etc/init.d/apache") {
1412 system('/etc//init.d/apache restart');
1413 } elsif (-e "/etc/init.d/apache-ssl") {
1414 system('/etc/init.d/apache-ssl restart');
1421 sub loadconfigfile {
1424 open (KC, "<$::etcdir/koha.conf");
1427 (next) if (/^\s*#/);
1428 if (/(.*)\s*=\s*(.*)/) {
1431 # Clean up white space at beginning and end
1432 $variable=~s/^\s*//g;
1433 $variable=~s/\s*$//g;
1436 $configfile{$variable}=$value;
1440 $::intranetdir=$configfile{'intranetdir'};
1441 $::opacdir=$configfile{'opacdir'};
1442 $::kohaversion=$configfile{'kohaversion'};
1443 $::kohalogdir=$configfile{'kohalogdir'};
1444 $::database=$configfile{'database'};
1445 $::hostname=$configfile{'hostname'};
1446 $::user=$configfile{'user'};
1447 $::pass=$configfile{'pass'};
1450 END { } # module clean-up code here (global destructor)
1456 A lot of variables like $::opacdir. Because Perl does not check
1457 for strictness when a package name is explicitly specified,
1458 using such variables defeats the purpose of "use strict".