335 lines
9.4 KiB
Perl
Executable File
335 lines
9.4 KiB
Perl
Executable File
#!/usr/bin/env perl
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Copyright (C) 2008-2020 TJ Saunders <tj@castaglia.org>
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
|
|
# ---------------------------------------------------------------------------
|
|
|
|
use strict;
|
|
|
|
use File::Basename qw(basename);
|
|
use Getopt::Long;
|
|
|
|
Getopt::Long::Configure("no_ignorecase");
|
|
|
|
my $prog = basename($0);
|
|
|
|
my $compiler = q(gcc);
|
|
my $cflags = q( -DLINUX -g2 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/var/jenkins/workspace/PLESK/CI/rapid-ci=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -Wall -fno-omit-frame-pointer -fno-strict-aliasing -Werror=implicit-function-declaration -DPR_SHARED_MODULE);
|
|
my $cppflags = q(-Wdate-time -D_FORTIFY_SOURCE=3);
|
|
my $ltdl_ldflags = q(-avoid-version -export-dynamic -module);
|
|
my $sbindir = q(/usr/sbin);
|
|
my $includedir = q(/usr/include);
|
|
my $installer = q(/usr/bin/install -c);
|
|
my $install_strip = q();
|
|
my $libexecdir = q(/usr/libexec/proftpd);
|
|
my $libtool = 'libtool';
|
|
|
|
if (!defined($ENV{LIBTOOL})) {
|
|
if ($^O eq 'darwin') {
|
|
$libtool = 'glibtool';
|
|
}
|
|
|
|
} else {
|
|
$libtool = $ENV{LIBTOOL};
|
|
}
|
|
|
|
my $opts = {};
|
|
GetOptions($opts, 'c|compile', 'i|install', 'd|clean', 'h|help', 'name=s',
|
|
'D=s@', 'I=s@', 'L=s@', 'l=s@', 'W=s@');
|
|
|
|
if ($opts->{h}) {
|
|
usage();
|
|
exit 0;
|
|
}
|
|
|
|
# Make sure we can query proftpd to find out its list of installed modules.
|
|
# Unless we see mod_dso listed, there's no point in compiling a shared
|
|
# module for proftpd to use.
|
|
|
|
my $proftpd = "$sbindir/proftpd";
|
|
unless (-x $proftpd) {
|
|
print STDERR "$proftpd not found or not executable\n";
|
|
exit 1;
|
|
}
|
|
|
|
unless (grep /mod_dso/, `$proftpd -l`) {
|
|
print STDERR "\nYour installed proftpd does not support shared modules/DSOs.\n";
|
|
print STDERR "Make sure the --enable-dso configure option is used when\n";
|
|
print STDERR "compiling proftpd.\n\n";
|
|
exit 1;
|
|
}
|
|
|
|
# If the libtool-specific linker flags are empty, it means that the
|
|
# script was generated by a configure script lacking the --enable-dso option.
|
|
unless (length($ltdl_ldflags) > 0) {
|
|
print STDERR "\nMissing the required libtool flags.\n";
|
|
print STDERR "Make sure the --enable-dso configure option is used when\n";
|
|
print STDERR "compiling proftpd.\n\n";
|
|
exit 1;
|
|
}
|
|
|
|
# Now, depending on the requested mode (compile/install/clean), build up
|
|
# and execute the commands.
|
|
|
|
my $mod_name = get_module_name();
|
|
|
|
if (defined($opts->{c})) {
|
|
my $srcs = [];
|
|
my $objs = [];
|
|
|
|
my $configure_script;
|
|
|
|
foreach my $file (@ARGV) {
|
|
if ($file =~ /\.c$/) {
|
|
push(@$srcs, $file);
|
|
|
|
if ($file =~ /\/?mod_[^\/]+\.c$/) {
|
|
$configure_script = $file;
|
|
$configure_script =~ s/(\/?)mod_[^\/]+\.c$/\1configure/;
|
|
|
|
if ($configure_script !~ /^\//) {
|
|
$configure_script = './' . $configure_script;
|
|
}
|
|
}
|
|
|
|
my $obj = $file;
|
|
$obj =~ s/\.c$/\.lo/;
|
|
|
|
# Handle an argument such as 'contrib/mod_sql_sqlite.c' by keeping
|
|
# just the name portion of the path.
|
|
$obj =~ s/^(.*)\///g;
|
|
|
|
push(@$objs, $obj);
|
|
|
|
} else {
|
|
print STDERR "Cannot compile non-.c file $file, aborting\n";
|
|
exit 1;
|
|
}
|
|
}
|
|
|
|
if (defined($configure_script)) {
|
|
# Check for any configure script for this module. If present, error out
|
|
# for now.
|
|
if (-f $configure_script) {
|
|
print STDERR "\nCannot compile $mod_name using prxs. Use existing $configure_script script instead:\n\n";
|
|
|
|
if ($configure_script ne './configure') {
|
|
my $mod_dir = $configure_script;
|
|
$mod_dir =~ s/configure$//g;
|
|
print STDERR " cd $mod_dir\n";
|
|
}
|
|
|
|
print STDERR " ./configure\n";
|
|
print STDERR " make\n";
|
|
print STDERR " make install\n";
|
|
exit 1;
|
|
}
|
|
}
|
|
|
|
foreach my $def (@{ $opts->{D} }) {
|
|
if ($def =~ /^(\S+)=(\S+)$/) {
|
|
$cflags .= " -D'$1=$2'";
|
|
|
|
} else {
|
|
$cflags .= " -D$def";
|
|
}
|
|
}
|
|
|
|
$cflags .= " -I. -I$includedir/proftpd";
|
|
|
|
foreach my $incdir (@{ $opts->{I} }) {
|
|
$cflags .= " -I$incdir";
|
|
}
|
|
|
|
my $cmds = [];
|
|
foreach my $src (@$srcs) {
|
|
push(@$cmds, "$libtool --mode=compile $compiler $cflags -c $src");
|
|
}
|
|
|
|
run_cmds($cmds);
|
|
|
|
my $objlist = '';
|
|
foreach my $obj (@$objs) {
|
|
$objlist .= " $obj";
|
|
}
|
|
|
|
my $ldflags .= " $ltdl_ldflags";
|
|
|
|
foreach my $libdir (@{ $opts->{L} }) {
|
|
$ldflags .= " -L$libdir";
|
|
}
|
|
|
|
# Scan through the .c files, looking for the $Libraries$ hint that
|
|
# proftpd's build system uses.
|
|
foreach my $src (@$srcs) {
|
|
if (open(my $fh, "< $src")) {
|
|
while (my $line = <$fh>) {
|
|
chomp($line);
|
|
|
|
if ($line =~ /\$Libraries:\s+(.*)?\$/) {
|
|
my $hint = $1;
|
|
|
|
# Assume that the library hint list is space-separated; add them
|
|
# to the $opts hashref. Don't forget to strip of the '-l' prefix;
|
|
# that is added back later in the handling of $opts.
|
|
my $libs = [split(/\s+/, $hint)];
|
|
foreach my $lib (@$libs) {
|
|
$lib =~ s/^\-l//;
|
|
push(@{ $opts->{l} }, $lib);
|
|
}
|
|
|
|
last;
|
|
}
|
|
}
|
|
|
|
close($fh);
|
|
|
|
} else {
|
|
print STDERR "Unable to scan $src for \$Libraries\$ hint: $!\n";
|
|
}
|
|
}
|
|
|
|
my $libs = "";
|
|
foreach my $lib (@{ $opts->{l} }) {
|
|
$libs .= " -l$lib";
|
|
}
|
|
|
|
$cmds = [];
|
|
push(@$cmds, "$libtool --mode=link $compiler -o $mod_name.la -rpath $libexecdir $ldflags $objlist $libs");
|
|
|
|
run_cmds($cmds);
|
|
}
|
|
|
|
if (defined($opts->{i})) {
|
|
my $cmds = [];
|
|
push(@$cmds, "$libtool --mode=install $installer $install_strip $mod_name.la $ENV{DESTDIR}$libexecdir");
|
|
|
|
run_cmds($cmds);
|
|
|
|
# Don't forget to remind the user to manually edit their proftpd.conf
|
|
# and add the LoadModule to load the just-installed module.
|
|
|
|
my $load_mod_name = $mod_name;
|
|
$load_mod_name =~ s/^(.*)\///;
|
|
|
|
print STDOUT "\nTo load your newly installed module into proftpd, be sure\n";
|
|
print STDOUT "to edit your proftpd.conf and add the following:\n\n";
|
|
print STDOUT " <IfModule mod_dso.c>\n";
|
|
print STDOUT " LoadModule $load_mod_name.c\n";
|
|
print STDOUT " </IfModule>\n\n";
|
|
print STDOUT "and then restart your proftpd server, so that the config change\n";
|
|
print STDOUT "becomes live.\n\n";
|
|
}
|
|
|
|
if (defined($opts->{d})) {
|
|
my $cmds = [];
|
|
push(@$cmds, "$libtool --mode=clean rm -f $mod_name.la *.lo");
|
|
|
|
run_cmds($cmds);
|
|
}
|
|
|
|
if (!defined($opts->{c}) &&
|
|
!defined($opts->{i}) &&
|
|
!defined($opts->{d})) {
|
|
print STDERR "No compile, install, or clean mode requested, exiting\n";
|
|
exit 1;
|
|
}
|
|
|
|
exit 0;
|
|
|
|
sub get_module_name {
|
|
# Determine the name of the module (e.g. "mod_foo") being operated upon.
|
|
if (defined($opts->{n})) {
|
|
return $opts->{n};
|
|
}
|
|
|
|
foreach my $file (@ARGV) {
|
|
# Handle an argument such as 'contrib/mod_sql_sqlite.c' by keeping
|
|
# just the name portion of the path.
|
|
|
|
if ($file =~ /\/?mod_([^\/]+)\.(c|la)$/) {
|
|
return "mod_$1";
|
|
}
|
|
}
|
|
|
|
return "mod_unknown";
|
|
}
|
|
|
|
sub run_cmds {
|
|
my $cmds = shift;
|
|
|
|
foreach my $cmd (@$cmds) {
|
|
print STDOUT "$cmd\n";
|
|
|
|
my $res = system($cmd);
|
|
if ($res) {
|
|
print STDERR "$prog: error executing command (", $res >> 8, ")\n";
|
|
exit 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
sub usage {
|
|
my $prog = basename($0);
|
|
|
|
print STDOUT <<EOU;
|
|
|
|
usage: $prog <action> <opts> <source files>
|
|
|
|
Actions:
|
|
|
|
-c, --compile Compiles the listed .c source files into a proftpd
|
|
DSO module.
|
|
|
|
-i, --install Installs a compiled proftpd DSO module into the
|
|
directory where proftpd expects to find loadable
|
|
DSO modules.
|
|
|
|
-d, --clean Removes any generated files, returning the build
|
|
directory to a clean state.
|
|
|
|
Options:
|
|
|
|
-h, --help Displays this message.
|
|
|
|
-n, --name Tells prxs the name of the module being compiled.
|
|
By default, prxs determines the module name from
|
|
the list of .c files listed, expecting to see a
|
|
"mod_\$name.c" file.
|
|
|
|
-D key Passes these macros through to the compilation step.
|
|
-D key=value Note that the space before the key is important.
|
|
|
|
-I includedir Specify additional include file search directories.
|
|
Note that the space before the directory is important.
|
|
|
|
-L libdir Specify additional library file search directories.
|
|
Note that the space before the directory is important.
|
|
|
|
-l library Specify additional libraries for linking.
|
|
Note that the space before the library name is important.
|
|
|
|
At least one of the above actions must be specified when using prxs. More
|
|
than one action can be specified at the same time.
|
|
|
|
To use prxs all in one step, you could do:
|
|
|
|
prxs -c -i -d mod_custom.c
|
|
|
|
EOU
|
|
}
|