#! /usr/bin/perl -w my $VERSION = qq(20051002djw); # bugs: generated configs.tbz contains empty dirs # TODO pod, automated remaster knoppix cloop, undo my $CDROM = '/cdrom'; # usually '/cdrom' if booted from dk|knoppix cd my $DKDIR = '/mnt/hda7/dk'; # must be on writable hd with a few gigs free my $DKDAT = 'KIOSK'; # for convenience, no md5sums, relative to $DKDIR/copy/cdrom/ my $scr = $0; $0 =~ s,.*/,,; # basename my $ocd = qq($CDROM); my $mcd = qq($DKDIR/master/cdrom); my $ccd = qq($DKDIR/copy/cdrom); my $tbz = qq($ccd/KNOPPIX/$0/$0-attic.tbz); my $txt = qq($ccd/KNOPPIX/$0/$0-attic.txt); my $ccf = qq($DKDIR/copy/configs); my $iso = qq($DKDIR/copy/$0.iso); my $md5 = qq(KNOPPIX/md5sums); # relative to cdrom/ ################################################################################ my $USAGE = qq( knoppix remastering script - $VERSION e.g., dpkg-purged openoffice-de-en and emacs21-common cloop file, with custom configs.tbz, knoppix.sh, boot and data files... ./$0 init; ./$0 new; ./$0 configs; ./$0 attic; ./$0 build; USAGE: $0 [ -a|--action ] OPTION OPTION: # in this order... # init $CDROM/* to $DKDIR/master (do not edit) new master to copy, tbz to configs (edit these) configs configs to tbz attic save modified/removed files (optional, enables undo) build copy to iso test info - compare master vs cdrom (slow) diff info - compare copy vs master list info - list files in copy and configs knoppix (TODO) remaster knoppix cloop undo (TODO) revert virgin copy to previous cdrom $0: USE UNDER SAME TERMS AS KNOPPIX AND AT YOUR OWN RISK. ); ################################################################################ use Getopt::Long; ### sub my_die { my $error = shift || 'unspecified error!'; die qq($USAGE$0: $error\n $!\n\n); } sub my_system { my ($cmd, $msg) = (shift, (shift || '')); warn qq(\n$msg\n $cmd\n); system $cmd || my_die qq(failed.); } sub my_copy { my ($fr, $to, $msg) = (shift, shift, (shift || qq(copying...))); $to =~ m,(.*)/.*,; -d qq($1) || my_system(qq(mkdir -p '$1'), qq(creating dir...)); -e qq($fr) && my_system(qq(cp -fRHL '$fr' '$to'), $msg); } sub diffs { # ignoring $DKDAT ... my ($fr, $to, $verbose) = (shift, shift, (shift || 0)); warn qq(\ncomparing $fr and $to files...\n\n); warn qq( m-odified, a-dded to or r-emoved from $to/ (no output implies no changes)\n\n) if $verbose; return `find {$fr,$to} \\ -path '$fr/$DKDAT' -prune -o \\ -path '$to/$DKDAT' -prune -o \\ -type f \\ -print | \\ sed -ne 's!^\\('$fr'\\|'$to'\\)/!!p' | \\ sort | uniq | \\ xargs -i diff -q '$fr/{}' '$to/{}' 2>&1 | \\ sed -e 's!^Files $fr/.\\+ and $to/\\(.\\+\\) differ\$!m: \\1!p' \\ -e 't' -ne 's!^diff: $fr/\\(.\\+\\): No such file or directory\$!a: \\1!p' \\ -e 't' -ne 's!^diff: $to/\\(.\\+\\): No such file or directory\$!r: \\1!p'`; # || qq(no differnces detected.\n); # FIXME forces scalar context } sub md5sum_knoppix { # (new and build) only if required ... -f qq($ccd/KNOPPIX/KNOPPIX) || my_die qq($ccd/KNOPPIX/KNOPPIX not found - first run $0 new); return if (-f qq($DKDIR/copy/md5sum-knoppix) && (stat qq($DKDIR/copy/md5sum-knoppix))[9] <= (stat qq($ccd/KNOPPIX/KNOPPIX))[9]); my_system(qq(cd '$ccd' && md5sum -b KNOPPIX/KNOPPIX > '$DKDIR/copy/md5sum-knoppix'), qq(KNOPPIX modified - calculating checksum - this takes a while...)); my_system(qq(echo `date --iso-8601` | \\ xargs -i touch -d '{}' '$DKDIR/copy/md5sum-knoppix' '$ccd/KNOPPIX/KNOPPIX'), qq(setting mtimes for files...)); } ### sub init { if (-e qq($mcd)) { my_die qq(master exists! if you must, firstmv or\n\n chattr -R -i $mcd/* && rm -fr $mcd\n\nno files copied.\n); } elsif (! -e qq($ocd/KNOPPIX/md5sums)) { my_die qq($ocd seems not to be a knoppix cd!\ntry umount -f '$ocd' && mount -o loop -t iso9660 dk.iso '$ocd'\n); } else { my_system(qq(mkdir -p '$mcd' && cd '$ocd' && rsync -a --exclude .rr_moved . '$mcd'), qq(copying almost EVERYTHING - this takes a while...)); my_system(qq(chattr -R +i '$mcd/'*" && chattr -R -i '$mcd/KNOPPIX/KNOPPIX'), qq(write-protecting cdrom files...)); # keep cloop writable my_system(qq(find '$mcd' -type f | sort -f), qq(listing master files...)); } warn qq(\n$0: init\n); } sub test { # obsolete? use original md5sums? if (-f qq($ocd/KNOPPIX/md5sums)) { print diffs($ocd, qq($mcd), 1); } else { my_die qq($ocd seems not to be a knoppix cd! try umount -f '$ocd' && mount -o loop -t iso9660 dk.iso '$ocd'\n); } warn qq(\n$0: test\n); } sub diff { print diffs(qq($mcd), qq($ccd), 1); warn qq(\n$0: diff\n); } sub new { if (! -e qq($mcd)) { my_die qq(master does not exist! first run\n\n $0 init\n no files copied.\n); } if (-e qq($ccd)) { my_die qq(copy exists! first mv or\n\n rm -fr $ccd\n no files copied.\n); } my_system(qq(mkdir -p '$ccd' && cd '$mcd' && rsync -a --exclude boot/isolinux/boot.msg --exclude '$tbz' --exclude '$txt' --exclude KNOPPIX/KNOPPIX --exclude '$md5' . '$ccd'), qq(copying master files to editable copy ...)); -f qq($ccd/KNOPPIX/dk/dk) || my_copy($scr, qq($ccd/KNOPPIX/dk/dk), qq(copying this script...)); -f qq($DKDIR/copy/$0) || my_copy($scr, qq($DKDIR/copy/$0), qq(copying this script...)); my_system(qq(find '$ccd' -type f | sort -f), qq(listing cdrom files...)); my_system(qq(chattr -R -i $ccd/*), qq(removing write-protection from cdrom files...)); my_system(qq(ln -f '$mcd/KNOPPIX/KNOPPIX' '$ccd/KNOPPIX/KNOPPIX'), qq(hard linking KNOPPIX...)); # FIXME $from is changeable md5sum_knoppix; # do once only, unless rebuilding KNOPPIX cloop my_system(qq(mkdir -p '$ccf' && tar -C '$ccf' -xjf '$mcd/KNOPPIX/configs.tbz'), qq(extracting configs...)); my_system(qq(find '$ccf' -type f | sort -f), qq(listing config files...)); warn qq(\nplay here...\ncd $DKDIR/copy\n); warn qq(\n$0: new\n); } sub attic { my_system(qq(echo -n > '$ccd/boot/isolinux/boot.msg' ), qq(truncating dk-generated file...)); my_system(qq(echo -n > '$ccd/KNOPPIX/md5sums'), qq(truncating dk-generated file...)); my_system(qq(touch '$txt'), qq(creating $txt ...)) unless -f $txt; my_system(qq(touch '$tbz'), qq(creating $tbz ...)) unless -f $tbz; my $diffs = diffs qq($mcd), qq($ccd); my_system(qq(cat < '$txt'\n${diffs}EOF), qq(generating $txt ...)); my $args = qq(); for (split /\n/, $diffs) { next if /KNOPPIX$/; # DON'T put cloop file in attic! next if /isolinux.bin$/; # likewise - mkisofs generates this ? my @a = split; $args .= qq( $a[1]) if $a[0] =~ /^(m|r):/; } my_system(qq(tar -C '$mcd' -cPpjf '$tbz'$args), qq(generating $tbz ...)); my_system(qq(tar -tjf '$tbz' | sort -f), qq(listing attic files...)); warn qq(\ndelete with\n rm -f '$tbz' '$txt'\n); warn qq(\n$0: attic\n); } sub configs { if (! -d qq($ccf)) { warn qq(configs does not exist! first run $0 new\n); warn qq($ccf not generated.\n); } # note: these zap any custom versions... my $CHROOT_UTILITIES = [ # from ldd `which tar` `which bzip2` ... # qq(/bin/bash), # qq(/lib/libncurses.so.5), qq(/lib/tls/libdl.so.2), qq(/lib/tls/libc.so.6), qq(/lib/ld-linux.so.2), qq(/bin/tar), qq(/lib/tls/librt.so.1), qq(/lib/tls/libc.so.6), qq(/lib/tls/libpthread.so.0), qq(/lib/ld-linux.so.2), qq(/usr/bin/bzip2), qq(/usr/lib/libbz2.so.1.0), qq(/lib/tls/libc.so.6), qq(/lib/ld-linux.so.2), ]; my $tar_args = qq(); my $rm_args = qq(); for (@$CHROOT_UTILITIES) { next unless $_; my_copy(qq($_), qq($ccf$_), qq(copying chroot utility file...)) unless -f qq($ccf$_); $tar_args .= qq( --exclude '$_' \\\n); $rm_args .= qq( '$ccf$_' \\\n); } my_system(qq(chroot '$ccf' tar -cPpjf configs.tbz --exclude configs.tbz \\\n$tar_args /), qq(building configs.tbz ...)); my $to = qq($ccd/KNOPPIX/configs.tbz); my_system(qq(mv -f '$ccf/configs.tbz' '$to'), qq(moving configs.tbz ...)); my_system(qq(tar -tPjf '$to' | grep -v '/\$' | sort -f && ls -l '$to'), qq(listing configs.tbz ...)); my_system(qq(rm -f \\\n$rm_args), qq(deleting chroot utilities...)) if $rm_args; warn qq(test with\n cd '$ccd/KNOPPIX' && ./knoppix.sh tar -xPpjf --backup=simple '$to'\n); warn qq(\n$0: configs\n); } sub build { my $boot_msg = qq($ccd/boot/isolinux/boot.msg); warn qq(generating $boot_msg ...\n); my $version = `date --iso-8601`; chomp $version; my_system qq(echo '\x0f17\x0c\x18logo.16' > $boot_msg); my_system qq(echo '' >> $boot_msg); my_system qq(echo "Press keys F2|F3|F4 for boot options (try 'kde' or 'kiosk') dk-ver: $version" >> $boot_msg); my_system qq(echo 'KNOPPIX V3.8.1 http://www.knoppix.de/ RELEASE: 2005-04-08' >> $boot_msg); # replace running script if newer (stat qq($scr))[9] > (stat qq($ccd/KNOPPIX/dk/dk))[9] && my_copy($scr, qq($ccd/KNOPPIX/dk/dk), qq(updating this script...));; # - logo.16 - convert png via ppm if (-f qq($ccd/boot/isolinux/logo.16.png) && (stat qq($ccd/boot/isolinux/logo.16.png))[9] > (stat qq($ccd/boot/isolinux/logo.16))[9]) { my_system(qq(cat $ccd/boot/isolinux/logo.16.png | \\ pngtopnm | ppmtolss16 > $ccd/boot/isolinux/logo.16), qq(converting newer logo.16.png to logo.16 ...)); } # md5sum new or modified files my ($sed_args, $md5_args) = ('', ''); for (diffs $mcd, $ccd) { print; my @a = split; my $s = $a[1]; #$s =~ s!\./!!; # $md5_args .= qq( $a[1]) if $a[0] =~ /^(m|a):/ && $a[1] !~ m!^(KNOPPIX/KNOPPIX|boot/isolinux/boot.cat|KNOPPIX/md5sums)$!; $s =~ s!/!\\/!g; # escape slashes $sed_args .= qq( -e '/$s\$/d') if $a[0] =~ /^(m|r):/; } md5sum_knoppix; # recalc if changed my_system(qq(cat $mcd/KNOPPIX/md5sums | sed $sed_args > /tmp/md5sums), qq(removing unwanted md5sums...)); my_system(qq(cd $ccd && md5sum -b $md5_args >> /tmp/md5sums), qq(generating new md5sums...)); my_system(qq(cat '$DKDIR/copy/md5sum-knoppix' /tmp/md5sums | sort -k 2 > '$ccd/KNOPPIX/md5sums')); # make the iso my_system(qq(mkisofs -pad -l -r -J -v -V '$version' -no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat -hide-rr-moved -no-bak -o '$iso' '$ccd'), qq(building iso...)); my_system(qq(ls -l '$iso'), qq(result:)); my $s = $iso; $s =~ s!/mnt/!/dev/!; # fragile! warn qq(test using\n mkdir -p /tmp/$0 && umount -f /tmp/$0 ; mount -o loop -t iso9660 $iso /tmp/$0 && ls -la /tmp/$0 or reboot using cheatcode knoppix bootfrom=$s\n\n); ### burn iso TODO use k3b meanwhile # my_system qq(); warn qq(\n$0: build\n); } sub knoppix { warn qq( note: currently using hard link to '$mcd/KNOPPIX/KNOPPIX' TODO remaster knoppix cloop - meanwhile try manually... mkdir -p '$DKDIR/copy/KNOPPIX' cp -Rp /KNOPPIX/* '$DKDIR/copy/KNOPPIX' cp --reply=yes /etc/dhcpc/resolve.conf '$DKDIR/copy/KNOPPIX/etc/dhcpc/resolve.conf' chroot '$DKDIR/copy/KNOPPIX' mount -t proc /proc proc dpkg --help dpkg --purge openoffice-de-en dpkg --purge emacs21-common umount /proc exit mkisofs -R -U -V 'foo' -P 'bar' -hide-rr-moved -cache-inodes -no-bak -pad '$DKDIR/copy/KNOPPIX/' \\ | nice -5 /usr/bin/create-compressed_fs - 65536 > '$ccd/KNOPPIX/KNOPPIX' ); warn qq(\n$0: knoppix\n); } sub undo { warn qq( TODO: meanwhile, something like... ### UNTESTED ### # cat '$mcd/KNOPPIX/dk/dk-attic.txt' | cut -d' ' -f 2 | \\ # xargs -p -i rm '$ccd'/{} && \\ # tar -C '$ccd' -xvjf '$mcd/KNOPPIX/dk/dk-attic.tbz' ); warn qq(\n$0: undo\n); } sub list { my_system(qq(find '$ccd' -type f | sort -f), qq(listing copy cdrom files...)); my_system(qq(find '$ccf' -type f | sort -f), qq(listing copy configs files...)); warn qq(\n$0: list\n); } ### start here... $> && my_die qq(you need to be root!); -W $DKDIR || my_die qq(directory '$DKDIR' must be on writable linux partition!); my $action = ''; &GetOptions('action=s' => \$action,); $action ||= $ARGV[0] if $ARGV[0]; if ($action eq 'init') { init; } elsif ($action eq 'test') { test; } elsif ($action eq 'diff') { diff; } elsif ($action eq 'list') { list; } elsif ($action eq 'new') { new; } elsif ($action eq 'configs') { configs; } elsif ($action eq 'attic') { attic; } elsif ($action eq 'build') { build; } elsif ($action eq 'knoppix') { knoppix; } elsif ($action eq 'undo') { undo; } elsif ($action eq 'md5') { md5sum_knoppix; } else { my_die qq(what do you want to do?); } exit 0; md5sum_knoppix # eof. __DATA__ cd files... cdrom/autorun.bat # open cdrom/index.html in default browser cdrom/autorun.inf # windows autorun config cdrom/autorun.pif # windows autorun executable cdrom/boot/isolinux/boot.cat # binary cdrom/boot/isolinux/boot.msg * # boot prompt (CUSTOM - add hints + ver) cdrom/boot/isolinux/f2 # boot help cdrom/boot/isolinux/f3 # boot help cdrom/boot/isolinux/f4 * # about... + more boot help (CUSTOM) cdrom/boot/isolinux/german.kbd # keyboard mappings - unused? cdrom/boot/isolinux/isolinux.bin # binary cdrom/boot/isolinux/isolinux.cfg * # define boot option behaviours (CUSTOM kiosk-mode + url) cdrom/boot/isolinux/linux # binary linux 2.6 kernel image cdrom/boot/isolinux/logo.16 * # boot splash built from logo.png (CUSTOM) cdrom/boot/isolinux/logo.png * # boot splash 6408x400px 4-bit (CUSTOM) cdrom/boot/isolinux/memtest # Memtest86 kernel cdrom/boot/isolinux/minirt.gz # boot fs - see linuxrc knoppix low-level cdrom/cdrom.ico * # windows cdrom icon (CUSTOM) cdrom/index.html * # cdrom home page seen by windows (CUSTOM) cdrom/KNOPPIX/background.png * # wm desktop bg 1024x768px (CUSTOM) cdrom/KNOPPIX/configs.tbz * # optional arbitrary files :-) (CUSTOM see make-configs-tbz.pl) cdrom/KNOPPIX/dk/debs/* * # software force installed by knoppix.sh (CUSTOM) cdrom/KNOPPIX/dk/dk * # this script cdrom/KNOPPIX/dk/dk-attic.tbz * # deleted|modified files from previous master (CUSTOM) cdrom/KNOPPIX/dk/dk-attic.txt * # list of differences betw this + previous cd (CUSTOM) cdrom/KNOPPIX/images/knoppix-24-1.png # old cdrom home page img - unused cdrom/KNOPPIX/images/knoppix-header.gif # old cdrom home page img - unused cdrom/KNOPPIX/index.html # knoppix home page, german cdrom/KNOPPIX/index_*.html # knoppix home pages, various languages cdrom/KNOPPIX/KNOPPIX * # compressed cloop fs (CUSTOM - no openoffice or emacs) cdrom/KNOPPIX/knoppix-cheatcodes.txt # boot prompts and their meaning cdrom/KNOPPIX/KNOPPIX-FAQ.txt # faq, german cdrom/KNOPPIX/KNOPPIX-FAQ-*.txt # faqs, various languages cdrom/KNOPPIX/knoppix.sh * # optional - unpack configs.tbz (CUSTOM - start servers) cdrom/KNOPPIX/knoppix-version # 3.8.1 2005-04-08 cdrom/KNOPPIX/ksplash/* * # kde splash images + config (CUSTOM - added by default 45xsession) cdrom/KNOPPIX/LICENSE.txt # gpl v2 cdrom/KNOPPIX/md5sums # used by testcd cheatcode (CUSTOM - regenerated) cdrom/KNOPPIX/MkImage-ct.exe # make KNOPPIX image file from windows cdrom/KNOPPIX/mkimg-de.exe # make KNOPPIX image file from windows cdrom/KNOPPIX/mkimg-src.zip # make KNOPPIX image file from windows cdrom/KNOPPIX/README_Security.txt # security issues config files... (all CUSTOM) configs/etc/apache/conf.d/kiosk.conf # relax httpd.conf options configs/etc/skel/.kderc # configs/etc/skel/.kde/share/config/kdesktoprc # configs/etc/X11/Xsession.d/45xsession # configs/usr/local/bin/desktop # configs/usr/local/lib/site_perl/Libdjw.pm # # kde desktop theme - better than cdrom/splash/* ? configs/usr/share/apps/ksplash/Themes/Default/splash_active_bar.png configs/usr/share/apps/ksplash/Themes/Default/splash_bottom.png configs/usr/share/apps/ksplash/Themes/Default/splash_inactive_bar.png configs/usr/share/apps/ksplash/Themes/Default/splash_top.png configs/usr/share/apps/ksplash/Themes/Default/Theme.rc # mozilla prefs configs/usr/share/knoppix/profile/.mozilla/appreg configs/usr/share/knoppix/profile/.mozilla/firefox/3d4ef4xp.default/prefs.js configs/usr/share/knoppix/profile/.mozilla/firefox/profiles.ini # www configs/var/www/777/bg_cubes.php configs/var/www/index.html configs/var/www/mysqltest.cgi configs/var/www/phpinfo.php ### f4 ### ABOUT: This bootable CDROM is a slimmed-down custom version of KNOPPIX, a 'free' Debian-based Linux distribution with good hardware detection. Remastering is simplified using the included dk script in the KNOPPIX/dk directory. Uses include network-aware turnkey apps, multimedia giveaways, and interactive web kiosks requiring a controlled operating environment. LICENSING: KNOPPIX and dk are licensed under GPLv2 - see KNOPPIX/LICENSE.txt file. Remastered disks with 3rd party content MIGHT have other restrictions. WARNING: As a safety feature, when KNOPPIX boots, hard drives on this PC have to be mounted manually. However, remastered disks MIGHT override this... +---------------------------------+ | USE THIS CDROM AT YOUR OWN RISK | +---------------------------------+ MORE CHEATCODES: (F1 for Main Page) knoppix home=scan|/dev/sda1/knoppix.img Search for|specify knoppix homedir knoppix toram Copy CD to RAM and run from there knoppix tohd=/dev/hda1 Copy CD to HD and run from there knoppix fromhd[=/dev/hda1] Boot from previously copied CD knoppix bootfrom=/dev/hda1/dk/copy/dk.iso Boot from (remastered) CD ISO