#!/usr/bin/perl
# Copyright 1999-2014. Parallels IP Holdings GmbH. All Rights Reserved.

use Config;

my $rc_conf = "/etc/rc.conf";

my %SERVICES = (
	### 'core' - is a preset with required services
	### 'additional' - is a preset with not required services
	###
	### rules:
	### 1) status "YES" or "NO" will be set for all 'core' and 'additional' services;
	### 2) all 'core' services will be uncommented in rc.conf;
	### 3) if no one of 'core' services wasn't found in rc.conf then all 'core' services
	###    will be added at the end of rc.conf;
	### 4) 
	'samba' => {'core' => [('smbd', 'nmbd')], 'additional' => [('samba', 'nmbd', 'winbind')]}
);

sub freebsd5_rc_service($$)
{
	my ($service, $action) = @_;

	unless (-f $rc_conf) {
		die "Unable to find '$rc_conf' file\n";
	}

	open (FD_in, "$rc_conf", ) || die "Unable to open restart script for '$rc_conf' service: $!\n";
	flock FD_in, LOCK_EX;
	binmode FD_in;

	open (FD_out, ">$rc_conf.tmp", ) || die "Unable to create temporary file '$rc_conf.tmp': $!\n";
	flock FD_out, LOCK_EX;
	binmode FD_out;

	my $allow_start_STATUS = (lc($action) eq 'on' ? 'YES' : 'NO');

	### fetch service description
	my $service_descr = $SERVICES{$service};
	my $core_regexp = join('|', @{$$service_descr{'core'}});
	my $additional_regexp = join('|', @{$$service_descr{'additional'}});

	$| = 1; ### do not use buffering output

	my $done = 0;
	while (<FD_in>) {
		chomp $_;

		### turn on/off core services
		if (s/^\s*#*\s*((${core_regexp})_enable).*$/\1="$allow_start_STATUS"/) {
			$done = 1;
		}

		### turn on/off additional services
		s/^(\s*#*\s*(${additional_regexp})_enable).*$/\1="$allow_start_STATUS"/;

		print FD_out "$_\n";
	}

	### if no one core service has been turned on/off then do it
	unless ($done) {
		print FD_out "\n### Samba service directives\n";
		foreach my $i (@{$$service_descr{'core'}}) {
			print FD_out "${i}_enable=\"$allow_start_STATUS\"\n";
		}
	}

	flock FD_out, LOCK_UN;
	close FD_out;

	unless (rename("$rc_conf.tmp", $rc_conf)) {
		warn "Unable to '$action' service '$service': an error occured during rename '$rc_conf.tmp' to $rc_conf: $!\n";
	}

	flock FD_in, LOCK_UN;
	close FD_in;

	unlink("$rc_conf.tmp") if ( -f "$rc_conf.tmp");
}


sub freebsd4_rc_service($$)
{
	my ($service, $action) = @_;

	my $rc_script = "/usr/local/etc/rc.d/$service.sh";

	unless ( -f $rc_script) {
		die "Unable to find service restart script '$rc_script'\n";
	}

	##########################################################
	### bug 51175 workaround
	### some new packages use new rc scripts functionality
	if (0 == system("sh $rc_script rcvar >/dev/null 2>&1")) {
		&freebsd5_rc_service($service, $action);
	} else {
		if (lc($action) eq 'on') {
			chmod 0755, $rc_script;
		} elsif (lc($action) eq 'off') {
			chmod 0644, $rc_script;
		}
	}
}

my ($service, $action) = @ARGV;

unless ($service && $action && (lc($service) !~ /^\s*(-h|--help)\s*$/)) {
	print "Usage: chkconfig <name> <on|off>\n\n";
	print "    <name> - is an name of some system service\n";
	print "    <on|off> - turn on|off the service with name <name>\n";
	die "\n";
}

unless (exists $SERVICES{$service}) {
	print "Unknown service '$service'. chkconfig supports following services:\n";
	foreach my $i (keys %SERVICES) {
		print "$i\n";
	}
	die "\n";
}

unless (lc($action) =~ /^on|off$/) {
	die "Error: wrong action '$action' is used.\n";
}

if ($Config{'osvers'} =~ /^4/ ) {
	&freebsd4_rc_service($service, $action);
} elsif ($Config{'osvers'} =~ /(^5|^6)/ ) {
	&freebsd5_rc_service($service, $action);
} else {
	die "Unknown OS release number '" . $Config{'osvers'} . "'\n";
}

exit 0;

