summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2008-05-29 15:11:38 -0700
committerH. Peter Anvin <hpa@zytor.com>2008-05-29 15:11:38 -0700
commitb536209dfb7bd50c37061735fe10d2c19a97d26d (patch)
tree9d8ca6882fc5d9721fb0efea1abfd6dc09886814 /utils
parent3ec40a0119587f63411475c76c69f9db24c7598e (diff)
downloadsyslinux-b536209dfb7bd50c37061735fe10d2c19a97d26d.tar.gz
Move files out of root into core, dos, and utils
Move source files out of the root directory; the root is a mess and has become virtually unmaintainable. The Syslinux core now lives in core/; the Linux and generic utilities has moved into utils/, and copybs.com has moved into dos/; it had to go somewhere, and it seemed as good a place as any.
Diffstat (limited to 'utils')
-rw-r--r--utils/Makefile58
-rw-r--r--utils/bin2hex.pl44
-rw-r--r--utils/gethostip.c131
-rwxr-xr-xutils/keytab-lilo111
-rwxr-xr-xutils/lss16toppm111
-rwxr-xr-xutils/md5pass34
-rw-r--r--utils/mkdiskimage.in310
-rwxr-xr-xutils/ppmtolss16393
-rwxr-xr-xutils/sha1pass34
-rwxr-xr-xutils/syslinux2ansi53
10 files changed, 1279 insertions, 0 deletions
diff --git a/utils/Makefile b/utils/Makefile
new file mode 100644
index 00000000..0c5a3636
--- /dev/null
+++ b/utils/Makefile
@@ -0,0 +1,58 @@
+## -----------------------------------------------------------------------
+##
+## Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+## Boston MA 02111-1307, USA; either version 2 of the License, or
+## (at your option) any later version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+#
+# SYSLINUX utilities
+#
+# No builtin rules
+MAKEFLAGS += -r
+MAKE += -r
+
+TMPFILE = $(shell mktemp /tmp/gcc_ok.XXXXXX)
+
+CC = gcc
+
+gcc_ok = $(shell tmpf=$(TMPFILE); if $(CC) $(1) dummy.c -o $$tmpf 2>/dev/null; \
+ then echo '$(1)'; else echo '$(2)'; fi; rm -f $$tmpf)
+
+comma := ,
+LDHASH := $(call gcc_ok,-Wl$(comma)--hash-style=both,)
+
+CFLAGS = -W -Wall -Os -fomit-frame-pointer -D_FILE_OFFSET_BITS=64
+LDFLAGS = -O2 -s $(LDHASH)
+LD = ld
+PERL = perl
+
+TARGETS = mkdiskimage gethostip
+ASIS = keytab-lilo lss16toppm md5pass ppmtolss16 sha1pass syslinux2ansi
+
+all: mkdiskimage gethostip
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+mkdiskimage: mkdiskimage.in ../mbr/mbr.bin bin2hex.pl
+ $(PERL) bin2hex.pl < ../mbr/mbr.bin | cat mkdiskimage.in - > $@
+ chmod a+x $@
+
+gethostip: gethostip.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+tidy dist:
+ rm -f *.o
+
+clean: tidy
+ rm -f $(TARGETS)
+
+spotless: clean
+
+installer: all
diff --git a/utils/bin2hex.pl b/utils/bin2hex.pl
new file mode 100644
index 00000000..3c86ec27
--- /dev/null
+++ b/utils/bin2hex.pl
@@ -0,0 +1,44 @@
+#!/usr/bin/perl
+## -----------------------------------------------------------------------
+##
+## Copyright 2003-2008 H. Peter Anvin - All Rights Reserved
+##
+## Permission is hereby granted, free of charge, to any person
+## obtaining a copy of this software and associated documentation
+## files (the "Software"), to deal in the Software without
+## restriction, including without limitation the rights to use,
+## copy, modify, merge, publish, distribute, sublicense, and/or
+## sell copies of the Software, and to permit persons to whom
+## the Software is furnished to do so, subject to the following
+## conditions:
+##
+## The above copyright notice and this permission notice shall
+## be included in all copies or substantial portions of the Software.
+##
+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+## OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+## HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+## WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+## FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+## OTHER DEALINGS IN THE SOFTWARE.
+##
+## -----------------------------------------------------------------------
+
+eval { use bytes; }; eval { binmode STDIN; };
+
+$len = 0;
+while ( read(STDIN,$ch,1) ) {
+ $cc = ord($ch);
+ $len += printf ("%x", $cc);
+ if ( $len > 72 ) {
+ print "\n";
+ $len = 0;
+ } else {
+ print " ";
+ $len++;
+ }
+}
+print "\n" if ( $len );
+exit 0;
diff --git a/utils/gethostip.c b/utils/gethostip.c
new file mode 100644
index 00000000..2a1e6e65
--- /dev/null
+++ b/utils/gethostip.c
@@ -0,0 +1,131 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001-2008 H. Peter Anvin - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * gethostip.c
+ *
+ * Small program to use gethostbyname() to print out a hostname in
+ * hex and/or dotted-quad notation
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <sysexits.h>
+#define _GNU_SOURCE /* For getopt_long */
+#include <getopt.h>
+
+const struct option options[] =
+{
+ { "hexadecimal", 0, NULL, 'x' },
+ { "decimal", 0, NULL, 'd' },
+ { "dotted-quad", 0, NULL, 'd' },
+ { "full-output", 0, NULL, 'f' },
+ { "name", 0, NULL, 'n' },
+ { "help", 0, NULL, 'h' },
+ { NULL, 0, NULL, 0 }
+};
+
+const char *program;
+
+void usage(int exit_code)
+{
+ fprintf(stderr, "Usage: %s [-dxnf] hostname/ip...\n", program);
+ exit(exit_code);
+}
+
+int main(int argc, char *argv[])
+{
+ int opt;
+ int output = 0;
+ int i;
+ char *sep;
+ int err = 0;
+
+ struct hostent *host;
+
+ program = argv[0];
+
+ while ( (opt = getopt_long(argc, argv, "dxfnh", options, NULL)) != -1 ) {
+ switch ( opt ) {
+ case 'd':
+ output |= 2; /* Decimal output */
+ break;
+ case 'x':
+ output |= 4; /* Hexadecimal output */
+ break;
+ case 'n':
+ output |= 1; /* Canonical name output */
+ break;
+ case 'f':
+ output = 7; /* Full output */
+ break;
+ case 'h':
+ usage(0);
+ break;
+ default:
+ usage(EX_USAGE);
+ break;
+ }
+ }
+
+ if ( optind == argc )
+ usage(EX_USAGE);
+
+ if ( output == 0 )
+ output = 7; /* Default output */
+
+ for ( i = optind ; i < argc ; i++ ) {
+ sep = "";
+ host = gethostbyname(argv[i]);
+ if ( !host ) {
+ herror(argv[i]);
+ err = 1;
+ continue;
+ }
+
+ if ( host->h_addrtype != AF_INET || host->h_length != 4 ) {
+ fprintf(stderr, "%s: No IPv4 address associated with name\n", argv[i]);
+ err = 1;
+ continue;
+ }
+
+ if ( output & 1 ) {
+ printf("%s%s", sep, host->h_name);
+ sep = " ";
+ }
+
+ if ( output & 2 ) {
+ printf("%s%u.%u.%u.%u", sep,
+ ((unsigned char *)host->h_addr)[0],
+ ((unsigned char *)host->h_addr)[1],
+ ((unsigned char *)host->h_addr)[2],
+ ((unsigned char *)host->h_addr)[3]);
+ sep = " ";
+ }
+
+ if ( output & 4 ) {
+ printf("%s%02X%02X%02X%02X", sep,
+ ((unsigned char *)host->h_addr)[0],
+ ((unsigned char *)host->h_addr)[1],
+ ((unsigned char *)host->h_addr)[2],
+ ((unsigned char *)host->h_addr)[3]);
+ sep = " ";
+ }
+
+ putchar('\n');
+ }
+
+ return err;
+}
diff --git a/utils/keytab-lilo b/utils/keytab-lilo
new file mode 100755
index 00000000..867be7e2
--- /dev/null
+++ b/utils/keytab-lilo
@@ -0,0 +1,111 @@
+#!/usr/bin/perl
+# --------------------------------------------------------------------------
+# This program was taken from the LILO-20 distribution; only this header
+# was added.
+#
+# LILO program code, documentation and auxiliary programs are
+# Copyright 1992-1997 Werner Almesberger.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms of parts of or the
+# whole original or derived work are permitted provided that the
+# original work is properly attributed to the author. The name of the
+# author may not be used to endorse or promote products derived from
+# this software without specific prior written permission. This work
+# is provided "as is" and without any express or implied warranties.
+# --------------------------------------------------------------------------
+
+eval { use bytes; }; eval { binmode STDOUT; };
+
+$DEFAULT_PATH = "/usr/lib/kbd/keytables";
+$DEFAULT_MAP = "us";
+$DEFAULT_EXT = ".map";
+
+sub usage
+{
+ print STDERR
+ "usage: $0 [ -p old_code=new_code ] ...\n".
+ (" "x(8+length $0))."[path]default_layout[.map] ] ".
+ "[path]kbd_layout[.map]\n";
+ exit 1;
+}
+
+
+while ($ARGV[0] eq "-p") {
+ shift(@ARGV);
+ &usage unless $ARGV[0] =~ /=/;
+ $table[eval($`)] = eval($');
+ shift(@ARGV);
+}
+&usage unless defined $ARGV[0];
+load_map("def",defined $ARGV[1] ? $ARGV[0] : undef);
+load_map("kbd",defined $ARGV[1] ? $ARGV[1] : $ARGV[0]);
+&build_table("plain","shift","ctrl","altgr","shift_ctrl",
+ "altgr_ctrl","alt","shift_alt","ctrl_alt");
+for ($i = 0; $i < 256; $i++) {
+ printf("%c",$table[$i] ? $table[$i] : $i) || die "print: $!";
+}
+close STDOUT || die "close: $!";
+
+
+sub load_map
+{
+ local ($pfx,$map) = @_;
+ local ($empty,$current);
+
+ $map = $DEFAULT_MAP unless defined $map;
+ $map = $DEFAULT_PATH."/".$map unless $map =~ m|/|;
+ $map .= $DEFAULT_EXT unless $map =~ m|/[^/]+\.[^/]+$|;
+ if (!open(FILE,"loadkeys -m $map |")) {
+ print STDERR "loadkeys -m $map: $!\n";
+ exit 1;
+ }
+ undef $current;
+ $empty = 1;
+ while (<FILE>) {
+ chop;
+ if (/^u_short\s+(\S+)_map\[\S+\]\s+=\s+{\s*$/) {
+ die "active at beginning of map" if defined $current;
+ $current = $pfx.":".$1;
+ next;
+ }
+ undef $current if /^};\s*$/;
+ next unless defined $current;
+ s/\s//g;
+ $map{$current} .= $_;
+ $empty = 0;
+ }
+ close FILE;
+ return unless $empty;
+ print STDERR "Keymap is empty\n";
+ exit 1;
+}
+
+
+sub build_table
+{
+ local (@maps) = @_;
+ local (@tmp);
+
+ $set = 0;
+ for $map (@maps) {
+ $code = $set;
+ for (split(",",$map{"def:".$map})) {
+ die "bad map entry $_ (def, map $map)" unless /^0x\S\S(\S\S)$/;
+ $tmp[$code] = hex $1 unless $tmp[$code];
+ $code++;
+ }
+ $set += 256;
+ }
+ $set = 0;
+ for $map (@maps) {
+ $code = $set;
+ for (split(",",$map{"kbd:".$map})) {
+ die "bad map entry $_ (kbd, map $map)" unless /^0x\S\S(\S\S)$/;
+ $table[$tmp[$code]] = hex $1 unless $table[$tmp[$code]];
+ $code++;
+ }
+ $set += 256;
+ }
+ $table[0] = 0;
+}
diff --git a/utils/lss16toppm b/utils/lss16toppm
new file mode 100755
index 00000000..18b7f642
--- /dev/null
+++ b/utils/lss16toppm
@@ -0,0 +1,111 @@
+#!/usr/bin/perl
+## -----------------------------------------------------------------------
+##
+## Copyright 2001-2008 H. Peter Anvin - All Rights Reserved
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+## Boston MA 02111-1307, USA; either version 2 of the License, or
+## (at your option) any later version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+##
+## lss16toppm:
+## Convert an LSS-16 image to PPM
+##
+## Usage:
+##
+## lss16toppm [-map] < file.lss > file.ppm
+##
+## The -map causes the color map to be output on stderr.
+##
+
+eval { use bytes; };
+eval { binmode STDIN; };
+eval { binmode STDOUT; };
+
+$map = 0;
+foreach $arg ( @ARGV ) {
+ if ( $arg eq '-map' ) {
+ $map = 1;
+ } else {
+ print STDERR "$0: Unknown option: $arg\n";
+ exit 127;
+ }
+}
+
+if ( read(STDIN, $header, 56) != 56 ) {
+ print STDERR "$0: Short file\n";
+ exit 1;
+}
+
+($magic, $xsize, $ysize, @colorset) = unpack("Vvvc48", $header);
+
+if ( $magic != 0x1413f33d ) {
+ print STDERR "$0: Invalid file format\n";
+ exit 1;
+}
+
+%color = ();
+for ( $i = 0 ; $i < 16 ; $i++ ) {
+ $r = int((shift @colorset) * 255 / 63 + 0.5);
+ $g = int((shift @colorset) * 255 / 63 + 0.5);
+ $b = int((shift @colorset) * 255 / 63 + 0.5);
+
+ $color{$i} = pack("ccc", $r, $g, $b);
+
+ if ( $map ) {
+ printf STDERR "#%02x%02x%02x=%d\n", $r, $g, $b, $i;
+ }
+}
+
+sub get_nybble() {
+ my($ch,$n);
+ if ( defined($nybble_buf) ) {
+ $n = $nybble_buf;
+ undef $nybble_buf;
+ } else {
+ if ( read(STDIN, $ch, 1) != 1 ) {
+ print STDERR "$0: Short read on input (file corrupt)\n";
+ exit 1;
+ }
+ $ch = ord($ch);
+ $nybble_buf = $ch >> 4;
+ $n = $ch & 0xF;
+ }
+ return $n;
+}
+
+print "P6\n";
+print "$xsize $ysize\n";
+print "255\n";
+
+for ( $y = 0 ; $y < $ysize ; $y++ ) {
+ $x = 0;
+ $last = 0;
+ undef $nybble_buf; # Nybble buffer starts clear on each line
+ while ( $x < $xsize ) {
+ $n = get_nybble();
+
+ if ( $n != $last ) {
+ print $color{$n};
+ $last = $n;
+ $x++;
+ } else {
+ $c = get_nybble();
+ if ( $c == 0 ) {
+ # Double-nybble run
+ $c = get_nybble();
+ $c += get_nybble() << 4;
+ $c += 16;
+ }
+ # Truncate overlong runs
+ $c = $xsize-$x if ( $c > $xsize-$x );
+ # Output run
+ print $color{$n} x $c;
+ $x += $c;
+ }
+ }
+}
diff --git a/utils/md5pass b/utils/md5pass
new file mode 100755
index 00000000..3404f1d6
--- /dev/null
+++ b/utils/md5pass
@@ -0,0 +1,34 @@
+#!/usr/bin/perl
+
+use bytes;
+use Crypt::PasswdMD5;
+use MIME::Base64;
+
+sub random_bytes($) {
+ my($n) = @_;
+ my($v, $i);
+
+ if ( open(RANDOM, '<', '/dev/random') ||
+ open(RANDOM, '<', '/dev/urandom') ) {
+ read(RANDOM, $v, $n);
+ } else {
+ # No real RNG available...
+ srand($$ ^ time);
+ $v = '';
+ for ( $i = 0 ; $i < $n ; $i++ ) {
+ $v .= ord(int(rand() * 256));
+ }
+ }
+
+ return $v;
+}
+
+
+($pass, $salt) = @ARGV;
+
+unless (defined($salt)) {
+ $salt = MIME::Base64::encode(random_bytes(6), '');
+ $salt =~ tr/\+/./; # . not +
+}
+
+print unix_md5_crypt($pass, $salt), "\n";
diff --git a/utils/mkdiskimage.in b/utils/mkdiskimage.in
new file mode 100644
index 00000000..f66ad7cf
--- /dev/null
+++ b/utils/mkdiskimage.in
@@ -0,0 +1,310 @@
+#!/usr/bin/perl
+## -----------------------------------------------------------------------
+##
+## Copyright 2002-2008 H. Peter Anvin - All Rights Reserved
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+## Boston MA 02111-1307, USA; either version 2 of the License, or
+## (at your option) any later version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+#
+# Creates a blank MS-DOS formatted hard disk image
+#
+
+use bytes;
+use integer;
+use Fcntl;
+use Errno;
+use Cwd;
+use IO::Handle; # For flush()
+
+sub absolute_path($) {
+ my($f) = @_;
+ my($c);
+
+ return $f if ( $f =~ /^\// );
+ $c = cwd();
+ $c = '' if ( $c eq '/' );
+ return $c.'/'.$f;
+}
+
+sub is_linux() {
+ return !!eval '{ '.
+ 'use POSIX; '.
+ '($sysname, $nodename, $release, $version, $machine) = POSIX::uname(); '.
+ "return \$sysname eq \'Linux\'; }";
+}
+
+sub get_random() {
+ # Get a 32-bit random number
+ my $rfd, $rnd;
+ my $rid;
+
+ if (sysopen($rfd, '/dev/urandom', O_RDONLY) &&
+ sysread($rfd, $rnd, 4) == 4) {
+ $rid = unpack("V", $rnd);
+ }
+
+ close($rfd) if (defined($rfd));
+ return $rid if (defined($rid));
+
+ # This sucks but is better than nothing...
+ return ($$+time()) & 0xffffffff;
+}
+
+$is_linux = is_linux();
+if ( $is_linux ) {
+ # IOCTL numbers
+ $BLKRRPART = 0x125f;
+ $BLKGETSIZE = 0x1260;
+}
+
+%opt = ();
+@args = ();
+
+while (defined($a = shift(@ARGV))) {
+ if ( $a =~ /^\-/ ) {
+ foreach $o ( split(//, substr($a,1)) ) {
+ $opt{$o} = 1;
+ if ($o eq 'i') {
+ $id = shift(@ARGV);
+ }
+ }
+ } else {
+ push(@args, $a);
+ }
+}
+
+($file,$c,$h,$s) = @args;
+$c += 0; $h += 0; $s += 0;
+
+$pentry = 1;
+$pentry = 2 if ( $opt{'2'} );
+$pentry = 3 if ( $opt{'3'} );
+$pentry = 4 if ( $opt{'4'} );
+
+if ( $opt{'z'} ) {
+ $h = $h || 64;
+ $s = $s || 32;
+}
+
+if ( $opt{'M'} && $h && $s ) {
+ # Specify size in megabytes, not in cylinders
+ $c = ($c*1024*2)/($h*$s);
+}
+
+$is_open = 0;
+
+if ( $c == 0 && $file ne '' ) {
+ $len = 0;
+ if ( sysopen(OUTPUT, $file, O_RDWR, 0666) ) {
+ $is_open = 1;
+
+ if ( (@filestat = stat(OUTPUT)) && S_ISREG($filestat[2]) ) {
+ $len = $filestat[7] >> 9;
+ } elsif ( $is_linux && S_ISBLK($filestat[2]) ) {
+ $blksize = pack("L!", 0);
+ if ( ioctl(OUTPUT, $BLKGETSIZE, $blksize) == 0 ) {
+ $len = unpack("L!", $blksize); # In 512-byte sectors!
+ }
+ }
+ }
+
+ if ( !$len ) {
+ print STDERR "$0: $file: don't know how to determine the size of this device\n";
+ exit 1;
+ }
+
+ $c = $len/($h*$s);
+}
+
+if ( $file eq '' || $c < 1 || $h < 1 || $h > 256 || $s < 1 || $s > 63 ) {
+ print STDERR "Usage: $0 [-doFMz4][-i id] file c h s (max: 1024 256 63)\n";
+ print STDERR " -d add DOSEMU header\n";
+ print STDERR " -o print filesystem offset to stdout\n";
+ print STDERR " -F format partition as FAT32\n";
+ print STDERR " -M \"c\" argument is megabytes, calculate cylinders\n";
+ print STDERR " -z use zipdisk geometry (h=64 s=32)\n";
+ print STDERR " -4 use partition entry 4 (standard for zipdisks)\n";
+ print STDERR " -i specify the MBR ID\n";
+ exit 1;
+}
+
+if ($c > 1024) {
+ print STDERR "Warning: more than 1024 cylinders ($c).\n";
+ print STDERR "Not all BIOSes will be able to boot this device.\n";
+ $cc = 1024;
+} else {
+ $cc = $c;
+}
+
+$cylsize = $h*$s*512;
+
+if ( !$is_open ) {
+ sysopen(OUTPUT, $file, O_CREAT|O_RDWR|O_TRUNC, 0666)
+ or die "$0: Cannot open: $file\n";
+}
+binmode OUTPUT;
+
+# Print out DOSEMU header, if requested
+if ( $opt{'d'} ) {
+ $emuhdr = "DOSEMU\0" . pack("VVVV", $h, $s, $c, 128);
+ $emuhdr .= "\0" x (128 - length($emuhdr));
+ print OUTPUT $emuhdr;
+}
+
+# Print the MBR and partition table
+$mbr = '';
+while ( $line = <DATA> ) {
+ chomp $line;
+ foreach $byte ( split(/\s+/, $line) ) {
+ $mbr .= chr(hex($byte));
+ }
+}
+if ( length($mbr) > 440 ) {
+ die "$0: Bad MBR code\n";
+}
+
+$mbr .= "\0" x (440 - length($mbr));
+if (defined($id)) {
+ $id = to_int($id);
+} else {
+ $id = get_random();
+}
+$mbr .= pack("V", $id); # Offset 440: MBR ID
+$mbr .= "\0\0"; # Offset 446: actual partition table
+
+print OUTPUT $mbr;
+
+# Print partition table
+$psize = $c*$h*$s-$s;
+$bhead = ($h > 1) ? 1 : 0;
+$bsect = 1;
+$bcyl = ($h > 1) ? 0 : 1;
+$ehead = $h-1;
+$esect = $s + ((($cc-1) & 0x300) >> 2);
+$ecyl = ($cc-1) & 0xff;
+if ( $c > 1024 ) {
+ $fstype = 0x0e;
+} elsif ( $psize > 65536 ) {
+ $fstype = 0x06;
+} else {
+ $fstype = 0x04;
+}
+for ( $i = 1 ; $i <= 4 ; $i++ ) {
+ if ( $i == $pentry ) {
+ print OUTPUT pack("CCCCCCCCVV", 0x80, $bhead, $bsect, $bcyl, $fstype,
+ $ehead, $esect, $ecyl, $s, $psize);
+ } else {
+ print OUTPUT "\0" x 16;
+ }
+}
+print OUTPUT "\x55\xaa";
+
+# Output blank file
+$totalsize = $c*$h*$s;
+$tracks = $c*$h;
+
+$track = "\0" x (512*$s);
+
+# Print fractional track
+print OUTPUT "\0" x (512 * ($s-1));
+
+for ( $i = 1 ; $i < $tracks ; $i++ ) {
+ print OUTPUT $track;
+}
+
+# Print mtools temp file
+$n = 0;
+while ( !defined($tmpdir) ) {
+ $tmpdir = "/tmp/mkdiskimage.$$.".($n++);
+ if ( !mkdir($tmpdir, 0700) ) {
+ die "$0: Failed to make temp directory: $tmpdir\n"
+ if ( $! != EEXIST );
+ undef $tmpdir;
+ }
+}
+
+$cfgfile = $tmpdir.'/mtools.conf';
+$imglink = $tmpdir.'/disk.img';
+die "$0: Failed to create symlink $imglink\n"
+ if ( !symlink(absolute_path($file), $imglink) );
+
+$header_size = ($opt{'d'} ? 128 : 0);
+
+# Start of filesystem
+$offset = $s*512 + $header_size;
+
+# Start of partition table entry
+$pstart = $header_size + 446 + 16*($pentry-1);
+
+open(MCONFIG, "> ${cfgfile}") or die "$0: Cannot make mtools config\n";
+print MCONFIG "drive z:\n";
+print MCONFIG "file=\"${imglink}\"\n";
+print MCONFIG "cylinders=${c}\n";
+print MCONFIG "heads=${h}\n";
+print MCONFIG "sectors=${s}\n";
+print MCONFIG "offset=${offset}\n";
+print MCONFIG "mformat_only\n";
+close(MCONFIG);
+
+# Output the filesystem offset to stdout if appropriate
+if ( $opt{'o'} ) {
+ print $offset, "\n";
+}
+
+$ENV{'MTOOLSRC'} = $cfgfile;
+if ( $opt{'F'} ) {
+ system('mformat', '-F', 'z:');
+} else {
+ system('mformat', 'z:');
+}
+
+# Clean up in /tmp
+unlink($cfgfile);
+unlink($imglink);
+rmdir($tmpdir);
+
+# MTOOLS doesn't write the bsHiddenSecs field correctly
+seek(OUTPUT, $offset + 0x1c, 0);
+print OUTPUT pack("V", ($offset-$header_size)>>9);
+
+# Set the partition type
+if ( $opt{'F'} ) {
+ if ( $c > 1024 ) {
+ $fstype = 0x0c; # FAT32 LBA
+ } else {
+ $fstype = 0x0b;
+ }
+} else {
+ if ( $c > 1024 ) {
+ $fstype = 0x0e; # FAT16 LBA
+ } elsif ( $psize > 65536 ) {
+ $fstype = 0x06; # FAT16 > 32MB
+ } else {
+ $fstype = 0x04; # FAT16 <= 32MB
+ }
+ seek(OUTPUT, $offset + 0x36, 0);
+ read(OUTPUT, $fsname, 8);
+
+ # FAT12: adjust partition type
+ if ( $fsname eq 'FAT12 ' ) {
+ $fstype = 0x01; # FAT12
+ }
+}
+seek(OUTPUT, $pstart+4, 0);
+print OUTPUT pack("C", $fstype);
+
+flush OUTPUT;
+
+# Just in case this is a block device, try to flush the partition table
+if ( $is_linux ) {
+ ioctl(OUTPUT, $BLKRRPART, 0);
+};
+
+exit 0;
+__END__
diff --git a/utils/ppmtolss16 b/utils/ppmtolss16
new file mode 100755
index 00000000..5af90831
--- /dev/null
+++ b/utils/ppmtolss16
@@ -0,0 +1,393 @@
+#!/usr/bin/perl
+## -----------------------------------------------------------------------
+##
+## Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+## Boston MA 02111-1307, USA; either version 2 of the License, or
+## (at your option) any later version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+##
+## ppmtolss16
+##
+## Convert a PNM file with max 16 colors to a simple RLE-based format:
+##
+## uint32 0x1413f33d ; magic (littleendian)
+## uint16 xsize ; littleendian
+## uint16 ysize ; littleendian
+## 16 x uint8 r,g,b ; color map, in 6-bit format (each byte is 0..63)
+##
+## Then, a sequence of nybbles:
+##
+## N ... if N is != previous pixel, one pixel of color N
+## ... otherwise run sequence follows ...
+## M ... if M > 0 then run length is M
+## ... otherwise run sequence is encoded in two nybbles,
+## littleendian, +16
+##
+## The nybble sequences are on a per-row basis; runs may not extend
+## across rows and odd-nybble rows are zero-padded.
+##
+## At the start of row, the "previous pixel" is assumed to be zero.
+##
+## Usage:
+##
+## ppmtolss16 [#rrggbb=i ...] < input.ppm > output.rle
+##
+## Command line options of the form #rrggbb=i indicate that
+## the color #rrggbb (hex) should be assigned index i (decimal)
+##
+
+eval { use bytes; };
+eval { binmode STDIN; };
+eval { binmode STDOUT; };
+
+$magic = 0x1413f33d;
+
+# Get a token from the PPM header. Ignore comments and leading
+# and trailing whitespace, as is required by the spec.
+# This routine eats exactly one character of trailing whitespace,
+# unless it is a comment (in which case it eats the comment up
+# to and including the end of line.)
+sub get_token() {
+ my($token, $ch);
+ my($ch);
+
+ do {
+ $ch = getc(STDIN);
+ return undef if ( !defined($ch) ); # EOF
+ if ( $ch eq '#' ) {
+ do {
+ $ch = getc(STDIN);
+ return undef if ( !defined($ch) );
+ } while ( $ch ne "\n" );
+ }
+ } while ( $ch =~ /^[ \t\n\v\f\r]$/ );
+
+ $token = $ch;
+ while ( 1 ) {
+ $ch = getc(STDIN);
+ last if ( $ch =~ /^[ \t\n\v\f\r\#]$/ );
+ $token .= $ch;
+ }
+ if ( $ch eq '#' ) {
+ do {
+ $ch = getc(STDIN);
+ } while ( defined($ch) && $ch ne "\n" );
+ }
+ return $token;
+}
+
+# Get a token, and make sure it is numeric (and exists)
+sub get_numeric_token() {
+ my($token) = get_token();
+
+ if ( $token !~ /^[0-9]+$/ ) {
+ print STDERR "Format error on input\n";
+ exit 1;
+ }
+
+ return $token + 0;
+}
+
+# Must be called before each pixel row is read
+sub start_new_row() {
+ $getrgb_leftover_bit_cnt = 0;
+ $getrgb_leftover_bit_val = 0;
+}
+
+# Get a single RGB token depending on the PNM type
+sub getrgb($) {
+ my($form) = @_;
+ my($rgb,$r,$g,$b);
+
+ if ( $form == 6 ) {
+ # Raw PPM, most common
+ return undef unless ( read(STDIN,$rgb,3) == 3 );
+ return unpack("CCC", $rgb);
+ } elsif ( $form == 3 ) {
+ # Plain PPM
+ $r = get_numeric_token();
+ $g = get_numeric_token();
+ $b = get_numeric_token();
+ return ($r,$g,$b);
+ } elsif ( $form == 5 ) {
+ # Raw PGM
+ return undef unless ( read(STDIN,$rgb,1) == 1 );
+ $r = unpack("C", $rgb);
+ return ($r,$r,$r);
+ } elsif ( $form == 2 ) {
+ # Plain PGM
+ $r = get_numeric_token();
+ return ($r,$r,$r);
+ } elsif ( $form == 4 ) {
+ # Raw PBM
+ if ( !$getrgb_leftover_bit_cnt ) {
+ return undef unless ( read(STDIN,$rgb,1) == 1 );
+ $getrgb_leftover_bit_val = unpack("C", $rgb);
+ $getrgb_leftover_bit_cnt = 8;
+ }
+ $r = ( $getrgb_leftover_bit_val & 0x80 ) ? 0x00 : 0xff;
+ $getrgb_leftover_bit_val <<= 1;
+ $getrgb_leftover_bit_cnt--;
+
+ return ($r,$r,$r);
+ } elsif ( $form == 1 ) {
+ # Plain PBM
+ my($ch);
+
+ do {
+ $ch = getc(STDIN);
+ return undef if ( !defined($ch) );
+ return (255,255,255) if ( $ch eq '0' ); # White
+ return (0,0,0) if ( $ch eq '1'); # Black
+ if ( $ch eq '#' ) {
+ do {
+ $ch = getc(STDIN);
+ return undef if ( !defined($ch) );
+ } while ( $ch ne "\n" );
+ }
+ } while ( $ch =~ /^[ \t\n\v\f\r]$/ );
+ return undef;
+ } else {
+ die "Internal error: unknown format: $form\n";
+ }
+}
+
+sub rgbconvert($$$$) {
+ my($r,$g,$b,$maxmult) = @_;
+ my($rgb);
+
+ $r = int($r*$maxmult);
+ $g = int($g*$maxmult);
+ $b = int($b*$maxmult);
+ $rgb = pack("CCC", $r, $g, $b);
+ return $rgb;
+}
+
+foreach $arg ( @ARGV ) {
+ if ( $arg =~ /^\#([0-9a-f])([0-9a-f])([0-9a-f])=([0-9]+)$/i ) {
+ $r = hex($1) << 4;
+ $g = hex($2) << 4;
+ $b = hex($3) << 4;
+ $i = $4 + 0;
+ } elsif ( $arg =~ /^\#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})=([0-9]+)$/i ) {
+ $r = hex($1);
+ $g = hex($2);
+ $b = hex($3);
+ $i = $4 + 0;
+ } elsif ( $arg =~ /^\#([0-9a-f]{3})([0-9a-f]{3})([0-9a-f]{3})=([0-9]+)$/i ) {
+ $r = hex($1) >> 4;
+ $g = hex($2) >> 4;
+ $b = hex($3) >> 4;
+ $i = $4 + 0;
+ } elsif ( $arg =~ /^\#([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})=([0-9]+)$/i ) {
+ $r = hex($1) >> 8;
+ $g = hex($2) >> 8;
+ $b = hex($3) >> 8;
+ $i = $4 + 0;
+ } else {
+ print STDERR "$0: Unknown argument: $arg\n";
+ next;
+ }
+
+ if ( $i > 15 ) {
+ print STDERR "$0: Color index out of range: $arg\n";
+ next;
+ }
+
+ $rgb = rgbconvert($r, $g, $b, 64/256);
+
+ if ( defined($index_forced{$i}) ) {
+ print STDERR "$0: More than one color index $i\n";
+ exit(1);
+ }
+ $index_forced{$i} = $rgb;
+ $force_index{$rgb} = $i;
+}
+
+$form = get_token();
+die "$0: stdin is not a PNM file" if ( $form !~ /^P([1-6])$/ );
+$form = $1+0;
+
+$xsize = get_numeric_token();
+$ysize = get_numeric_token();
+if ( $form == 1 || $form == 4 ) {
+ $maxcol = 255; # Internal convention
+} else {
+ $maxcol = get_numeric_token();
+}
+$maxmult = 64/($maxcol+1); # Equal buckets conversion
+
+@data = ();
+
+for ( $y = 0 ; $y < $ysize ; $y++ ) {
+ start_new_row();
+ for ( $x = 0 ; $x < $xsize ; $x++ ) {
+ die "$0: Premature EOF at ($x,$y) of ($xsize,$ysize)\n"
+ if ( !defined(@pnmrgb = getrgb($form)) );
+ # Convert to 6-bit representation
+ $rgb = rgbconvert($pnmrgb[0], $pnmrgb[1], $pnmrgb[2], $maxmult);
+ $color_count{$rgb}++;
+ push(@data, $rgb);
+ }
+}
+
+# Sort list of colors according to freqency
+@colors = sort { $color_count{$b} <=> $color_count{$a} } keys(%color_count);
+
+# Now we have our pick of colors. Sort according to intensity;
+# this is more or less an ugly hack to cover for the fact that
+# using PPM as input doesn't let the user set the color map,
+# which the user really needs to be able to do.
+
+sub by_intensity() {
+ my($ra,$ga,$ba) = unpack("CCC", $a);
+ my($rb,$gb,$bb) = unpack("CCC", $b);
+
+ my($ia) = $ra*0.299 + $ga*0.587 + $ba*0.114;
+ my($ib) = $rb*0.299 + $gb*0.587 + $bb*0.114;
+
+ return ( $ia <=> $ib ) if ( $ia != $ib );
+
+ # If same, sort based on RGB components,
+ # with highest priority given to G, then R, then B.
+
+ return ( $ga <=> $gb ) if ( $ga != $gb );
+ return ( $ra <=> $rb ) if ( $ra != $rb );
+ return ( $ba <=> $bb );
+}
+
+@icolors = sort by_intensity @colors;
+
+# Insert forced colors into "final" array
+@colors = (undef) x 16;
+foreach $rgb ( keys(%force_index) ) {
+ $i = $force_index{$rgb};
+ $colors[$i] = $rgb;
+ $color_index{$rgb} = $i;
+}
+
+undef %force_index;
+
+# Insert remaining colors in the remaining slots,
+# in luminosity-sorted order
+$nix = 0;
+while ( scalar(@icolors) ) {
+ # Advance to the next free slot
+ $nix++ while ( defined($colors[$nix]) && $nix < 16 );
+ last if ( $nix >= 16 );
+ $rgb = shift @icolors;
+ if ( !defined($color_index{$rgb}) ) {
+ $colors[$nix] = $rgb;
+ $color_index{$rgb} = $nix;
+ }
+}
+
+while ( scalar(@icolors) ) {
+ $rgb = shift @icolors;
+ $lost++ if ( !defined($color_index{$rgb}) );
+}
+
+if ( $lost ) {
+ printf STDERR
+ "$0: Warning: color palette truncated (%d colors ignored)\n", $lost;
+}
+
+undef @icolors;
+
+# Output header
+print pack("Vvv", $magic, $xsize, $ysize);
+
+# Output color map
+for ( $i = 0 ; $i < 16 ; $i++ ) {
+ if ( defined($colors[$i]) ) {
+ print $colors[$i];
+ } else {
+ # Padding for unused color entries
+ print pack("CCC", 63*$i/15, 63*$i/15, 63*$i/15);
+ }
+}
+
+sub output_nybble($) {
+ my($ny) = @_;
+
+ if ( !defined($ny) ) {
+ if ( defined($nybble_tmp) ) {
+ $ny = 0; # Force the last byte out
+ } else {
+ return;
+ }
+ }
+
+ $ny = $ny & 0x0F;
+
+ if ( defined($nybble_tmp) ) {
+ $ny = ($ny << 4) | $nybble_tmp;
+ print chr($ny);
+ $bytes++;
+ undef $nybble_tmp;
+ } else {
+ $nybble_tmp = $ny;
+ }
+}
+
+sub output_run($$$) {
+ my($last,$this,$run) = @_;
+
+ if ( $this != $last ) {
+ output_nybble($this);
+ $run--;
+ }
+ while ( $run ) {
+ if ( $run >= 16 ) {
+ output_nybble($this);
+ output_nybble(0);
+ if ( $run > 271 ) {
+ $erun = 255;
+ $run -= 271;
+ } else {
+ $erun = $run-16;
+ $run = 0;
+ }
+ output_nybble($erun);
+ output_nybble($erun >> 4);
+ } else {
+ output_nybble($this);
+ output_nybble($run);
+ $run = 0;
+ }
+ }
+}
+
+$bytes = 0;
+undef $nybble_tmp;
+
+for ( $y = 0 ; $y < $ysize ; $y++ ) {
+ $last = $prev = 0;
+ $run = 0;
+ for ( $x = 0 ; $x < $xsize ; $x++ ) {
+ $rgb = shift(@data);
+ $i = $color_index{$rgb} + 0;
+ if ( $i == $last ) {
+ $run++;
+ } else {
+ output_run($prev, $last, $run);
+ $prev = $last;
+ $last = $i;
+ $run = 1;
+ }
+ }
+ # Output final datum for row; we're always at least one pixel behind
+ output_run($prev, $last, $run);
+ output_nybble(undef); # Flush row
+}
+
+$pixels = $xsize * $ysize;
+$size = ($pixels+1)/2;
+printf STDERR "%d pixels, %d bytes, (%2.2f%% compression)\n",
+ $pixels, $bytes, 100*($size-$bytes)/$size;
diff --git a/utils/sha1pass b/utils/sha1pass
new file mode 100755
index 00000000..3be2dbc1
--- /dev/null
+++ b/utils/sha1pass
@@ -0,0 +1,34 @@
+#!/usr/bin/perl
+
+use bytes;
+use Digest::SHA1;
+use MIME::Base64;
+
+sub random_bytes($) {
+ my($n) = @_;
+ my($v, $i);
+
+ if ( open(RANDOM, '<', '/dev/random') ||
+ open(RANDOM, '<', '/dev/urandom') ) {
+ read(RANDOM, $v, $n);
+ } else {
+ # No real RNG available...
+ srand($$ ^ time);
+ $v = '';
+ for ( $i = 0 ; $i < $n ; $i++ ) {
+ $v .= ord(int(rand() * 256));
+ }
+ }
+
+ return $v;
+}
+
+
+($pass, $salt) = @ARGV;
+
+unless (defined($salt)) {
+ $salt = MIME::Base64::encode(random_bytes(6), '');
+}
+$pass = Digest::SHA1::sha1_base64($salt, $pass);
+
+print '$4$', $salt, '$', $pass, "\$\n";
diff --git a/utils/syslinux2ansi b/utils/syslinux2ansi
new file mode 100755
index 00000000..085f6c97
--- /dev/null
+++ b/utils/syslinux2ansi
@@ -0,0 +1,53 @@
+#!/usr/bin/perl
+#
+# Perl script to convert a Syslinux-format screen to PC-ANSI
+# to display in a color xterm or on the Linux console
+#
+
+@ansicol = (0,4,2,6,1,5,3,7);
+
+$getting_file = 0;
+$enable = 1;
+
+while ( read(STDIN, $ch, 1) > 0 ) {
+ if ( $ch eq "\x1A" ) { # <SUB> <Ctrl-Z> EOF
+ last;
+ } elsif ( $ch eq "\x0C" ) { # <FF> <Ctrl-L> Clear screen
+ print "\x1b[2J" if ( $enable && !$getting_file );
+ } elsif ( $ch eq "\x0F" ) { # <SI> <Ctrl-O> Attribute change
+ if ( !$getting_file ) {
+ if ( read(STDIN, $attr, 2) == 2 ) {
+ $attr = hex $attr;
+ if ( $enable ) {
+ print "\x1b[0;";
+ if ( $attr & 0x80 ) {
+ print "5;";
+ $attr &= ~0x80;
+ }
+ if ( $attr & 0x08 ) {
+ print "1;";
+ $attr &= ~0x08;
+ }
+ printf "%d;%dm",
+ $ansicol[$attr >> 4] + 40, $ansicol[$attr & 7] + 30;
+ }
+ }
+ }
+ } elsif ( $ch eq "\x18" ) { # <CAN> <Ctrl-X> Display image
+ # We can't display an image; pretend to be a text screen
+ # Ignore all input until end of line
+ $getting_file = 1;
+ } elsif ( (ord($ch) & ~07) == 0x10 ) { # Mode controls
+ $enable = (ord($ch) & 0x01); # Emulate the text screen
+ } elsif ( $ch eq "\x0D" ) { # <CR> <Ctrl-M> Carriage return
+ # Ignore
+ } elsif ( $ch eq "\x0A" ) { # <LF> <Ctrl-J> Line feed
+ if ( $getting_file ) {
+ $getting_file = 0;
+ } else {
+ print $ch if ( $enable );
+ }
+ } else {
+ print $ch if ( $enable && !$getting_file );
+ }
+}