#!/usr/bin/perl
# Copyright 2002 MandrakeSoft - released under the GNU GPL v2
use Config;
use MDK::Common;
Config->import;
my ($arch) = $Config{archname} =~ /(.*?)-/;

die "usage: makedev <directory> [<device_name>]\n" if !member($#ARGV, qw(0 1));
my ($dev_dir, $dev_name) = @ARGV;
my $makedev_d = '/etc/makedev.d';

umask 0;

my %vars;

my %uids = map { (split ':')[0,2] } cat_('/etc/passwd');
my %gids = map { (split ':')[0,2] } cat_('/etc/group');
my @lines = map { cat_($_) } sort(glob_("$makedev_d/*.conf"));

foreach (@lines) {
    s/\s*$//;
    next if /^$/ || /^#/; # empty lines & comments are simply dropped :)

    s/\$(\w+)/$vars{$1} || die qq(unrecognized macro $1 at "$_"\n)/ge;

    if (/^=(\w+)(.*)/) {
	$vars{$1} = $2;
    } elsif (/^l\s+(\S+)\s+(\S+)$/) {
	symlink $2, "$dev_dir/$1" if !$dev_name || ($dev_name && $1 =~ $dev_name);
    } elsif (/^[bc]/) {
	my ($kind, $permission, $owner, $group, $major, $minor, $minor_step, $nb, $name, $base) = split;
	next if $dev_name && $name !~ /^$dev_name$/;
	my $uid = $uids{$owner};
	my $gid = $gids{$group};
	my $major_minor = make_dev_t($major, $minor);
	$permission = oct($permission) | ($kind eq 'b' ? 0x6000 : 0x2000);

	next if $name =~ /^(efirtc)$/ && $arch !~ /ia64/;
	next if $name =~ /^(kbd|openprom)$/ && $arch !~ /sparc/;

	$name = "$dev_dir/$name";

	make_dev($name, $base, $permission, $major_minor, $uid, $gid);

	if ($nb > 1) {
	    my $max = $major_minor + $minor_step * ($nb - 1);
	    $name .= "%d" if $name !~ /%/;
	    do {
		$base++;
		$major_minor += $minor_step;
		make_dev($name, $base, $permission, $major_minor, $uid, $gid);
	    } until $major_minor == $max;
	}
    } elsif (/^[as]\s/) {
	# old line, not using them
    } else { warn qq(unrecognised line "$_"\n) }
}

sub make_dev_t { ($_[0] << 8) | $_[1] }

sub make_dev {
	my ($name, $base, $permission, $major_minor, $uid, $gid) = @_;
	my $file = sprintf($name, $base);
	if (syscall_('mknodat', -100, $file, $permission, $major_minor) || do {
	    mkdir_p(dirname($file));  # it failled, try to create directory in case they're missing
	    syscall_('mknodat', -100, $file, $permission, $major_minor); #or warn "mknodat failed for $file\n";
	}) { chown $uid, $gid, $file }
}
