]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - configure
d8d356bfbd9f2bc3451e8ab4472c0da2487a68a0
[user/henk/code/inspircd.git] / configure
1 #!/usr/bin/env perl
2
3 #
4 # InspIRCd -- Internet Relay Chat Daemon
5 #
6 #   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
7 #   Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org>
8 #   Copyright (C) 2003, 2006-2008 Craig Edwards <craigedwards@brainbox.cc>
9 #   Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net>
10 #   Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
11 #   Copyright (C) 2007 John Brooks <john.brooks@dereferenced.net>
12 #   Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.com>
13 #   Copyright (C) 2003-2006 Craig McLure <craig@chatspike.net>
14 #
15 # This file is part of InspIRCd.  InspIRCd is free software: you can
16 # redistribute it and/or modify it under the terms of the GNU General Public
17 # License as published by the Free Software Foundation, version 2.
18 #
19 # This program is distributed in the hope that it will be useful, but WITHOUT
20 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
21 # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
22 # details.
23 #
24 # You should have received a copy of the GNU General Public License
25 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
26 #
27
28
29 BEGIN {
30         require 5.8.0;
31 }
32
33 use strict;
34 use warnings FATAL => qw(all);
35
36 use Data::Dumper;
37 BEGIN {
38         $Data::Dumper::Sortkeys = 1;
39         $Data::Dumper::Useqq = 1;
40 };
41
42 use File::Copy ();
43 use Cwd;
44 use Getopt::Long;
45
46 # Utility functions for our buildsystem
47 use make::utilities;
48 use make::configure;
49
50 ###############################################################################################
51 #
52 #                                 NON-EDITABLE VARIABLES
53 #
54 ###############################################################################################
55
56 our ($opt_use_gnutls, $opt_use_openssl, $opt_nointeractive, $opt_ports, $opt_epoll, $opt_kqueue,
57      $opt_noports, $opt_noepoll, $opt_nokqueue, $opt_freebsd_port, $opt_system, $opt_uid);
58
59 our ($opt_base_dir, $opt_config_dir, $opt_module_dir, $opt_binary_dir, $opt_data_dir, $opt_log_dir);
60
61 sub list_extras ();
62
63 sub enable_extras (@);
64
65 sub disable_extras (@);
66
67 my @opt_enableextras;
68 my @opt_disableextras;
69
70 GetOptions (
71         'enable-gnutls' => \$opt_use_gnutls,
72         'system' => \$opt_system,
73         'uid=s' => \$opt_uid,
74         'enable-openssl' => \$opt_use_openssl,
75         'disable-interactive' => \$opt_nointeractive,
76         'enable-ports' => \$opt_ports,
77         'enable-epoll' => \$opt_epoll,
78         'enable-kqueue' => \$opt_kqueue,
79         'disable-ports' => \$opt_noports,
80         'disable-epoll' => \$opt_noepoll,
81         'disable-kqueue' => \$opt_nokqueue,
82         'enable-freebsd-ports-openssl' => \$opt_freebsd_port,
83         'prefix=s' => \$opt_base_dir,
84         'config-dir=s' => \$opt_config_dir,
85         'module-dir=s' => \$opt_module_dir,
86         'binary-dir=s' => \$opt_binary_dir,
87         'data-dir=s' => \$opt_data_dir,
88         'log-dir=s' => \$opt_log_dir,
89         'help'  => sub { showhelp(); },
90         'update' => sub { update(); },
91         'clean' => sub { clean(); },
92         'list-extras' => sub { list_extras; exit 0; }, # This, --enable-extras, and --disable-extras are for non-interactive managing.
93         'enable-extras=s@' => \@opt_enableextras, # ^
94         'disable-extras=s@' => \@opt_disableextras, # ^
95 );
96
97 if (scalar(@opt_enableextras) + scalar(@opt_disableextras) > 0) {
98         @opt_enableextras = split /,/, join(',', @opt_enableextras);
99         @opt_disableextras = split /,/, join(',', @opt_disableextras);
100         enable_extras(@opt_enableextras);
101         disable_extras(@opt_disableextras);
102         list_extras;
103         print "Remember: YOU are responsible for making sure any libraries needed have been installed!\n";
104         exit 0;
105 }
106
107 our $interactive = !(
108         (defined $opt_base_dir) ||
109         (defined $opt_config_dir) ||
110         (defined $opt_module_dir) ||
111         (defined $opt_base_dir) ||
112         (defined $opt_binary_dir) ||
113         (defined $opt_data_dir) ||
114         (defined $opt_log_dir) ||
115         (defined $opt_nointeractive) ||
116         (defined $opt_kqueue) ||
117         (defined $opt_epoll) ||
118         (defined $opt_ports) ||
119         (defined $opt_use_openssl) ||
120         (defined $opt_nokqueue) ||
121         (defined $opt_noepoll) ||
122         (defined $opt_noports) ||
123         (defined $opt_system) ||
124         (defined $opt_uid) ||
125         (defined $opt_use_gnutls) ||
126         (defined $opt_freebsd_port)
127 );
128
129 chomp(our $topdir = getcwd());
130 our $this = resolve_directory($topdir);                                         # PWD, Regardless.
131 our @modlist = ();                                                                      # Declare for Module List..
132 our %config = ();                                                                       # Initiate Configuration Hash..
133 our $cache_loaded = getcache();
134 $config{ME} = resolve_directory($topdir);                               # Present Working Directory
135
136 $config{BASE_DIR} = $config{ME}."/run";
137
138 if (defined $opt_base_dir) {
139         $config{BASE_DIR} = $opt_base_dir;
140 } elsif (defined $opt_system) {
141         $config{BASE_DIR} = '/var/lib/inspircd';
142 }
143
144 if (defined $opt_system) {
145         $config{UID} = $opt_uid || 'ircd';
146         $config{CONFIG_DIR}      = '/etc/inspircd';
147         $config{MODULE_DIR}      = '/usr/lib/inspircd';
148         $config{BINARY_DIR}      = '/usr/sbin/';
149         $config{BUILD_DIR}       = resolve_directory($config{ME}."/build");         # Build Directory
150         $config{DATA_DIR}        = '/var/inspircd';
151         $config{LOG_DIR}         = '/var/log/inspircd';
152 } else {
153         $config{UID} = $opt_uid || $<;
154         $config{CONFIG_DIR}      = resolve_directory($config{BASE_DIR}."/conf");        # Configuration Directory
155         $config{MODULE_DIR}      = resolve_directory($config{BASE_DIR}."/modules");     # Modules Directory
156         $config{BINARY_DIR}      = resolve_directory($config{BASE_DIR}."/bin");         # Binary Directory
157         $config{BUILD_DIR}       = resolve_directory($config{ME}."/build");         # Build Directory
158         $config{DATA_DIR}        = resolve_directory($config{BASE_DIR}."/data");        # Data directory
159         $config{LOG_DIR}         = resolve_directory($config{BASE_DIR}."/logs");        # Log directory
160 }
161
162 if (defined $opt_config_dir) {
163         $config{CONFIG_DIR} = $opt_config_dir;
164 }
165 if (defined $opt_module_dir) {
166         $config{MODULE_DIR} = $opt_module_dir;
167 }
168 if (defined $opt_binary_dir) {
169         $config{BINARY_DIR} = $opt_binary_dir;
170 }
171 if (defined $opt_data_dir) {
172         $config{DATA_DIR} = $opt_data_dir;
173 }
174 if (defined $opt_log_dir) {
175         $config{LOG_DIR} = $opt_log_dir;
176 }
177 chomp($config{HAS_GNUTLS}   = `pkg-config --modversion gnutls 2>/dev/null`); # GNUTLS Version.
178
179 if (defined $opt_freebsd_port)
180 {
181         chomp($config{HAS_OPENSSL} = `pkg-config --modversion openssl 2>/dev/null`);
182         chomp($config{HAS_OPENSSL_PORT}  = `pkg-config --modversion openssl 2>/dev/null`);
183         $config{USE_FREEBSD_BASE_SSL} = "n";
184 }
185 else
186 {
187         if ($^O eq "freebsd")
188         {
189                 # default: use base ssl
190                 chomp($config{HAS_OPENSSL} = `openssl version | cut -d ' ' -f 2`);                      # OpenSSL version, freebsd specific
191                 chomp($config{HAS_OPENSSL_PORT}  = `pkg-config --modversion openssl 2>/dev/null`);      # Port version, may be different
192         }
193         else
194         {
195                 chomp($config{HAS_OPENSSL}  = `pkg-config --modversion openssl 2>/dev/null`);           # Openssl version, others
196                 $config{HAS_OPENSSL_PORT} = "";
197         }
198 }
199
200 chomp(our $gnutls_ver = $config{HAS_GNUTLS});
201 chomp(our $openssl_ver = $config{HAS_OPENSSL});
202 $config{USE_GNUTLS}         = "n";
203 if (defined $opt_use_gnutls)
204 {
205         $config{USE_GNUTLS} = "y";                                      # Use gnutls.
206 }
207 $config{USE_OPENSSL}    = "n";                                          # Use openssl.
208 if (defined $opt_use_openssl)
209 {
210         $config{USE_OPENSSL} = "y";
211 }
212
213 $config{HAS_STDINT}      = "false";                                     # stdint.h check
214 $config{USE_KQUEUE}      = "y";                                         # kqueue enabled
215 if (defined $opt_nokqueue) {
216         $config{USE_KQUEUE} = "n";
217 }
218 $config{USE_POLL}     = "y";                                    # poll enabled
219 $config{USE_EPOLL}        = "y";                                        # epoll enabled
220 if (defined $opt_noepoll)
221 {
222         $config{USE_EPOLL} = "n";
223 }
224 $config{USE_PORTS}        = "y";                                        # epoll enabled
225 if (defined $opt_noports)
226 {
227         $config{USE_PORTS} = "n";
228 }
229 $config{OSNAME}             = $^O;                                      # Operating System Name
230 $config{STARTSCRIPT}      = "inspircd";                 # start script?
231 $config{DESTINATION}      = "BASE";                             # Is target path.
232 if ($config{OSNAME} =~ /darwin/i)
233 {
234         $config{STARTSCRIPT}      = "org.inspircd.plist";               # start script for OSX.
235 }
236
237 $config{CXX} = defined $ENV{CXX} && !system("$ENV{CXX} -v > /dev/null 2>&1") ? $ENV{CXX} : find_compiler();
238 if ($config{CXX} eq "") {
239         print "A C++ compiler could not be detected on your system!\n";
240         print "Set the CXX environment variable to the full path if this is incorrect.\n";
241         exit 1; 
242 }
243
244 our %cxx = get_compiler_info($config{CXX});
245 if ($cxx{UNSUPPORTED}) {
246         print "Your C++ compiler is too old to build InspIRCd!\n";
247         print "Reason: $cxx{REASON}\n";
248         exit 1;
249 }
250
251 if ($config{HAS_OPENSSL} =~ /^([-[:digit:].]+)(?:[a-z])?(?:\-[a-z][0-9])?/) {
252         $config{HAS_OPENSSL} = $1;
253 } else {
254         $config{HAS_OPENSSL} = "";
255 }
256
257 # Get and Set some important vars..
258 getmodules();
259
260 sub clean
261 {
262         unlink(".config.cache");
263 }
264
265 our ($has_epoll, $has_ports, $has_kqueue) = (0, 0, 0);
266
267 sub update
268 {
269         eval {
270                 chomp($topdir = getcwd());
271                 $this = resolve_directory($topdir);                                          # PWD, Regardless.
272                 getmodules();
273                 # Does the cache file exist?
274                 if (!getcache()) {
275                         # No, No it doesn't.. *BASH*
276                         print "You have not run ./configure before. Please do this before trying to run the update script.\n";
277                         exit 0;
278                 } else {
279                         # We've Loaded the cache file and all our variables..
280                         print "Updating files...\n";
281                         $has_epoll = $config{HAS_EPOLL};
282                         $has_ports = $config{HAS_PORTS};
283                         $has_kqueue = $config{HAS_KQUEUE};
284                         writefiles(1);
285                         makecache();
286                         print "Complete.\n";
287                         exit;
288                 }
289         };
290         if ($@)
291         {
292                 print "Configure update failed: $@\n";
293         }
294         exit;
295 }
296
297 print "Running non-interactive configure...\n" unless $interactive;
298 print "Checking for cache from previous configure... ";
299 print ($cache_loaded ? "found\n" : "not found\n");
300 $config{SYSTEM} = lc $^O;
301 print "Checking operating system version... $config{SYSTEM}\n";
302
303 print "Checking whether <stdint.h> exists... ";
304 if (test_header($config{CXX}, "stdint.h")) {
305         $config{HAS_STDINT} = "true";
306         print "yes\n";
307 } else {
308         $config{HAS_STDINT} = "false";
309         print "no\n";
310 }
311
312 printf "Checking whether clock_gettime() exists... ";
313 if (test_file($config{CXX}, "clock_gettime.cpp", "-lrt")) {
314         $config{HAS_CLOCK_GETTIME} = "true";
315         print "yes\n";
316 } else {
317         $config{HAS_CLOCK_GETTIME} = "false";
318         print "no\n";
319 }
320
321 printf "Checking whether eventfd() exists... ";
322 if (test_file($config{CXX}, "eventfd.cpp")) {
323         $config{HAS_EVENTFD} = "true";
324         print "yes\n";
325 } else {
326         $config{HAS_EVENTFD} = "false";
327         print "no\n";
328 }
329
330 printf "Checking if a TCP deferring mechanism is available... ";
331 if (test_file($config{CXX}, "tcp_defer_accept.cpp")) {
332         $config{HAS_DEFER} = "TCP_DEFER_ACCEPT";
333         print "yes (TCP_DEFER_ACCEPT)\n";
334 } elsif (test_file($config{CXX}, "so_acceptfilter.cpp")) {
335         $config{HAS_DEFER} = "SO_ACCEPTFILTER";
336         print "yes (SO_ACCEPTFILTER)\n";
337 } else {
338         $config{HAS_DEFER} = "false";
339         print "no\n";
340 }
341
342 print "Checking whether epoll is available... ";
343 $has_epoll = test_header($config{CXX}, "sys/epoll.h");
344 print $has_epoll ? "yes\n" : "no\n";
345
346 print "Checking whether Kqueue is available... ";
347 $has_kqueue = test_file($config{CXX}, "kqueue.cpp");
348 print $has_kqueue ? "yes\n" : "no\n";
349
350 print 'Checking whether Solaris IOCP is available... ';
351 $has_ports = test_header($config{CXX}, 'port.h');
352 print $has_ports ? "yes\n" : "no\n";
353
354 $config{HAS_EPOLL} = $has_epoll;
355 $config{HAS_KQUEUE} = $has_kqueue;
356
357 printf "Checking for libgnutls... ";
358 if (defined($config{HAS_GNUTLS}) && (($config{HAS_GNUTLS}) || ($config{HAS_GNUTLS} eq "y"))) {
359         if (defined($gnutls_ver) && ($gnutls_ver ne "")) {
360                 print "yes\n";
361                 $config{HAS_GNUTLS} = "y";
362         } else {
363                 print "no\n";
364                 $config{HAS_GNUTLS} = "n";
365         }
366 } else {
367         print "no\n";
368         $config{HAS_GNUTLS} = "n";
369 }
370
371 printf "Checking for openssl... ";
372 if (defined($config{HAS_OPENSSL}) && (($config{HAS_OPENSSL}) || ($config{HAS_OPENSSL} eq "y"))) {
373         if (defined($openssl_ver) && ($openssl_ver ne "")) {
374                 print "yes\n";
375                 $config{HAS_OPENSSL} = "y";
376         } else {
377                 print "no\n";
378                 $config{HAS_OPENSSL} = "n";
379         }
380 } else {
381         print "no\n";
382         $config{HAS_OPENSSL} = "n";
383 }
384
385 printf "Checking if you are running an ancient, unsupported OS... ";
386 if ($config{OSNAME} =~ /FreeBSD/i)
387 {
388         my $version = `uname -r`;
389         if ($version =~ /^4\./)
390         {
391                 print "yes.\n";
392                 print "FreeBSD 4.x is no longer supported. By ANYONE.\n";
393                 print "To build, you will need to add the following to CXXFLAGS:\n";
394                 print "\t-L/usr/local/lib -lgnugetopt -DHAVE_DECL_GETOPT=1\n";
395         }
396         else
397         {
398                 print "no ($version)\n";
399         }
400 }
401 else
402 {
403         print "no ($config{OSNAME})\n";
404 }
405
406 ################################################################################
407 #                         BEGIN INTERACTIVE PART                              #
408 ################################################################################
409
410 # Clear the Screen..
411 if ($interactive)
412 {
413         print "\e[2J\e[0G\e[0d"; # J = Erase in Display, 2 = Entire Screen, (G, d) = Move cursor to (..,..)
414         my $wholeos = $^O;
415
416         my $rev = getrevision();
417         # Display Introduction Message..
418         print <<"STOP" ;
419 Welcome to the \e[1mInspIRCd\e[0m Configuration program! (\e[1minteractive mode\e[0m)
420 \e[1mPackage maintainers: Type ./configure --help for non-interactive help\e[0m
421
422 *** If you are unsure of any of these values, leave it blank for    ***
423 *** standard settings that will work, and your server will run      ***
424 *** using them. Please consult your IRC network admin if in doubt.  ***
425
426 Press \e[1m<RETURN>\e[0m to accept the default for any option, or enter
427 a new value. Please note: You will \e[1mHAVE\e[0m to read the docs
428 dir, otherwise you won't have a config file!
429
430 Your operating system is: \e[1;32m$config{OSNAME}\e[0m ($wholeos)
431 Your InspIRCd revision ID is \e[1;32mr$rev\e[0m
432 STOP
433         if ($rev eq "r0") {
434                 print " (Non-SVN build)";
435         }
436         print ".\n\n";
437
438         print "I have detected the following compiler: \e[1;32m$cxx{NAME}\e[0m (version \e[1;32m$cxx{VERSION}\e[0m)\n\n";
439
440         # Directory Settings..
441         my $tmpbase = $config{BASE_DIR};
442         dir_check("do you wish to install the InspIRCd base", "BASE_DIR");
443         if ($tmpbase ne $config{BASE_DIR}) {
444                 $config{CONFIG_DIR}      = resolve_directory($config{BASE_DIR}."/conf");           # Configuration Dir
445                 $config{MODULE_DIR}      = resolve_directory($config{BASE_DIR}."/modules");     # Modules Directory
446                 $config{DATA_DIR}        = resolve_directory($config{BASE_DIR}."/data");        # Data Directory
447                 $config{LOG_DIR}         = resolve_directory($config{BASE_DIR}."/logs");        # Log Directory
448                 $config{BINARY_DIR}      = resolve_directory($config{BASE_DIR}."/bin");     # Binary Directory
449         }
450
451         dir_check("are the configuration files", "CONFIG_DIR");
452         dir_check("are the modules to be compiled to", "MODULE_DIR");
453         dir_check("is the IRCd binary to be placed", "BINARY_DIR");
454         dir_check("are variable data files to be located in", "DATA_DIR");
455         dir_check("are the logs to be stored in", "LOG_DIR");
456         dir_check("do you want the build to take place", "BUILD_DIR");
457                 
458         my $chose_hiperf = 0;
459         if ($has_kqueue) {
460                 yesno('USE_KQUEUE',"You are running a BSD operating system, and kqueue\nwas detected. Would you like to enable kqueue support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable kqueue?");
461                 print "\n";
462                 if ($config{USE_KQUEUE} eq "y") {
463                         $chose_hiperf = 1;
464                 }
465         }
466         if ($has_epoll) {
467                 yesno('USE_EPOLL',"You are running a Linux 2.6+ operating system, and epoll\nwas detected. Would you like to enable epoll support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable epoll?");
468                 print "\n";
469                 if ($config{USE_EPOLL} eq "y") {
470                         $chose_hiperf = 1;
471                 }
472         }
473         if ($has_ports) {
474                 yesno('USE_PORTS',"You are running Solaris 10.\nWould you like to enable I/O completion ports support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable support for I/O completion ports?");
475                 print "\n";
476                 if ($config{USE_PORTS} eq "y") {
477                         $chose_hiperf = 1;
478                 }
479         }
480
481         if (!$chose_hiperf) {
482                 yesno('USE_POLL', "Would you like to use poll?\n This is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable poll?");
483                 if ($config{USE_POLL} ne "y")
484                 {
485                         print "No high-performance socket engines are available, or you chose\n";
486                         print "not to enable one. Defaulting to select() engine.\n\n";
487                 }
488         }
489
490         $config{USE_FREEBSD_BASE_SSL} = "n";
491         $config{USE_FREEBSD_PORTS_SSL} = "n";
492         if ($config{HAS_OPENSSL_PORT} ne "")
493         {
494                 $config{USE_FREEBSD_PORTS_SSL} = "y";
495                 print "I have detected the OpenSSL FreeBSD port installed on your system,\n";
496                 print "version \e[1;32m".$config{HAS_OPENSSL_PORT}."\e[0m. Your base system OpenSSL is version \e[1;32m".$openssl_ver."\e[0m.\n\n";
497                 yesno('USE_FREEBSD_PORTS_SSL', "Do you want to use the FreeBSD ports version?");
498                 print "\n";
499                 $config{USE_FREEBSD_BASE_SSL} = "y" if ($config{USE_FREEBSD_PORTS_SSL} eq "n");
500
501                 if ($config{USE_FREEBSD_BASE_SSL} eq "n")
502                 {
503                         # update to port version
504                         $openssl_ver = $config{HAS_OPENSSL_PORT};
505                 }
506         }
507         else
508         {
509                 $config{USE_FREEBSD_BASE_SSL} = "y" if ($^O eq "freebsd");
510         }
511
512         $config{USE_SSL} = "n";
513         $config{MODUPDATE} = 'n';
514
515         if ($config{HAS_GNUTLS} eq "y" || $config{HAS_OPENSSL} eq "y")
516         {
517                 print "Detected GnuTLS version: \e[1;32m" . $gnutls_ver . "\e[0m\n";
518                 print "Detected OpenSSL version: \e[1;32m" . $openssl_ver . "\e[0m\n\n";
519
520                 yesno('USE_SSL', "One or more SSL libraries detected. Would you like to enable SSL support?");
521                 if ($config{USE_SSL} eq "y")
522                 {
523                         if ($config{HAS_GNUTLS} eq "y")
524                         {
525                                 yesno('USE_GNUTLS',"Would you like to enable SSL with m_ssl_gnutls? (recommended)");
526                                 if ($config{USE_GNUTLS} eq "y")
527                                 {
528                                         print "\nUsing GnuTLS SSL module.\n";
529                                 }
530                         }
531
532                         if ($config{HAS_OPENSSL} eq "y")
533                         {
534                                 yesno('USE_OPENSSL', "Would you like to enable SSL with m_ssl_openssl?");
535                                 if ($config{USE_OPENSSL} eq "y")
536                                 {
537                                         print "\nUsing OpenSSL SSL module.\nYou will get better performance if you move to GnuTLS in the future.\n";
538                                 }
539                         }
540                 }
541         }
542         else
543         {
544                 print "\nCould not detect OpenSSL or GnuTLS. Make sure pkg-config is installed and\n";
545                 print "is in your path.\n\n";
546         }
547
548         yesno('MODUPDATE',"Would you like to check for updates to third-party modules?");
549         print "\n";
550         if ($config{MODUPDATE} eq "y") {
551                 print "Checking for upgrades to extra and third party modules... ";
552                 system "./modulemanager upgrade";
553         }
554 }
555
556 # We are on a POSIX system, we can enable POSIX extras without asking
557 symlink "extra/m_regex_posix.cpp", "src/modules/m_regex_posix.cpp";
558
559 dumphash();
560
561 if (($config{USE_GNUTLS} eq "y") && ($config{HAS_GNUTLS} ne "y"))
562 {
563         print "Sorry, but i couldn't detect gnutls. Make sure gnutls-config is in your path.\n";
564         exit(0);
565 }
566 if (($config{USE_OPENSSL} eq "y") && ($config{HAS_OPENSSL} ne "y"))
567 {
568         print "Sorry, but i couldn't detect openssl. Make sure openssl is in your path.\n";
569         exit(0);
570 }
571 our $failed = 0;
572
573 $config{CERTGEN} ||= 'y';
574 yesno('CERTGEN',"Would you like generate SSL certificates now?") if ($interactive && ($config{USE_GNUTLS} eq "y" || $config{USE_OPENSSL} eq "y"));
575
576 if ($config{USE_GNUTLS} eq "y") {
577         unless (-r "src/modules/m_ssl_gnutls.cpp") {
578                 print "Symlinking src/modules/m_ssl_gnutls.cpp from extra/\n";
579                 symlink "extra/m_ssl_gnutls.cpp", "src/modules/m_ssl_gnutls.cpp" or print STDERR "Symlink failed: $!";
580         }
581         if ($interactive && $config{CERTGEN} eq 'y')
582         {
583                 unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
584                         print "SSL Certificates Not found, Generating.. \n\n
585 *************************************************************
586 * Generating the Private Key may take some time, go grab a  *
587 * Coffee. Even better, to generate some more entropy if it  *
588 * is taking a while, open another console and type du / a   *
589 * few times and get that HD going :) Then answer the        *
590 * Questions which follow. If you are unsure, just hit enter *
591 *************************************************************\n\n";
592                         $failed = system "./tools/genssl gnutls";
593                         if ($failed) {
594                                 print "\n\e[1;32mCertificate generation failed!\e[0m\n\n";
595                         } else {
596                                 print "\nCertificate generation complete, copying to config directory... ";
597                                 File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
598                                 File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
599                                 print "Done.\n\n";
600                         }
601                 }
602                 else {
603                         print "SSL Certificates found, skipping.\n\n";
604                 }
605         }
606         else
607         {
608                 print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
609         }
610 }
611
612 if ($config{USE_OPENSSL} eq "y") {
613         unless (-r "src/modules/m_ssl_openssl.cpp") {
614                 print "Symlinking src/modules/m_ssl_openssl.cpp from extra/\n";
615                 symlink "extra/m_ssl_openssl.cpp", "src/modules/m_ssl_openssl.cpp" or print STDERR "Symlink failed: $!";
616         }
617         $failed = 0;
618         if ($interactive && $config{CERTGEN} eq 'y')
619         {
620                 unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
621                         print "SSL Certificates Not found, Generating.. \n\n
622 *************************************************************
623 * Generating the certificates may take some time, go grab a *
624 * coffee, or something.                                     *
625 *************************************************************\n\n";
626                         system "./tools/genssl openssl";
627                         print "\nCertificate generation complete, copying to config directory... ";
628                         File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
629                         File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
630                         File::Copy::move("dhparams.pem", "$config{CONFIG_DIR}/dhparams.pem") or print STDERR "Could not copy dhparams.pem!\n";
631                         print "Done.\n\n";
632                 } else {
633                         print "SSL Certificates found, skipping.\n\n"
634                 }
635         }
636         else
637         {
638                 print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
639         }
640 }
641 if (($config{USE_GNUTLS} eq "n") && ($config{USE_OPENSSL} eq "n")) {
642         print "Skipping SSL Certificate generation, SSL support is not available.\n\n";
643 }
644
645 depcheck();
646 writefiles(1);
647 makecache();
648
649 print "\n\n";
650 print "To build your server with these settings, please run '\e[1;32mmake\e[0m' now.\n";
651 if (($config{USE_GNUTLS} eq "y") || ($config{USE_OPENSSL} eq "y")) {
652         print "Please note: for \e[1;32mSSL support\e[0m you will need to load required\n";
653         print "modules in your config. This configure script has added those modules to the\n";
654         print "build process. For more info please refer to:\n";
655         print "\e[1;32mhttp://wiki.inspircd.org/Installation_From_Tarball\e[0m\n";
656 }
657 print "*** \e[1;32mRemember to edit your configuration files!!!\e[0m ***\n\n\n";
658
659 ################################################################################
660 #                             HELPER FUNCTIONS                          #
661 ################################################################################
662 sub getcache {
663         # Retrieves the .config.cache file, and loads values into the main config hash.
664         open(CACHE, ".config.cache") or return 0;
665         while (<CACHE>) {
666                 chomp;
667                 # Ignore Blank lines, and comments..
668                 next if /^\s*$/;
669                 next if /^\s*#/;
670                 my ($key, $value) = split("=", $_, 2);
671                 $value =~ /^\"(.*)\"$/;
672                 # Do something with data here!
673                 $config{$key} = $1;
674         }
675         close(CACHE);
676         return 1;
677 }
678
679 sub makecache {
680         # Dump the contents of %config
681         print "Writing \e[1;32mcache file\e[0m for future ./configures ...\n";
682         open(FILEHANDLE, ">.config.cache");
683         foreach my $key (keys %config) {
684                 print FILEHANDLE "$key=\"$config{$key}\"\n";
685         }
686         close(FILEHANDLE);
687 }
688
689 sub dir_check {
690         my ($desc, $hash_key) = @_;
691         my $complete = 0;
692         while (!$complete) {
693                 print "In what directory $desc?\n";
694                 print "[\e[1;32m$config{$hash_key}\e[0m] -> ";
695                 chomp(my $var = <STDIN>);
696                 if ($var eq "") {
697                         $var = $config{$hash_key};
698                 }
699                 if ($var =~ /^\~\/(.+)$/) {
700                         # Convert it to a full path..
701                         $var = resolve_directory($ENV{HOME} . "/" . $1);
702                 }
703                 elsif ((($config{OSNAME} =~ /MINGW32/i) and ($var !~ /^[A-Z]{1}:\\.*/)) and (substr($var,0,1) ne "/"))
704                 {
705                         # Assume relative Path was given.. fill in the rest.
706                         $var = $this . "/$var";
707                 }
708
709                 $var = resolve_directory($var);
710                 if (! -e $var) {
711                         print "$var does not exist. Create it?\n[\e[1;32my\e[0m] ";
712                         chomp(my $tmp = <STDIN>);
713                         if (($tmp eq "") || ($tmp =~ /^y/i)) {
714                                 # Attempt to Create the Dir..
715                                 my $chk = eval {
716                                         use File::Path ();
717                                         File::Path::mkpath($var, 0, 0777);
718                                         1;
719                                 };
720                                 unless (defined($chk) && -d $var) {
721                                         print "Unable to create directory. ($var)\n\n";
722                                         # Restart Loop..
723                                         next;
724                                 }
725                         } else {
726                                 # They said they don't want to create, and we can't install there.
727                                 print "\n\n";
728                                 next;
729                         }
730                 } else {
731                         if (!is_dir($var)) {
732                                 # Target exists, but is not a directory.
733                                 print "File $var exists, but is not a directory.\n\n";
734                                 next;
735                         }
736                 }
737                 # Either Dir Exists, or was created fine.
738                 $config{$hash_key} = $var;
739                 $complete = 1;
740                 print "\n";
741         }
742 }
743
744 our $SHARED = "";
745
746 my ($mliflags, $mfrules, $mobjs, $mfcount) = ("", "", "", 0);
747
748 sub writefiles {
749         my($writeheader) = @_;
750         # First File.. config.h
751         chomp(my $incos = `uname -n -s -r`);
752         chomp(my $version = `sh src/version.sh`);
753         chomp(my $revision2 = getrevision());
754         my $branch = "InspIRCd-0.0";
755         if ($version =~ /^(InspIRCd-[0-9]+\.[0-9]+)\.[0-9]+/)
756         {
757                 $branch = $1;
758         }
759         if ($writeheader == 1)
760         {
761                 print "Writing \e[1;32mconfig.h\e[0m\n";
762                 open(FILEHANDLE, ">include/config.h.tmp");
763                 print FILEHANDLE <<EOF;
764 /* Auto generated by configure, do not modify! */
765 #pragma once
766
767 #define BRANCH "$branch"
768 #define VERSION "$version"
769 #define REVISION "$revision2"
770 #define SYSTEM "$incos"
771
772 #define CONFIG_PATH "$config{CONFIG_DIR}"
773 #define DATA_PATH "$config{DATA_DIR}"
774 #define LOG_PATH "$config{LOG_DIR}"
775 #define MOD_PATH "$config{MODULE_DIR}"
776
777 EOF
778
779                 if ($config{OSNAME} =~ /SunOS/i) {
780                         print FILEHANDLE "#define IS_SOLARIS\n";
781                 }
782                 if ($config{OSNAME} =~ /MINGW32/i) {
783                         print FILEHANDLE "#define IS_MINGW\n";
784                 }
785                 if ($config{HAS_STDINT} eq "true") {
786                         print FILEHANDLE "#define HAS_STDINT\n";
787                 }
788                 if ($config{HAS_EVENTFD} eq 'true') {
789                         print FILEHANDLE "#define HAS_EVENTFD\n";
790                 }
791                 if ($config{HAS_CLOCK_GETTIME} eq 'true') {
792                         print FILEHANDLE "#define HAS_CLOCK_GETTIME\n";
793                 }
794                 my $use_hiperf = 0;
795                 if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) {
796                         print FILEHANDLE "#define USE_KQUEUE\n";
797                         $config{SOCKETENGINE} = "socketengine_kqueue";
798                         $use_hiperf = 1;
799                 }
800                 if (($has_epoll) && ($config{USE_EPOLL} eq "y")) {
801                         print FILEHANDLE "#define USE_EPOLL\n";
802                         $config{SOCKETENGINE} = "socketengine_epoll";
803                         $use_hiperf = 1;
804                 }
805                 if (($has_ports) && ($config{USE_PORTS} eq "y")) {
806                         print FILEHANDLE "#define USE_PORTS\n";
807                         $config{SOCKETENGINE} = "socketengine_ports";
808                         $use_hiperf = 1;
809                 }
810                 # user didn't choose either epoll or select for their OS.
811                 # default them to USE_SELECT (ewwy puke puke)
812                 if (!$use_hiperf) {
813                         print "no hi-perf, " . $config{USE_POLL};
814                         if ($config{USE_POLL} eq "y")
815                         {
816                                 print FILEHANDLE "#define USE_POLL\n";
817                                 $config{SOCKETENGINE} = "socketengine_poll";
818                         }
819                         else
820                         {
821                                 print FILEHANDLE "#define USE_SELECT\n";
822                                 $config{SOCKETENGINE} = "socketengine_select";
823                         }
824                 }
825
826                 if ($config{HAS_DEFER} eq "TCP_DEFER_ACCEPT") {
827                         print FILEHANDLE "#define USE_TCP_DEFER_ACCEPT\n";
828                 } elsif ($config{HAS_DEFER} eq "SO_ACCEPTFILTER") {
829                         print FILEHANDLE "#define USE_SO_ACCEPTFILTER\n"
830                 }
831
832                 print FILEHANDLE "\n#include \"threadengines/threadengine_pthread.h\"\n";
833                 close(FILEHANDLE);
834                 
835                 my $file = 'include/config.h';
836                 my $diff = 0;
837                 open my $fh1, $file or $diff = 1;
838                 open my $fh2, $file.'.tmp' or die "Can't read $file.tmp that we just wrote: $!";
839                 while (!$diff) {
840                         my $line1 = <$fh1>;
841                         my $line2 = <$fh2>;
842                         if (defined($line1) != defined($line2)) {
843                                 $diff = 1;
844                         } elsif (!defined $line1) {
845                                 last;
846                         } else {
847                                 $diff = ($line1 ne $line2);
848                         }
849                 }
850                 if ($diff) {
851                         unlink $file;
852                         rename "$file.tmp", $file;
853                 } else {
854                         unlink "$file.tmp";
855                 }
856         }
857
858         # Write all .in files.
859         my $tmp = "";
860         my $file = "";
861         my $exe = "inspircd";
862
863         # Do this once here, and cache it in the .*.inc files,
864         # rather than attempting to read src/version.sh from
865         # compiled code -- we might not have the source to hand.
866         # Fix for bug#177 by Brain.
867
868         chomp($version = `sh ./src/version.sh`);
869         chomp(my $revision = getrevision());
870         $version = "$version(r$revision)";
871
872         # We can actually parse any file starting with . and ending with .inc,
873         # but right now we only parse .inspircd.inc to form './inspircd'
874         prepare_dynamic_makefile();
875
876         my @dotfiles = qw(main.mk inspircd);
877         push @dotfiles, 'org.inspircd.plist' if $config{OSNAME} eq 'darwin';
878
879         foreach my $file (@dotfiles) {
880                 open(FILEHANDLE, "make/template/$file") or die "Can't open make/template/$file: $!";
881                 $_ = join '', <FILEHANDLE>;
882                 close(FILEHANDLE);
883
884                 $config{BUILD_DIR} ||= resolve_directory($config{ME}."/build");
885
886                 for my $var (qw(
887                         CXX SYSTEM BASE_DIR CONFIG_DIR MODULE_DIR BINARY_DIR BUILD_DIR DATA_DIR UID
888                         STARTSCRIPT DESTINATION SOCKETENGINE
889                 )) {
890                         s/\@$var\@/$config{$var}/g;
891                 }
892                 s/\@EXECUTABLE\@/$exe/ if defined $exe;
893                 s/\@VERSION\@/$version/ if defined $version;
894
895                 if ($file eq 'main.mk') {
896                         print "Writing \e[1;32mGNUmakefile\e[0m ...\n";
897
898                         my $mk_tmp = $_;
899                         s/\@IFDEF (\S+)/ifdef $1/g;
900                         s/\@IFNDEF (\S+)/ifndef $1/g;
901                         s/\@IFEQ (\S+) (\S+)/ifeq ($1,$2)/g;
902                         s/\@IFNEQ (\S+) (\S+)/ifneq ($1,$2)/g;
903                         s/\@ELSIFEQ (\S+) (\S+)/else ifeq ($1,$2)/g;
904                         s/\@ELSE/else/g;
905                         s/\@ENDIF/endif/g;
906                         s/ *\@BSD_ONLY .*\n//g;
907                         s/\@GNU_ONLY //g;
908                         s/\@DO_EXPORT (.*)/export $1/g;
909                         open MKF, '>GNUmakefile' or die "Can't write to GNUmakefile: $!";
910                         print MKF $_;
911                         close MKF;
912
913                         print "Writing \e[1;32mBSDmakefile\e[0m ...\n";
914                         $_ = $mk_tmp;
915                         s/\@IFDEF (\S+)/.if defined($1)/g;
916                         s/\@IFNDEF (\S+)/.if !defined($1)/g;
917                         s/\@IFEQ (\S+) (\S+)/.if $1 == $2/g;
918                         s/\@IFNEQ (\S+) (\S+)/.if $1 != $2/g;
919                         s/\@ELSIFEQ (\S+) (\S+)/.elif $1 == $2/g;
920                         s/\@ELSE/.else/g;
921                         s/\@ENDIF/.endif/g;
922                         s/\@BSD_ONLY //g;
923                         s/ *\@GNU_ONLY .*\n//g;
924                         $mk_tmp = $_;
925                         $mk_tmp =~ s#\@DO_EXPORT (.*)#"MAKEENV += ".join ' ', map "$_='\${$_}'", split /\s/, $1#eg;
926                         open MKF, '>BSDmakefile' or die "Can't write to BSDmakefile: $!";
927                         print MKF $mk_tmp;
928                         close MKF;
929                 } else {
930                         print "Writing \e[1;32m$file\e[0m ...\n";
931                         open(FILEHANDLE, ">$file") or die("Can't write to $file: $!\n");
932                         print FILEHANDLE $_;
933                         close(FILEHANDLE);
934                 }
935         }
936
937         chmod 0755, 'inspircd';
938 }
939
940 sub depcheck
941 {
942         getmodules();
943         for my $mod (@modlist) {
944                 getcompilerflags("src/modules/m_$mod.cpp");
945                 getlinkerflags("src/modules/m_$mod.cpp");
946         }
947 }
948
949 sub prepare_dynamic_makefile
950 {
951         my $i = 0;
952
953         if (!$has_epoll)
954         {
955                 $config{USE_EPOLL} = 0;
956         }
957         if (!$has_kqueue)
958         {
959                 $config{USE_KQUEUE} = 0;
960         }
961         if (!$has_ports)
962         {
963                 $config{USE_PORTS} = 0;
964         }
965 }
966
967 # Routine to list out the extra/ modules that have been enabled.
968 # Note: when getting any filenames out and comparing, it's important to lc it if the
969 # file system is not case-sensitive (== Epoc, MacOS, OS/2 (incl DOS/DJGPP), VMS, Win32
970 # (incl NetWare, Symbian)). Cygwin may or may not be case-sensitive, depending on
971 # configuration, however, File::Spec does not currently tell us (it assumes Unix behavior).
972 sub list_extras () {
973         use File::Spec;
974         # @_ not used
975         my $srcdir = File::Spec->catdir("src", "modules");
976         my $abs_srcdir = File::Spec->rel2abs($srcdir);
977         local $_;
978         my $dd;
979         opendir $dd, File::Spec->catdir($abs_srcdir, "extra") or die (File::Spec->catdir($abs_srcdir, "extra") . ": $!\n");
980         my @extras = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
981         closedir $dd;
982         undef $dd;
983         opendir $dd, $abs_srcdir or die "$abs_srcdir: $!\n";
984         my @sources = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
985         closedir $dd;
986         undef $dd;
987         my $maxlen = (sort { $b <=> $a } (map {length($_)} (@extras)))[0];
988         my %extras = ();
989 EXTRA:  for my $extra (@extras) {
990                 next if (File::Spec->curdir() eq $extra || File::Spec->updir() eq $extra);
991                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
992                 my $abs_source = File::Spec->catfile($abs_srcdir, $extra);
993                 next unless ($extra =~ m/\.(cpp|h)$/ || (-d $abs_extra)); # C++ Source/Header, or directory
994                 if (-l $abs_source) {
995                         # Symlink, is it in the right place?
996                         my $targ = readlink($abs_source);
997                         my $abs_targ = File::Spec->rel2abs($targ, $abs_srcdir);
998                         if ($abs_targ eq $abs_extra) {
999                                 $extras{$extra} = "\e[32;1menabled\e[0m";
1000                         } else {
1001                                 $extras{$extra} = sprintf("\e[31;1mwrong symlink target (%s)\e[0m", $abs_targ);
1002                         }
1003                 } elsif (-e $abs_source) {
1004                         my ($devext, $inoext) = stat($abs_extra);
1005                         my ($devsrc, $inosrc, undef, $lnksrc) = stat($abs_source);
1006                         if ($lnksrc > 1) {
1007                                 if ($devsrc == $devext && $inosrc == $inoext) {
1008                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1009                                 } else {
1010                                         $extras{$extra} = sprintf("\e[31;1mwrong hardlink target (%d:%d)\e[0m", $devsrc, $inosrc);
1011                                 }
1012                         } else {
1013                                 open my $extfd, "<", $abs_extra;
1014                                 open my $srcfd, "<", $abs_source;
1015                                 local $/ = undef;
1016                                 if (scalar(<$extfd>) eq scalar(<$srcfd>)) {
1017                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1018                                 } else {
1019                                         $extras{$extra} = sprintf("\e[31;1mout of synch (re-copy)\e[0m");
1020                                 }
1021                         }
1022                 } else {
1023                         $extras{$extra} = "\e[33;1mdisabled\e[0m";
1024                 }
1025         }
1026         # Now let's add dependency info
1027         for my $extra (keys(%extras)) {
1028                 next unless $extras{$extra} =~ m/enabled/; # only process enabled extras.
1029                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
1030                 my @deps = split / +/, getdependencies($abs_extra);
1031                 for my $dep (@deps) {
1032                         if (exists($extras{$dep})) {
1033                                 my $ref = \$extras{$dep}; # Take reference.
1034                                 if ($$ref !~ m/needed by/) {
1035                                         # First dependency found.
1036                                         if ($$ref =~ m/enabled/) {
1037                                                 $$ref .= " (needed by \e[32;1m$extra\e[0m";
1038                                         } else {
1039                                                 $$ref =~ s/\e\[.*?m//g; # Strip out previous coloring. Will be set in bold+red+blink later.
1040                                                 $$ref .= " (needed by \e[0;32;1;5m$extra\e[0;31;1;5m";
1041                                         }
1042                                 } else {
1043                                         if ($$ref =~ m/enabled/) {
1044                                                 $$ref .= ", \e[32;1m$extra\e[0m";
1045                                         } else {
1046                                                 $$ref .= ", \e[0;32;1;5m$extra\e[0;31;1;5m";
1047                                         }
1048                                 }
1049                         }
1050                 }
1051         }
1052         for my $extra (sort {$a cmp $b} keys(%extras)) {
1053                 my $text = $extras{$extra};
1054                 if ($text =~ m/needed by/ && $text !~ m/enabled/) {
1055                         printf "\e[31;1;5m%-*s = %s%s\e[0m\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? ")" : "");
1056                 } else {
1057                         printf "%-*s = %s%s\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? "\e[0m)" : "");
1058                 }
1059         }
1060         return keys(%extras) if wantarray; # Can be used by manage_extras.
1061 }
1062
1063 sub enable_extras (@) {
1064         my (@extras) = @_;
1065         for my $extra (@extras) {
1066                 my $extrapath = "src/modules/extra/$extra";
1067                 if (!-e $extrapath) {
1068                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : No such file or directory in src/modules/extra\n";
1069                         next;
1070                 }
1071                 my $source = "src/modules/$extra";
1072                 if (-e $source) {
1073                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : destination in src/modules exists (might already be enabled?)\n";
1074                         next;
1075                 }
1076                 # Get dependencies, and add them to be processed.
1077                 my @deps = split / +/, getdependencies($extrapath);
1078                 for my $dep (@deps) {
1079                         next if scalar(grep { $_ eq $dep } (@extras)) > 0; # Skip if we're going to be enabling it anyway.
1080                         if (!-e "src/modules/$dep" && !-e "include/$dep") {
1081                                 if (-e "src/modules/extra/$dep") {
1082                                         print STDERR "Will also enable extra \e[32;1m$dep\e[0m (needed by \e[32;1m$extra\e[0m)\n";
1083                                         push @extras, $dep;
1084                                 } else {
1085                                         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";
1086                                 }
1087                         }
1088                 }
1089                 print "Enabling $extra ... \n";
1090                 symlink "extra/$extra", $source or print STDERR "$source: Cannot link to 'extra/$extra': $!\n";
1091         }
1092 }
1093
1094 sub disable_extras (@)
1095 {
1096         opendir my $dd, "src/modules/extra/";
1097         my @files = readdir($dd);
1098         closedir $dd;
1099         my (@extras) = @_;
1100 EXTRA:  for my $extra (@extras) {
1101                 my $extrapath = "src/modules/extra/$extra";
1102                 my $source = "src/modules/$extra";
1103                 if (!-e $extrapath) {
1104                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : Is not an extra\n";
1105                         next;
1106                 }
1107                 if ((! -l $source) || readlink($source) ne "extra/$extra") {
1108                         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";
1109                         next;
1110                 }
1111                 # Check if anything needs this.
1112                 for my $file (@files) {
1113                         my @deps = split / +/, getdependencies("src/modules/extra/$file");
1114                         # File depends on this extra...
1115                         if (scalar(grep { $_ eq $extra } @deps) > 0) {
1116                                 # And is both enabled and not about to be disabled.
1117                                 if (-e "src/modules/$file" && scalar(grep { $_ eq $file } @extras) < 1) {
1118                                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : is needed by \e[32;1m$file\e[0m\n";
1119                                         next EXTRA;
1120                                 }
1121                         }
1122                 }
1123                 # Now remove.
1124                 print "Disabling $extra ... \n";
1125                 unlink "src/modules/$extra" or print STDERR "Cannot disable \e[32;1m$extra\e[0m : $!\n";
1126         }
1127 }