#
# InspIRCd -- Internet Relay Chat Daemon
#
+# Copyright (C) 2020 Nicole Kleinhoff <ilbelkyr@shalture.org>
+# Copyright (C) 2020 Daniel Vassdal <shutter@canternet.org>
# Copyright (C) 2019 Matt Schatz <genius3000@g3k.solutions>
-# Copyright (C) 2019 Anatole Denis <natolumin@rezel.net>
-# Copyright (C) 2017 emerson <github@emersonveenstra.net>
-# Copyright (C) 2013-2019 Sadie Powell <sadie@witchery.services>
+# Copyright (C) 2013-2021 Sadie Powell <sadie@witchery.services>
# Copyright (C) 2012, 2019 Robby <robby@chatbelgie.be>
# Copyright (C) 2012 ChrisTX <xpipe@hotmail.de>
# Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org>
#
-BEGIN {
- require 5.10.0;
-}
-
-use feature ':5.10';
+use v5.10.0;
use strict;
use warnings FATAL => qw(all);
+use Cwd qw(getcwd);
use File::Basename qw(basename);
use File::Copy ();
-use File::Spec::Functions qw(rel2abs);
+use File::Spec::Functions qw(abs2rel catfile catdir rel2abs);
use FindBin qw($RealDir);
use Getopt::Long qw(GetOptions);
use POSIX qw(getgid getuid);
$opt_log_dir,
$opt_manual_dir,
$opt_module_dir,
+ $opt_portable,
$opt_prefix,
+ $opt_runtime_dir,
$opt_script_dir,
$opt_socketengine,
$opt_system,
'log-dir=s' => \$opt_log_dir,
'manual-dir=s' => \$opt_manual_dir,
'module-dir=s' => \$opt_module_dir,
+ 'portable' => \$opt_portable,
'prefix=s' => \$opt_prefix,
+ 'runtime-dir=s' => \$opt_runtime_dir,
'script-dir=s' => \$opt_script_dir,
'socketengine=s' => \$opt_socketengine,
'system' => \$opt_system,
'uid=s' => \$opt_uid,
- # TODO: when the modulemanager rewrite is done these should be removed.
'disable-extras=s@' => \@opt_disableextras,
'enable-extras=s@' => \@opt_enableextras,
'list-extras' => sub { list_extras; exit 0; },
);
if (scalar(@opt_enableextras) + scalar(@opt_disableextras) > 0) {
- @opt_enableextras = split /[, ]+/, join(',', @opt_enableextras);
- @opt_disableextras = split /[, ]+/, join(',', @opt_disableextras);
+ @opt_enableextras = grep { /\S/ } split /[, ]+/, join(',', @opt_enableextras);
+ @opt_disableextras = grep { /\S/ } split /[, ]+/, join(',', @opt_disableextras);
enable_extras(@opt_enableextras);
disable_extras(@opt_disableextras);
list_extras;
defined $opt_log_dir ||
defined $opt_manual_dir ||
defined $opt_module_dir ||
+ defined $opt_portable ||
defined $opt_prefix ||
+ defined $opt_runtime_dir ||
defined $opt_script_dir ||
defined $opt_socketengine ||
defined $opt_system ||
);
my %version = get_version $opt_distribution_label;
-print_format "<|BOLD Configuring InspIRCd $version{FULL} on $^O.|>\n";
+say console_format "<|BOLD Configuring InspIRCd $version{FULL} on $^O.|>";
my %config;
if ($interactive) {
%config = read_config_file(CONFIGURE_CACHE_FILE);
- run_test CONFIGURE_CACHE_FILE, %config;
+ run_test abs2rel(CONFIGURE_CACHE_FILE, $RealDir), %config;
if (!defined $config{VERSION}) {
$config{VERSION} = CONFIGURE_CACHE_VERSION;
} elsif ($config{VERSION} != CONFIGURE_CACHE_VERSION) {
}
$config{SOCKETENGINE} = $opt_socketengine // $socketengines[0];
-if (defined $opt_system) {
- $config{BASE_DIR} = $opt_prefix // '/var/lib/inspircd';
- $config{BINARY_DIR} = $opt_binary_dir // '/usr/sbin';
- $config{CONFIG_DIR} = $opt_config_dir // '/etc/inspircd';
- $config{DATA_DIR} = $opt_data_dir // '/var/inspircd';
- $config{EXAMPLE_DIR} = $opt_example_dir // '/usr/share/doc/inspircd';
- $config{LOG_DIR} = $opt_log_dir // '/var/log/inspircd';
- $config{MANUAL_DIR} = $opt_manual_dir // '/usr/share/man/man1';
- $config{MODULE_DIR} = $opt_module_dir // '/usr/lib/inspircd';
- $config{SCRIPT_DIR} = $opt_script_dir // '/usr/share/inspircd'
+if (defined $opt_portable) {
+ print_error '--portable and --system can not be used together!' if defined $opt_system;
+ $config{DESTDIR} = catfile $RealDir, 'run', '';
+ $config{BASE_DIR} = $opt_prefix // '';
+ $config{BINARY_DIR} = $opt_binary_dir // 'bin';
+ $config{CONFIG_DIR} = $opt_config_dir // 'conf';
+ $config{DATA_DIR} = $opt_data_dir // 'data';
+ $config{EXAMPLE_DIR} = $opt_example_dir // catdir $config{CONFIG_DIR}, 'examples';
+ $config{LOG_DIR} = $opt_log_dir // 'logs';
+ $config{MANUAL_DIR} = $opt_manual_dir // 'manuals';
+ $config{MODULE_DIR} = $opt_module_dir // 'modules';
+ $config{RUNTIME_DIR} = $opt_runtime_dir // $config{DATA_DIR};
+ $config{SCRIPT_DIR} = $opt_script_dir // $config{BASE_DIR};
+} elsif (defined $opt_system) {
+ $config{BASE_DIR} = $opt_prefix // '/';
+ $config{BINARY_DIR} = $opt_binary_dir // catdir $config{BASE_DIR}, 'usr/sbin';
+ $config{CONFIG_DIR} = $opt_config_dir // catdir $config{BASE_DIR}, 'etc/inspircd';
+ $config{DATA_DIR} = $opt_data_dir // catdir $config{BASE_DIR}, 'var/lib/inspircd';
+ $config{EXAMPLE_DIR} = $opt_example_dir // catdir $config{BASE_DIR}, 'usr/share/doc/inspircd';
+ $config{LOG_DIR} = $opt_log_dir // catdir $config{BASE_DIR}, 'var/log/inspircd';
+ $config{MANUAL_DIR} = $opt_manual_dir // catdir $config{BASE_DIR}, 'usr/share/man/man1';
+ $config{MODULE_DIR} = $opt_module_dir // catdir $config{BASE_DIR}, 'usr/lib/inspircd';
+ $config{RUNTIME_DIR} = $opt_runtime_dir // catdir $config{BASE_DIR}, 'var/run/inspircd';
+ $config{SCRIPT_DIR} = $opt_script_dir // catdir $config{BASE_DIR}, 'usr/share/inspircd';
} else {
- $config{BASE_DIR} = $opt_prefix // $config{BASE_DIR} // rel2abs 'run';
- $config{BINARY_DIR} = $opt_binary_dir // $config{BINARY_DIR} // rel2abs $config{BASE_DIR} . '/bin';
- $config{CONFIG_DIR} = $opt_config_dir // $config{CONFIG_DIR} // rel2abs $config{BASE_DIR} . '/conf';
- $config{DATA_DIR} = $opt_data_dir // $config{DATA_DIR} // rel2abs $config{BASE_DIR} . '/data';
- $config{EXAMPLE_DIR} = $opt_example_dir // $config{EXAMPLE_DIR} // $config{CONFIG_DIR} . '/examples';
- $config{LOG_DIR} = $opt_log_dir // $config{LOG_DIR} // rel2abs $config{BASE_DIR} . '/logs';
- $config{MANUAL_DIR} = $opt_manual_dir // $config{MANUAL_DIR} // rel2abs $config{BASE_DIR} . '/manuals';
- $config{MODULE_DIR} = $opt_module_dir // $config{MODULE_DIR} // rel2abs $config{BASE_DIR} . '/modules';
- $config{SCRIPT_DIR} = $opt_script_dir // $config{SCRIPT_DIR} // $config{BASE_DIR};
+ $config{BASE_DIR} = rel2abs $opt_prefix // $config{BASE_DIR} // catdir $RealDir, 'run';
+ $config{BINARY_DIR} = $opt_binary_dir // $config{BINARY_DIR} // catdir $config{BASE_DIR}, 'bin';
+ $config{CONFIG_DIR} = $opt_config_dir // $config{CONFIG_DIR} // catdir $config{BASE_DIR}, 'conf';
+ $config{DATA_DIR} = $opt_data_dir // $config{DATA_DIR} // catdir $config{BASE_DIR}, 'data';
+ $config{EXAMPLE_DIR} = $opt_example_dir // $config{EXAMPLE_DIR} // catdir $config{CONFIG_DIR}, 'examples';
+ $config{LOG_DIR} = $opt_log_dir // $config{LOG_DIR} // catdir $config{BASE_DIR}, 'logs';
+ $config{MANUAL_DIR} = $opt_manual_dir // $config{MANUAL_DIR} // catdir $config{BASE_DIR}, 'manuals';
+ $config{MODULE_DIR} = $opt_module_dir // $config{MODULE_DIR} // catdir $config{BASE_DIR}, 'modules';
+ $config{RUNTIME_DIR} = $opt_runtime_dir // $config{RUNTIME_DIR} // $config{DATA_DIR};
+ $config{SCRIPT_DIR} = $opt_script_dir // $config{SCRIPT_DIR} // $config{BASE_DIR};
}
# Parse --gid=123 or --gid=foo and extract the group id.
to specify an unprivileged group to run as.
EOW
if (!prompt_bool $interactive, "Are you sure you want to build as the $group[0] group?", 0) {
+ # PACKAGERS: You do not need to delete this check. Use `--gid $(id -g)` or `--gid 0` instead.
say STDERR "If you are sure you want to build as the $group[0] group pass the --gid $group[2] flag." unless $interactive;
exit 1;
}
to specify an unprivileged user to run as.
EOW
if (!prompt_bool $interactive, "Are you sure you want to build as the $user[0] user?", 0) {
+ # PACKAGERS: You do not need to delete this check. Use `--uid $(id -u)` or `--uid 0` instead.
say STDERR "If you are sure you want to build as the $user[0] user pass the --uid $user[2] flag." unless $interactive;
exit 1;
}
EOW
}
+# Warn about Perl versions that will not be supported in the future.
+if ($^V lt 'v5.26.0') {
+ print_warning <<"EOW";
+You are building InspIRCd with Perl $^V. This is very old and will
+not be supported by the next major version of InspIRCd. Please consider updating
+to Perl v5.26 or newer.
+EOW
+}
+
+# Warn about compiler versions that will not be supported in the future.
+my %future_compilers = (
+ AppleClang => version->parse('10.0'),
+ Clang => version->parse('5.0'),
+ GCC => version->parse('7.0'),
+);
+if (exists $future_compilers{$compiler{NAME}} && $compiler{VERSION} lt $future_compilers{$compiler{NAME}}) {
+ print_warning <<"EOW";
+You are building InspIRCd with $compiler{NAME} v$compiler{VERSION}. This is very old and
+will not be supported by the next major version of InspIRCd. Please consider
+updating to $compiler{NAME} v$future_compilers{$compiler{NAME}} or newer.
+EOW
+}
+
# Check that the user actually wants this version.
if (defined $version{REAL_LABEL}) {
print_warning <<'EOW';
my $question = <<"EOQ";
Currently, InspIRCd is configured with the following paths:
-<|BOLD Base:|> $config{BASE_DIR}
<|BOLD Binary:|> $config{BINARY_DIR}
<|BOLD Config:|> $config{CONFIG_DIR}
<|BOLD Data:|> $config{DATA_DIR}
if (prompt_bool $interactive, $question, 0) {
my $original_base_dir = $config{BASE_DIR};
$config{BASE_DIR} = prompt_dir $interactive, 'In what directory do you wish to install the InspIRCd base?', $config{BASE_DIR};
- foreach my $key (qw(BINARY_DIR CONFIG_DIR DATA_DIR LOG_DIR MANUAL_DIR MODULE_DIR SCRIPT_DIR)) {
+ for my $key (qw(BINARY_DIR CONFIG_DIR DATA_DIR LOG_DIR MANUAL_DIR MODULE_DIR SCRIPT_DIR)) {
$config{$key} =~ s/^\Q$original_base_dir\E/$config{BASE_DIR}/;
}
$config{BINARY_DIR} = prompt_dir $interactive, 'In what directory should the InspIRCd binary be placed?', $config{BINARY_DIR};
$config{MODULE_DIR} = prompt_dir $interactive, 'In what directory are modules to be placed?', $config{MODULE_DIR};
$config{SCRIPT_DIR} = prompt_dir $interactive, 'In what directory are scripts to be placed?', $config{SCRIPT_DIR};
$config{EXAMPLE_DIR} = $config{CONFIG_DIR} . '/examples';
+ $config{RUNTIME_DIR} = $config{DATA_DIR};
}
# Configure module settings.
Would you like to enable extra modules manually?
EOQ
if (prompt_bool $interactive, $question, 0) {
- foreach my $extra (<src/modules/extra/m_*.cpp>) {
- my $module_name = basename $extra, '.cpp';
- if (prompt_bool $interactive, "Would you like to enable $module_name?", 0) {
- enable_extras "$module_name.cpp";
+ for my $extra (<$RealDir/src/modules/extra/m_*.cpp>) {
+ my $module_name = module_shrink $extra;
+ if (prompt_bool $interactive, "Would you like to enable the <|BOLD $module_name|> module?", 0) {
+ enable_extras $module_name;
}
}
} elsif (!defined $opt_disable_auto_extras) {
- # TODO: finish modulemanager rewrite and replace this code with:
- # system './modulemanager', 'enable', '--auto';
my %modules = (
- # Missing: m_ldap, m_regex_stdlib, m_ssl_mbedtls
+ 'm_argon2.cpp' => 'pkg-config --exists libargon2',
'm_geo_maxmind.cpp' => 'pkg-config --exists libmaxminddb',
'm_mysql.cpp' => 'mysql_config --version',
'm_pgsql.cpp' => 'pg_config --version',
+ 'm_ldap.cpp' => "echo '#include <ldap.h>' | $config{CXX} -E -",
'm_regex_pcre.cpp' => 'pcre-config --version',
'm_regex_posix.cpp' => undef,
'm_regex_re2.cpp' => 'pkg-config --exists re2',
+ 'm_regex_stdlib.cpp' => "$config{CXX} -o /dev/null -std=c++11 $RealDir/make/test/compiler.cpp",
'm_regex_tre.cpp' => 'pkg-config --exists tre',
'm_sqlite3.cpp' => 'pkg-config --exists sqlite3',
'm_ssl_gnutls.cpp' => 'pkg-config --exists gnutls',
+ 'm_ssl_mbedtls.cpp' => "echo '#include <mbedtls/version.h>' | $config{CXX} -E -",
'm_ssl_openssl.cpp' => 'pkg-config --exists openssl',
'm_sslrehashsignal.cpp' => undef,
);
https://letsencrypt.org/getting-started/ for more details.
EOQ
-if (<src/modules/m_ssl_*.cpp>) {
+if (<$RealDir/src/modules/m_ssl_*.cpp>) {
if (prompt_bool $interactive, $question, $interactive) {
- system './tools/genssl', 'auto';
+ create_directory CONFIGURE_DIRECTORY, 0750 or print_error "unable to create ${\CONFIGURE_DIRECTORY}: $!";
+ system './tools/genssl', 'auto', CONFIGURE_DIRECTORY;
+ } else {
+ my @pems = <${\CONFIGURE_DIRECTORY}/{cert,csr,dhparams,key}.pem>;
+ $question = <<EOQ;
+The following self-signed files were previously generated and will be installed
+when you run Make. Do you want to delete them?
+
+ * ${\join "\n * ", @pems}
+EOQ
+ if (@pems && prompt_bool $interactive, $question, 0) {
+ unlink @pems;
+ }
}
-} else {
+} elsif (!defined $opt_disable_auto_extras) {
print_warning <<"EOM";
You are building without enabling any SSL modules. This is not
recommended as SSL greatly enhances the security and privacy of your IRC server
write_configure_cache %config;
parse_templates \%config, \%compiler, \%version;
-print_format <<"EOM";
+print console_format <<"EOM";
Configuration is complete! You have chosen to build with the following settings:
<|GREEN Extra Modules:|>
EOM
-for my $file (<src/modules/m_*>) {
- my $module = basename $file, '.cpp';
- say " * $module" if -l $file;
+for my $file (<$RealDir/src/modules/m_*>) {
+ say " * ${\module_shrink $file}" if -l $file;
}
-print_format <<"EOM";
+my @makeargs;
+push @makeargs, "-C${\abs2rel $RealDir}" unless getcwd eq $RealDir;
+push @makeargs, "-j${\(get_cpu_count() + 1)}";
+
+print console_format <<"EOM";
<|GREEN Paths:|>
- <|GREEN Base:|> $config{BASE_DIR}
<|GREEN Binary:|> $config{BINARY_DIR}
<|GREEN Config:|> $config{CONFIG_DIR}
<|GREEN Data:|> $config{DATA_DIR}
<|GREEN Log:|> $config{LOG_DIR}
<|GREEN Manual:|> $config{MANUAL_DIR}
<|GREEN Module:|> $config{MODULE_DIR}
+ <|GREEN Runtime:|> $config{RUNTIME_DIR}
<|GREEN Script:|> $config{SCRIPT_DIR}
<|GREEN Execution Group:|> $config{GROUP} ($config{GID})
<|GREEN Execution User:|> $config{USER} ($config{UID})
<|GREEN Socket Engine:|> $config{SOCKETENGINE}
-To build with these settings run '<|GREEN make -j${\get_cpu_count} install|>' now.
+To build with these settings run '<|GREEN make ${\join ' ', @makeargs} install|>' now.
EOM
my @sources = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
closedir $dd;
undef $dd;
- my $maxlen = (sort { $b <=> $a } (map {length($_)} (@extras)))[0];
+ my $maxlen = (sort { $b <=> $a } (map { length module_shrink $_ } (@extras)))[0];
my %extras = ();
EXTRA: for my $extra (@extras) {
next if (File::Spec->curdir() eq $extra || File::Spec->updir() eq $extra);
for my $extra (sort {$a cmp $b} keys(%extras)) {
my $text = $extras{$extra};
if ($text =~ m/needed by/ && $text !~ m/enabled/) {
- printf "\e[31;1;5m%-*s = %s%s\e[0m\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? ")" : "");
+ printf "\e[31;1;5m%-*s = %s%s\e[0m\n", $maxlen, module_shrink($extra), $text, ($text =~ m/needed by/ ? ")" : "");
} else {
- printf "%-*s = %s%s\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? "\e[0m)" : "");
+ printf "%-*s = %s%s\n", $maxlen, module_shrink($extra), $text, ($text =~ m/needed by/ ? "\e[0m)" : "");
}
}
return keys(%extras) if wantarray; # Can be used by manage_extras.
}
-sub enable_extras (@) {
- my (@extras) = @_;
- for my $extra (@extras) {
- $extra = "m_$extra" unless $extra =~ /^m_/;
- $extra = "$extra.cpp" unless $extra =~ /\.cpp$/;
- my $extrapath = "src/modules/extra/$extra";
- if (!-e $extrapath) {
- print STDERR "Cannot enable \e[32;1m$extra\e[0m : No such file or directory in src/modules/extra\n";
- next;
- }
- my $source = "src/modules/$extra";
- if (-e $source) {
- print STDERR "Cannot enable \e[32;1m$extra\e[0m : destination in src/modules exists (might already be enabled?)\n";
- next;
+sub enable_extras(@) {
+ my $moduledir = catdir $RealDir, 'src', 'modules';
+ my $extradir = catdir $moduledir, 'extra';
+
+ for my $extra (@_) {
+ my $shortname = module_shrink $extra;
+ my $extrafile = module_expand $extra;
+
+ my $extrapath = catfile $extradir, $extrafile;
+ if (!-f $extrapath) {
+ print_error "<|GREEN $extra|> is not an extra module!";
}
- # Get dependencies, and add them to be processed.
- my @deps = split /\s+/, get_directive($extrapath, 'ModDep', '');
- for my $dep (@deps) {
- next if scalar(grep { $_ eq $dep } (@extras)) > 0; # Skip if we're going to be enabling it anyway.
- if (!-e "src/modules/$dep" && !-e "include/$dep") {
- if (-e "src/modules/extra/$dep") {
- print STDERR "Will also enable extra \e[32;1m$dep\e[0m (needed by \e[32;1m$extra\e[0m)\n";
- push @extras, $dep;
- } else {
- print STDERR "\e[33;1mWARNING:\e[0m module \e[32;1m$extra\e[0m might be missing dependency \e[32;1m$dep\e[0m - YOU are responsible for satisfying it!\n";
- }
+
+ my $modulepath = catfile $moduledir, $extrafile;
+ if (-l $modulepath) {
+ if (readlink($modulepath) ne $extrapath) {
+ unlink $modulepath; # Remove the dead symlink.
+ } else {
+ next; # Module is already enabled.
}
}
- print "Enabling $extra ... \n";
- symlink "extra/$extra", $source or print STDERR "$source: Cannot link to 'extra/$extra': $!\n";
+
+ if (-e $modulepath) {
+ print_error "unable to symlink <|GREEN ${\abs2rel $modulepath}|> to <|GREEN ${\abs2rel $extrapath}|>: the target exists and is not a symlink.";
+ } else {
+ say console_format "Enabling the <|GREEN $shortname|> module ...";
+ symlink $extrapath, $modulepath or print_error "unable to symlink <|GREEN ${\abs2rel $modulepath}|> to <|GREEN ${\abs2rel $extrapath}|>: $!";
+ }
}
}
-sub disable_extras (@)
-{
- opendir my $dd, "src/modules/extra/";
- my @files = readdir($dd);
- closedir $dd;
- my (@extras) = @_;
-EXTRA: for my $extra (@extras) {
- $extra = "m_$extra" unless $extra =~ /^m_/;
- $extra = "$extra.cpp" unless $extra =~ /\.cpp$/;
- my $extrapath = "src/modules/extra/$extra";
- my $source = "src/modules/$extra";
- if (!-e $extrapath) {
- print STDERR "Cannot disable \e[32;1m$extra\e[0m : Is not an extra\n";
- next;
- }
- if ((! -l $source) || readlink($source) ne "extra/$extra") {
- print STDERR "Cannot disable \e[32;1m$extra\e[0m : Source is not a link or doesn't refer to the right file. Remove manually if this is in error.\n";
- next;
- }
- # Check if anything needs this.
- for my $file (@files) {
- my @deps = split /\s+/, get_directive("src/modules/extra/$file", 'ModDep', '');
- # File depends on this extra...
- if (scalar(grep { $_ eq $extra } @deps) > 0) {
- # And is both enabled and not about to be disabled.
- if (-e "src/modules/$file" && scalar(grep { $_ eq $file } @extras) < 1) {
- print STDERR "Cannot disable \e[32;1m$extra\e[0m : is needed by \e[32;1m$file\e[0m\n";
- next EXTRA;
- }
- }
+sub disable_extras(@) {
+ my $moduledir = catdir $RealDir, 'src', 'modules';
+ my $extradir = catdir $moduledir, 'extra';
+
+ for my $extra (@_) {
+ my $shortname = module_shrink $extra;
+ my $extrafile = module_expand $extra;
+
+ my $modulepath = catfile $moduledir, $extrafile;
+ my $extrapath = catfile $extradir, $extrafile;
+ if (!-e $modulepath && !-e $extrapath) {
+ print_error "the <|GREEN $shortname|> module does not exist!";
+ } elsif (!-e $modulepath && -e $extrapath) {
+ print_error "the <|GREEN $shortname|> module is not currently enabled!";
+ } elsif ((-e $modulepath && !-e $extrapath) || !-l $modulepath) {
+ print_error "the <|GREEN $shortname|> module is not an extra module!";
+ } else {
+ say console_format "Disabling the <|GREEN $shortname|> module ...";
+ unlink $modulepath or print_error "unable to unlink <|GREEN $extrapath|>: $!";
}
- # Now remove.
- print "Disabling $extra ... \n";
- unlink "src/modules/$extra" or print STDERR "Cannot disable \e[32;1m$extra\e[0m : $!\n";
}
}