+ eval {
+ # Redirect simple requests to controller.pl without any GET/POST
+ # param to the login page.
+ $self->redirect_to_login(error => 'action') if !$::form->{action};
+
+ # Show an error if the »action« parameter doesn't match the
+ # pattern »Controller/action«.
+ $::form->{action} =~ m|^ ( [A-Z] [A-Za-z0-9_]* ) / ( [a-z] [a-z0-9_]* ) ( \. [a-zA-Z]+ )? $|x || die "Unroutable request -- invalid controller/action.\n";
+ ($controller, $action) = ($1, $2);
+ delete $::form->{action};
+
+ $request_type = $3 ? lc(substr($3, 1)) : 'html';
+
+ 1;
+ } or do {
+ $::form->{label_error} = $::request->{cgi}->pre($EVAL_ERROR);
+ show_error('generic/error');
+ };
+
+ return (controller => $controller, action => $action, request_type => $request_type);
+}
+
+sub _cache_file_modification_times {
+ my ($self) = @_;
+
+ return unless $self->_interface_is_fcgi && $::lx_office_conf{debug}->{restart_fcgi_process_on_changes};
+
+ require File::Find;
+ require POSIX;
+
+ my $wanted = sub {
+ return unless $File::Find::name =~ m/\.(?:pm|f?pl|html|conf|conf\.default)$/;
+ $fcgi_file_cache{ $File::Find::name } = (stat $File::Find::name)[9];
+ };
+
+ my $cwd = POSIX::getcwd();
+ File::Find::find($wanted, map { "${cwd}/${_}" } qw(config bin SL templates/webpages));
+ map { my $name = "${cwd}/${_}"; $fcgi_file_cache{$name} = (stat $name)[9] } qw(admin.pl dispatcher.fpl);
+}
+
+sub _watch_for_changed_files {
+ my ($self) = @_;
+
+ return unless $self->_interface_is_fcgi && $::lx_office_conf{debug}->{restart_fcgi_process_on_changes};
+
+ my $ok = all { (stat($_))[9] == $fcgi_file_cache{$_} } keys %fcgi_file_cache;
+ return if $ok;
+ $::lxdebug->message(LXDebug::DEBUG1(), "Program modifications detected. Restarting.");
+ $self->restart_after_request(1);
+}
+
+sub get_standard_filehandles {
+ my $self = shift;
+
+ return $self->{interface} =~ m/f(?:ast)cgi/i ? $self->{request}->GetHandles() : (\*STDIN, \*STDOUT, \*STDERR);
+}
+
+sub _check_for_old_config_files {
+ my @old_files = grep { -f "config/${_}" } qw(authentication.pl console.conf lx-erp.conf lx-erp-local.conf);
+ return unless @old_files;
+
+ $::form->{title} = $::locale->text('Old configuration files');
+ $::form->header;
+ print $::form->parse_html_template('login_screen/old_configuration_files', { FILES => \@old_files });
+
+ end_request();
+}
+
+sub _parse_number_with_unit {
+ my ($number) = @_;
+
+ return undef unless defined $number;
+ return $number unless $number =~ m{^ \s* (\d+) \s* ([kmg])b \s* $}xi;
+
+ my %factors = (K => 1024, M => 1024 * 1024, G => 1024 * 1024 * 1024);
+
+ return $1 * $factors{uc $2};
+}
+
+sub _memory_usage_is_too_high {
+ return undef unless $::lx_office_conf{system};
+
+ my %limits = (
+ rss => _parse_number_with_unit($::lx_office_conf{system}->{memory_limit_rss}),
+ size => _parse_number_with_unit($::lx_office_conf{system}->{memory_limit_vsz}),
+ );
+
+ # $::lxdebug->dump(0, "limits", \%limits);
+
+ return undef unless $limits{rss} || $limits{vsz};
+
+ my %usage;
+
+ my $in = IO::File->new("/proc/$$/status", "r") or return undef;
+
+ while (<$in>) {
+ chomp;
+ $usage{lc $1} = _parse_number_with_unit($2) if m{^ vm(rss|size): \s* (\d+ \s* [kmg]b) \s* $}ix;
+ }
+
+ $in->close;
+
+ # $::lxdebug->dump(0, "usage", \%usage);
+
+ foreach my $type (keys %limits) {
+ next if !$limits{$type};
+ next if $limits{$type} >= ($usage{$type} // 0);
+
+ $::lxdebug->message(LXDebug::WARN(), "Exiting due to memory size limit reached for type '${type}': limit " . $limits{$type} . " bytes, usage " . $usage{$type} . " bytes");
+
+ return 1;
+ }
+
+ return 0;
+}