But if your virtual machine is hosting a qemu guest, then in that guest a fork/exec can take 0.2 of a second, and MAKEDEV generic-i386 can take a couple of hours. (This is because the kqemu kernel module is not available, http://www.linuxquestions.org/questions/linux-virtualization-and-cloud-90/qemu-running-on-ubuntu-vmware-guest-cannot-find-dev-kvm-936253/).
The first hacky-hack to cut down on the number of fork/exec is to stop calling sed quite so often, cue this patch (requires MAKEDEV to run under bash).
--- /sbin/MAKEDEV 2009-07-30 08:39:09.000000000 -0700 +++ /MAKEDEV 2014-02-21 06:31:43.000000000 -0800 @@ -1,4 +1,4 @@ -#! /bin/sh - +#! /bin/bash - # $Id$ #---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---# @@ -116,7 +116,9 @@ devicename () { # translate device names to something safe # A-Z is not full alphabet in all locales (e.g. in et_EE) - echo "$*" | LC_ALL=C sed -e 's/[^A-Za-z0-9_]/_/g' + #echo "$*" | LC_ALL=C sed -e 's/[^A-Za-z0-9_]/_/g' + echo "${*//[^ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789]/_}" + } makedev () { # usage: makedev name [bcu] major minor owner group mode @@ -231,12 +233,14 @@ exec 3<$procfs/devices while read major device extra <&3 do - device=`echo $device | sed 's#/.*##'` + #device=`echo $device | sed 's#/.*##'` + device="${device%%/*}" case "$major" in Character|Block|'') ;; *) - safedevname=`devicename $device` + safedevname="${device//[^ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234566 +789]/_}" eval "major_$safedevname=$major" devices="$devices $device" ;; @@ -247,7 +251,8 @@ Major () { device=$2 - devname=`devicename $1` + devname="${1//[^ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234566 +789]/_}" if [ "$opt_d" ] then echo -1 # don't care @@ -2149,7 +2154,8 @@ exec 3<$procfs/devices while read major device extra <&3 do - device=`echo $device | sed 's#/.*##'` + # device=`echo $device | sed 's#/.*##'` + device="${device%%/*}" case "$major" in Character|Block|'') ;;
The next hack is to stop the 5 or 6 fork/exec when MAKEDEV deletes a device node, creates a (temporary device node), chmods it, chowns it, and renames it.
How do we do that? We run MAKEDEV -n so that it does none of these and then feed the output to a perl script which will do them.
Sadly perl has no native mknod call and there are no libraries in this environment, and so I use perl's blessed syscall function with a hard-wired syscall 133 for mknod (as it is, on my kernel):
time /MAKEDEV -n generic-i386 | perl -ne ' print; umask(0); ($c, $f, $node, $major, $minor, $own, $perm) = split; if ($node eq "->") { symlink($major, $f) || die "sym: $!"; } else { # system("mknod",$f,$node,$major,$minor) && die "mknod($f,$node,$major,$minor): $? $!"; # chmod(oct($perm), $f) || die "chmod: $!"; $n=0; $n=0010000 if ($node eq "f"); $n=0020000 if ($node eq "c"); $n=0060000 if ($node eq "b"); $n=0140000 if ($node eq "s"); if (syscall(133, $f, oct($perm) | $n, (($minor & 0xff) | (($major & 0xfff) << 8) | (( ($minor & ~0xff)) << 12) | (( ($major & ~0xfff)) << 32))) == -1) { die "syscall: $!"; } ($user,$group)=split(/:/,$own); $user=getpwnam($user); $group=getgrnam($group); chown($user,$group,$f) || die "chown: $own $!"; } '
Leaving in the system("mknod,...) took around 24 minutes, but moving straight to syscall(mknod,...) takes1 minute 8 seconds.
I did toy with having bash use printf or something to pack a binary tar archive (or even getting perl to pack a tar archive) to pipe to tar -x, but... this will have to do for now.
I suspect this depends on a bug in MAKEDEV which seems to still create sub-directories needed even in -n mode.
It would have been better to pipe the output to a c program which would parse it, I will do that, another day...