diff options
Diffstat (limited to 'contrib')
153 files changed, 20692 insertions, 0 deletions
diff --git a/contrib/3c90xutil/Makefile b/contrib/3c90xutil/Makefile new file mode 100644 index 0000000..1dd1723 --- /dev/null +++ b/contrib/3c90xutil/Makefile @@ -0,0 +1,9 @@ +FILES = cromutil bromutil + +INCLUDEDIR = /usr/include +CFLAGS = -O2 -fomit-frame-pointer -Wall -I$(INCLUDEDIR) + +all: $(FILES) + +clean: + rm -f $(FILES) *~ core diff --git a/contrib/3c90xutil/README b/contrib/3c90xutil/README new file mode 100644 index 0000000..235530f --- /dev/null +++ b/contrib/3c90xutil/README @@ -0,0 +1,31 @@ +This utility was apparently writen by John Finlay and came to me +via Richard Schroeder who got it from Greg Beeley. John, if you want +to be credited with your full address or whatever in the Etherboot +documentation, please contact me (Etherboot maintainer). + +1/18/2000 Marty Connor (mdc@thinguin.org) added code for the 3C905C +with AT49BV512 Flash memory, and created cromutil and bromutil to +differentiate the versions. cromutil is for 3C905C and bromutil is +for 3C905B. + +Be careful. You can easily erase your Flash memory using these +utilities. Make *sure* to back them up first using the "read" +command. You must "erase" before using "prog" to program the chip with +Etherboot code. This code comes with NO WARRANTY, and you take sole +responsibility and liability for whatever it does. Read the +"romutil.txt" file for more information on commands. + +That being said, if you are programming a 3C905C-TXM (for example) +you would do something like this: + + $ cd etherboot-x.x.x/contrib + $ tar -zxvf n3c905xutil.tar.gz + $ cd n3c905xutil + $ make + # replace 0x6600 with whatever the IO Addr for your card is!!!! + $ ./cromutil 0x6600 read > 905cbackup.bin + $ ./cromutil 0x6600 erase + $ ./cromutil 0x6600 prog < 3c90x.lzrom + +You should now have an Etherboot-enabled 3c905C-TXM. + diff --git a/contrib/3c90xutil/bromutil.c b/contrib/3c90xutil/bromutil.c new file mode 100644 index 0000000..a736e5a --- /dev/null +++ b/contrib/3c90xutil/bromutil.c @@ -0,0 +1,169 @@ +/* + * readutil.c - perform various control ops on the 3c509b bios rom + * + */ + +#ifndef __i386__ +# error "This program can't compile or run on non-intel computers" +#else + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#ifdef __FreeBSD__ + +#include <fcntl.h> +#include <machine/cpufunc.h> + +#define OUTB(data, port) outb(port, data) +#define OUTW(data, port) outw(port, data) +#define OUTL(data, port) outl(port, data) + +#else + +#include <sys/io.h> + +#define OUTB(data, port) outb(data, port) +#define OUTW(data, port) outw(data, port) +#define OUTL(data, port) outl(data, port) + +#endif + +int main(int argc, char **argv) +{ + unsigned int i, j, n; + unsigned int ioaddr; + unsigned long recvrstat; + unsigned char buf[128]; + unsigned char b; + + if (argc != 3) { + printf("Usage: romid ioaddr [erase|protect|unprotect|id|read >file|prog <file]\n"); + exit(-1); + } + +#ifdef __FreeBSD__ + /* get permissions for in/out{blw} */ + open("/dev/io",O_RDONLY,0); +#else + setuid(0); /* if we're setuid, do it really */ + if (iopl(3)) { + perror("iopl()"); + exit(1); + } +#endif + + sscanf(argv[1],"%x",&ioaddr); + /* Set the register window to 3 for the 3c905b */ + OUTW(0x803, ioaddr+0xe); + recvrstat = inl(ioaddr); /* save the receiver status */ + /* set the receiver type to MII so the full bios rom address space + can be accessed */ + OUTL((recvrstat & 0xf00fffff)|0x00600000, ioaddr); + + /* Set the register window to 0 for the 3c905b */ + OUTW(0x800, ioaddr+0xe); + + if (strcmp(argv[2], "erase") == 0) { + /* do the funky chicken to erase the rom contents */ + OUTL(0x5555, ioaddr+0x4); + OUTB(0xaa, ioaddr+0x8); + OUTL(0x2aaa, ioaddr+0x4); + OUTB(0x55, ioaddr+0x8); + OUTL(0x5555, ioaddr+0x4); + OUTB(0x80, ioaddr+0x8); + OUTL(0x5555, ioaddr+0x4); + OUTB(0xaa, ioaddr+0x8); + OUTL(0x2aaa, ioaddr+0x4); + OUTB(0x55, ioaddr+0x8); + OUTL(0x5555, ioaddr+0x4); + OUTB(0x10, ioaddr+0x8); + printf("Bios ROM at %04x has been erased\n", ioaddr); + } else if (strcmp(argv[2], "protect") == 0) { + OUTL(0x5555, ioaddr+0x4); + OUTB(0xaa, ioaddr+0x8); + OUTL(0x2aaa, ioaddr+0x4); + OUTB(0x55, ioaddr+0x8); + OUTL(0x5555, ioaddr+0x4); + OUTB(0xa0, ioaddr+0x8); + printf("Software Data Protection for Bios ROM at %04x has been enabled\n", + ioaddr); + } else if (strcmp(argv[2], "unprotect") == 0) { + OUTL(0x5555, ioaddr+0x4); + OUTB(0xaa, ioaddr+0x8); + OUTL(0x2aaa, ioaddr+0x4); + OUTB(0x55, ioaddr+0x8); + OUTL(0x5555, ioaddr+0x4); + OUTB(0x80, ioaddr+0x8); + OUTL(0x5555, ioaddr+0x4); + OUTB(0xaa, ioaddr+0x8); + OUTL(0x2aaa, ioaddr+0x4); + OUTB(0x55, ioaddr+0x8); + OUTL(0x5555, ioaddr+0x4); + OUTB(0x20, ioaddr+0x8); + printf("Software Data Protection for Bios ROM at %04x has been disabled\n", + ioaddr); + } else if (strcmp(argv[2], "id") == 0) { + OUTL(0x5555, ioaddr+0x4); + OUTB(0xaa, ioaddr+0x8); + OUTL(0x2aaa, ioaddr+0x4); + OUTB(0x55, ioaddr+0x8); + OUTL(0x5555, ioaddr+0x4); + OUTB(0x90, ioaddr+0x8); + /* 10ms delay needed */ + printf("Manufacturer ID - "); + /* manuf. id */ + OUTL(0x0000, ioaddr+0x4); + printf("%02x\n", inb(ioaddr+0x8)); + /* device id */ + OUTL(0x0001, ioaddr+0x4); + printf("Device ID - %02x\n", inb(ioaddr+0x8)); + /* undo the funky chicken */ + OUTL(0x5555, ioaddr+0x4); + OUTB(0xaa, ioaddr+0x8); + OUTL(0x2aaa, ioaddr+0x4); + OUTB(0x55, ioaddr+0x8); + OUTL(0x5555, ioaddr+0x4); + OUTB(0xf0, ioaddr+0x8); + } else if (strcmp(argv[2], "read") == 0) { + for (i = 0; i < 65536; i++) { + OUTL(i, ioaddr+0x4); + b = inb(ioaddr+0x8); + write(1, &b, 1); + } + } else if (strcmp(argv[2], "prog") == 0) { + /* program the rom in 128 bute chunks */ + for (i = 0, n = 0; i < 65536; i += n) { + n = read(0, buf, 128); + if (n == 0) + break; + if (n < 0) { + perror("File Error"); + exit(-3); + } + /* disable SDP temporarily for programming a sector */ + OUTL(0x5555, ioaddr+0x4); + OUTB(0xaa, ioaddr+0x8); + OUTL(0x2aaa, ioaddr+0x4); + OUTB(0x55, ioaddr+0x8); + OUTL(0x5555, ioaddr+0x4); + OUTB(0xa0, ioaddr+0x8); + for (j = 0; j < n; j++) { + OUTL(i+j, ioaddr+0x4); + OUTB(buf[j], ioaddr+0x8); + } + /* wait for the programming of this sector to coomplete */ + while (inb(ioaddr+0x8) != buf[j-1]) + ; + } + } + + /* Set the register window to 3 for the 3c905b */ + OUTW(0x803, ioaddr+0xe); + /* restore the receiver status */ + OUTL(recvrstat, ioaddr); + return 0; +} + +#endif /* __i386__ */ diff --git a/contrib/3c90xutil/cromutil.c b/contrib/3c90xutil/cromutil.c new file mode 100644 index 0000000..d4751fb --- /dev/null +++ b/contrib/3c90xutil/cromutil.c @@ -0,0 +1,103 @@ +/* + * 3c905cutil.c - perform various control ops on the 3C905C bios rom + * which we assume to be an AT49BV512 + * + */ + +#ifndef __i386__ +# error "This program can't compile or run on non-intel computers" +#else + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/io.h> + +int main(int argc, char **argv) +{ + unsigned int ioaddr, i, n; + unsigned char b; + + setuid(0); /* if we're setuid, do it really */ + if (argc != 3) { + printf("Usage: romid ioaddr [erase|id|read >file|prog <file]\n"); + exit(-1); + } + if (iopl(3)) { + perror("iopl()"); + exit(1); + } + sscanf(argv[1],"%x",&ioaddr); + + /* Set the register window to 0 for the 3C905C */ + outw(0x800, ioaddr+0xe); + + if (strcmp(argv[2], "erase") == 0) { + /* do the funky chicken to erase the rom contents */ + outl(0x5555, ioaddr+0x4); + outb(0xaa, ioaddr+0x8); + outl(0x2aaa, ioaddr+0x4); + outb(0x55, ioaddr+0x8); + outl(0x5555, ioaddr+0x4); + outb(0x80, ioaddr+0x8); + outl(0x5555, ioaddr+0x4); + outb(0xaa, ioaddr+0x8); + outl(0x2aaa, ioaddr+0x4); + outb(0x55, ioaddr+0x8); + outl(0x5555, ioaddr+0x4); + outb(0x10, ioaddr+0x8); + sleep (1); + printf("Bios ROM at %04x has been erased\n", ioaddr); + } else if (strcmp(argv[2], "id") == 0) { + outl(0x5555, ioaddr+0x4); + outb(0xaa, ioaddr+0x8); + outl(0x2aaa, ioaddr+0x4); + outb(0x55, ioaddr+0x8); + outl(0x5555, ioaddr+0x4); + outb(0x90, ioaddr+0x8); + /* 10ms delay needed */ + printf("Manufacturer ID - "); + /* manuf. id */ + outl(0x0000, ioaddr+0x4); + printf("%02x\n", inb(ioaddr+0x8)); + /* device id */ + outl(0x0001, ioaddr+0x4); + printf("Device ID - %02x\n", inb(ioaddr+0x8)); + /* undo the funky chicken */ + outl(0x5555, ioaddr+0x4); + outb(0xaa, ioaddr+0x8); + outl(0x2aaa, ioaddr+0x4); + outb(0x55, ioaddr+0x8); + outl(0x5555, ioaddr+0x4); + outb(0xf0, ioaddr+0x8); + } else if (strcmp(argv[2], "read") == 0) { + for (i = 0; i < 65536; i++) { + outl(i, ioaddr+0x4); + b = inb(ioaddr+0x8); + write(1, &b, 1); + } + } else if (strcmp(argv[2], "prog") == 0) { + for (i = 0; i < 65536; i++) { + n = read(0, &b, 1); + if (n == 0) + break; + if (n < 0) { + perror("File Error"); + exit(-3); + } + outl(0x5555, ioaddr+0x4); + outb(0xaa, ioaddr+0x8); + outl(0x2aaa, ioaddr+0x4); + outb(0x55, ioaddr+0x8); + outl(0x5555, ioaddr+0x4); + outb(0xA0, ioaddr+0x8); + outl(i, ioaddr+0x4); + outb(b, ioaddr+0x8); + while (inb(ioaddr+0x8) != b) + ; + } + } + return 0; +} + +#endif /* __i386__ */ diff --git a/contrib/3c90xutil/romutil.txt b/contrib/3c90xutil/romutil.txt new file mode 100644 index 0000000..58074b9 --- /dev/null +++ b/contrib/3c90xutil/romutil.txt @@ -0,0 +1,36 @@ +I wrote the attached little util program to try out the basic approach +and thought that you might find it useful as well as providing some +simple testing. It isn't a final solution so the interface is rough. The +program must be run as root on an Intel based machine. + +The key point is that the IO address needs to be entered - I grab it +from the dmesg output: + +eth0: 3Com 3c905B Cyclone 100baseTx at 0xe400, 00:10:4b:d2:5e:0d, IRQ +11 + +or "cat /proc/pci" to find the "I/O at XXXXXX" for your 3Com Card. + +Some example commands are: + +romutil 0xe400 erase - erases the ROM contents +romutil 0xe400 protect - enables the Software Data Protection +on the ROM [3c905B only] +romutil 0xe400 unprotect - disables the Software Data Protection +on the ROM [3c905B only] +romutil 0xe400 id - displays the manufacturer and +device IDs +romutil 0xe400 read >file - writes the contents of the ROM to stdout +romutil 0xe400 prog <file - writes the contents of the stdin into the +ROM (<64k) + +I tried reading and writing the ROM while doing large ftp transfers and +experienced no problems. I didn't spend much time worrying about the +possible race conditions. My system has lots of resources (450MHx P2, +128MB RAM) so it might not provide the best test candidate. + +Let me know what results you get if you try it out. + +Thanks + +John diff --git a/contrib/Diskless-From-NT/Config.txt b/contrib/Diskless-From-NT/Config.txt new file mode 100644 index 0000000..60385fb --- /dev/null +++ b/contrib/Diskless-From-NT/Config.txt @@ -0,0 +1,537 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_X86=y +CONFIG_ISA=y +# CONFIG_SBUS is not set +CONFIG_UID16=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# Processor type and features +# +CONFIG_M386=y +# CONFIG_M486 is not set +# CONFIG_M586 is not set +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +# CONFIG_M686 is not set +# CONFIG_M686FXSR is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_X86_CMPXCHG is not set +CONFIG_X86_L1_CACHE_SHIFT=4 +# CONFIG_TOSHIBA is not set +# CONFIG_MICROCODE is not set +# CONFIG_X86_MSR is not set +# CONFIG_X86_CPUID is not set +CONFIG_NOHIGHMEM=y +# CONFIG_HIGHMEM4G is not set +# CONFIG_HIGHMEM64G is not set +CONFIG_MATH_EMULATION=y +CONFIG_MTRR=y +# CONFIG_SMP is not set +# CONFIG_X86_UP_IOAPIC is not set + +# +# General setup +# +CONFIG_NET=y +# CONFIG_VISWS is not set +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +# CONFIG_PCI_NAMES is not set +CONFIG_EISA=y +# CONFIG_MCA is not set +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +CONFIG_PM=y +# CONFIG_ACPI is not set +# CONFIG_APM is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +CONFIG_PARPORT=y +CONFIG_PARPORT_PC=y +CONFIG_PARPORT_PC_FIFO=y +# CONFIG_PARPORT_PC_SUPERIO is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_SUNBPP is not set +# CONFIG_PARPORT_OTHER is not set +# CONFIG_PARPORT_1284 is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set + +# +# Block devices +# +CONFIG_BLK_DEV_FD=m +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +CONFIG_NET_ISA=y +# CONFIG_E2100 is not set +# CONFIG_EEXPRESS is not set +# CONFIG_EEXPRESS_PRO is not set +# CONFIG_HPLAN_PLUS is not set +# CONFIG_HPLAN is not set +# CONFIG_ETH16I is not set +CONFIG_NE2000=y +# CONFIG_SK_G16 is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Input core support +# +# CONFIG_INPUT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_PRINTER=m +# CONFIG_LP_CONSOLE is not set +# CONFIG_PPDEV is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set + +# +# Joysticks +# + +# +# Game port support +# + +# +# Gameport joysticks +# + +# +# Serial port support +# + +# +# Serial port joysticks +# + +# +# Parallel port joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_AGP=m +CONFIG_AGP_INTEL=y +CONFIG_AGP_I810=y +CONFIG_AGP_VIA=y +# CONFIG_AGP_AMD is not set +# CONFIG_AGP_SIS is not set +# CONFIG_AGP_ALI is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=m +# CONFIG_EFS_FS is not set +CONFIG_JFFS_FS_VERBOSE=0 +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +CONFIG_NLS_ISO8859_1=m +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y +# CONFIG_VIDEO_SELECT is not set +# CONFIG_MDA_CONSOLE is not set + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Sound +# +CONFIG_SOUND=m +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +CONFIG_SOUND_ES1371=m +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +CONFIG_SOUND_VIA82CXXX=m +CONFIG_SOUND_OSS=m +# CONFIG_SOUND_TRACEINIT is not set +# CONFIG_SOUND_DMAP is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_ADLIB is not set +# CONFIG_SOUND_ACI_MIXER is not set +# CONFIG_SOUND_CS4232 is not set +# CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_NM256 is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_PAS is not set +# CONFIG_SOUND_PSS is not set +CONFIG_SOUND_SB=m +# CONFIG_SOUND_AWE32_SYNTH is not set +# CONFIG_SOUND_WAVEFRONT is not set +# CONFIG_SOUND_MAUI is not set +CONFIG_SOUND_YM3812=m +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_YMPCI is not set +# CONFIG_SOUND_YMFPCI is not set +# CONFIG_SOUND_UART6850 is not set +# CONFIG_SOUND_AEDSP16 is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +# CONFIG_MAGIC_SYSRQ is not set diff --git a/contrib/Diskless-From-NT/Diskless-From-NT.txt b/contrib/Diskless-From-NT/Diskless-From-NT.txt new file mode 100644 index 0000000..54c2b74 --- /dev/null +++ b/contrib/Diskless-From-NT/Diskless-From-NT.txt @@ -0,0 +1,565 @@ + + +The Diskless Terminal running from NT server Mini-HOWTO +Pavel Tkatchouk, ptkatcho@portal.ca +v0.1, June 19th 1999 + +Table of Contents + +1. Introduction. + + 1.1 What is it for? + 1.2 Do we need this HOWTO? + 1.3 A bit of History. + +2. Project description. + + 2.1 Packaging. + 2.2 Image. + 2.2.1 Kernel. + 2.2.2 MRFS. + 2.2.3 Building MRFS. + 2.3 Remotefs. + 2.4 Booting sequence. + 2.4.1 BOOTP, TFTP. + 2.5 Bootprom. + +3. Resources. + +4. Copyright. + +5. Feedback and credits. + + +1. Introduction. + + +1.1. What is it for? + +This document describes how to build software distribution to run Java client on diskless +terminal booted from Microsoft Windows 95/98/NT workstation. Package can also be easily +modified to be used as Linux terminal or X Windows terminal's software. I found it also +convenient for setup over the Ethernet of floppyless PS's, hard disk of which for some +reason can not be accessed (sealed case under warranty, etc.). + + +1.2. Do we need this HOWTO? + +To be honest, I'm not sure. There are few excellent HOWTO's (see 3. Recources) that up until +recently I considered quite sufficient to build what I've done two years ago. But since my +project uses MS Windows as a file server vs. traditional NFS there were some know-how's +involved which number of people wanted to see in some formal document. + + +1.3. A bit of history. + +My project at that time (1996) was to find OS/JVM that will allow to run Java application +on hardware we manufacture. Hardware is practically generic x86 PC except it has no keyboard, +hard drive, floppy drive, mouse, but touchscreen over LCD, plus some POS specific peripherals +(badge reader, credit card reader, etc.). Due to cost consideration it had no any significant +storage, so OS and Java client along with support binaries, libraries etc. had to be loaded +remotely. Because our clients are exclusively Windows shops, Server had to be Windows as well. +During evaluation of different commercial OS'es along with JVM's available it become apparent +to my surprise that most promising solution was GPL one - Linux. + + +2. Project description. + +2.1. Packaging. + +The whole distribution consists of remote file system (RemoteFS) residing on MS Windows +server (NT Workstation, NT Server or Windows9x) and tagged bootable image. + + +2.2. Image. + +Image (~1.5MB) is generated by mknbi utility that comes with Etherboot package +<http://etherboot.sourceforge.net>. It can include minimal root file system (MRFS) +like in my case (since I had to boot client from MS Windows server and Linux kernel doesn't +support SMBFS-Root, only NFS-Root. So I had to keep rootfs in the ramdisk). To generate +image the following script can be used. + +#!/bin/sh +# mkrootnet: makes tagged netbootable image +# This image includes kernel and minimal root filesystem +# to do initial boot. +# +# Copyright (c) Pavel Tkatchouk 1996. All rights reserved. +# Permission is granted for this material to be freely +# used and distributed, provided the source is acknowledged. +# No warranty of any kind is provided. You use this material +# at your own risk. +# +DEVICEFILENAME="/tmp/file" # temporary file to be used as device +FSBLOCKS=4096 # uncompressed filesystem size in K +BOOTDISKDIR="/usr/BOOT/ROOTFS" # root filesystem model +MOUNT="/mnt2" # temporary mount point +ROOTFS="/tmp/rootfs" # root filesystem image +ROOTFSGZ="/tmp/rootfs.gz" # compressed root filesystem image +KERNEL="/usr/KERNELS/vmlinuz-nt" # kernel image +KERNELTMP="/tmp/vmlinuz" # temporary copy of kernel image +BOOTIMAGE="/tmp/img" # tagged image to be booted by client +# if you want ramisk more than default 4096 set CMDLINE, don't forget to +# adjust $FSBLOCKS +# CMDLINE="ramdisk_size=8192" # parameters to pass to the kernel +# +echo "check:" +echo "- if tftp server's download dir mounted to /mnt" +echo "- loopback device is built-in or loaded" +echo "\n press Enter when done" +read tmp +UPLOAD="/mnt/tmp" # tftp server's dir to upload bootimage +echo -e "\nZeroing $DEVICEFILENAME of $FSBLOCKS k" +echo "to be used as device for root filesystem model" +dd if=/dev/zero of=$DEVICEFILENAME bs=1k count=$FSBLOCKS +echo -e "\nMaking file system on $DEVICEFILENAME" +mke2fs -m 0 $DEVICEFILENAME +echo "Mounting $DEVICEFILENAME as a loopback device" +mount -o loop -t ext2 $DEVICEFILENAME $MOUNT +curdir=`pwd` +cd $BOOTDISKDIR +echo -e "Copying files from $BOOTDISKDIR to $DEVICEFILENAME, please wait" +find . -print|cpio -pmd $MOUNT +echo "Unmounting $MOUNT" +umount $MOUNT +cd $curdir +echo "Copying $DEVICEFILENAME to $ROOTFS" +dd if=$DEVICEFILENAME of=$ROOTFS bs=1k +echo "Compressing $ROOTFS, it may take a while" +echo "Please wait..." +if [ -f $ROOTFSGZ ];then + rm -f $ROOTFSGZ +fi +gzip -c $ROOTFS>$ROOTFSGZ +rm -f $ROOTFS +echo -e "\nCreating netbootable image" +cp $KERNEL $KERNELTMP +mknbi -d ram -i rom -r $ROOTFSGZ -k $KERNELTMP -a $CMDLINE -o $BOOTIMAGE +echo "Uploading $BOOTIMAGE to $UPLOAD" +cp $BOOTIMAGE $UPLOAD +echo "Cleaning after ourselves" +rm -f $KERNELTMP $DEVICEFILENAME $BOOTIMAGE +echo "All done" + + +In the above script actual image is generated by the following comand + +#mknbi -d ram -i rom -r rootfs.gz -k vmlinuz-nt -o img + +where: + rootfs.gz - minimal root file system (MRFS); + vmlinuz-nt - kernel; + img - resulting image. + + +Note: +Default ramdisk size is 4096. It was enough for RedHat4.1 based minimal file system, but +apparently not enough for 5.2 based. When this happens "end request:I/O error, dev 01:00 ..." +error shows up. To fix that either use "mknbi -a ramdisk_size=8192" to pass parameter to the +kernel (doesn't require kernel recompilation), or change /usr/src/linux/drivers/block/rd.c: +int rd_size= from 4096 to 8192 or whatever and rebuild the kernel. + + +2.2.1. Kernel. + +Kernels 2.0.30 and 2.0.36 have been used by author, although nothing is preventing you from +experimenting with others. Kernel should include ramdisk support. The following +<link to .config> configuration has been used to build <link to binary (kernel 2.0.30)>. +You may find some components unnecessary, just exclude them and rebuild. + +Don't forget to change root device after you built the kernel (rdev vmlinuz /dev/rd). + +Gotcha's: apparently smbfs is broken in 2.2.x kernels. Symptoms: remote share is mounted +just fine but after a while fails with "smb_request: result = -32" errmsg. I've heard +SuSe has fix for that. + +2.2.2. MRFS. + +Minimal root file system is required to get Linux up and running along with networking until +it can mount remote file system to run X/Java from there. After image gets loaded from the +server MRFS is decompressed into ramdisk. If you can afford a lot of ram on your terminal the +entire remote file system can be moved to rootfs.gz. That will make your terminal more +responsive. + + +2.2.3. Building MRFS. + +Some folks found it easier to start from scratch, others use known "minimal" Linux distributions +(Linux Router, tomsrtbt, etc.), yet others prefer to start from "big" Linuces like I did. Every +path has it's pro and contras. + +Pruning standard distribution (RedHat, Debian, etc.) to your needs might be very time consuming. +To ease that painful process I have used remotely booted diskless client with NFS-Root (see +Etherboot's Readme, NFS-Root and NFS-Root-Client mini-HOWTO's, Diskless-HOWTO): + +- setup minimal RedHat4.1 install (networked workstation, X, no development, mail, etc., ~117MB); +- find . -print|cpio -pmd /usr/NFS/ROOTFS - copy entire fs tree to NFS exported dir; +- mknod /usr/NFS/ROOTFS/dev/nfsroot b 0 255; +- build vmlinuz-nfs kernel according to NFS-Howto (built-in bootp,rarp,NFS,NFS root,NIC + driver,RAM disk); +- rdev vmlinuz-nfs /dev/nfsroot - to set NFS root device; +- build image for NFS-Root fs: + #mknbi -d rom -i rom -k vmlinuz-nfs -o nfsImage; +- boot client while monitoring NFS file requests (by Solaris snoop); +- copy files from /usr/NFS/ROOTFS to /usr/BOOT/ROOTFS (MRFS model) according to snoop's + filelist; +- generate image by mkrootnet script (don't forget to point to the right kernel vmlinuz-nt). + +The above trick not only allows to determine the sought files set but also debug boot process +analyzing NFS messages. I found it convenient to put "read tmp" statements into init scripts +for debugging. Tracking files up until issuing login gives you <link to rootfs.gz> MRFS (~1MB) +that can be used to boot Linux from ROM (flash, eprom, DiskOnChip, SanDisk, etc.) as well. All +the other files requested by client (during starting X, Java, Java client) were put into (link +to remotefs.zip, ~9MB). + + +To restore MRFS model on your PC from the above rootfs.gz: +- #cd /tmp +- #gunzip rootfs.gz +- #mount -o loop -t ext2 /tmp/rootfs /mnt +- #cd /mnt +- #find . -print|cpio -pmd /usr/BOOT/ROOTFS +- #umount /mnt + +Note: + +You will have to change attributes of some dirs, files (/etc/mtab, /etc/mtab~, /var/lock/subsys/*, +/var/run/*, /dev/tty*, etc.) against standard. This is because with standard attribs diskless +client refused to work. For example I had to change /dev/tty* ownerships to 99:99 from original +0:0 or 0:5, to get rid of errmsg "INIT: Id "1" respawning too fast: disabled for 5 minutes". +Being admin illiterate I just chmod them to 777 and chown to 99:99 to make life easier. +THIS IS SERIOUS SECURITY VIOLATION!!! Using keyboardless terminal with no daemons running in +my case reduces the risk, yet I would appreciate very much those more experienced who will help +to restore the right attribs while keeping the distribution working. + +Some "gotcha's" to watch for during MRFS building: +- standard attributes/ownership of some files don't work; +- rdev must be set (non-tagged image didn't work, so couldn't use config file to pass parrs + to the kernel); +- diskless client writes 99:99 ownership on generated files; +- "password incorrect" for root, but any other OK and su OK too. + + +2.3. RemoteFS. + +Remotefs.zip file includes everything required by the system that can be located on +remote file system, i.e after booting has been complete and remote file system mounted. +In my case it is X Windows System and Java binaries, libraries etc. To use that file on +MS Windows NT: +- unzip remotefs.zip to some directory; +- share this directory read-only as "usr" (or share as some other name and pass this name to + the client through bootptab configuration file for BOOTP server; +- create an account username=root, password=linux on NT (can be set in bootptab). + +Note: +There's no symbolic links on NTFS, so UNIX links must be replaced by copies on NTFS. +To determine potential troublmakers one could use the following: +- first copy required subset (according to snoop's intercept) from /usr/NFS/ROOTFS to + /usr/BOOT/REMOTEFS; +- mount some share from NTFS to /mnt; +- /usr/BOOT/REMOTEFS#find . -print|cpio -pmd /mnt 2>links; +In the links file you will find names to work with. + + +2.4. Booting sequence. + +Boot occurs in the following sequence: +- bootprom sends bootp request, +- bootp server responds with subnet mask, client's name, client's IP, TFTP server's IP, + bootfile name and some optional parameters (like NT's username/password to use it's share, + you could pass some other share name here as say T104="somedir"); +- bootprom downloads image from TFTP server; +- kernel starts; +- kernel decompresses MRFS in RAM; +- system starts init using ramdisk root, +- mounts remote file system from NT via SMBFS; +- automatically logins; +- starts xstart script located on remotefs (/usr/sbin) where you can start any of your + programs, change parameters, etc. without rebuilding the image. + +Below are some config/init sample files from <rootfs.gz>, <remotefs.zip>: + +<bootptab, change to link> +t1:sm=255.255.255.0:sa=192.168.33.150:bf=img:T100="pavelnt4":T101="root":T102="linux" +touch1:hn=touch1:tc=t1:ha=00A0F00035CD:ip=192.168.33.127 + +</etc/fstab, change to link>: +/dev/ram / ext2 defaults 1 1 +/proc /proc proc defaults 0 0 + +</etc/rc.d/rc.bootp, change to link later>: +#!/bin/sh +# Written to simply set the IP stuff up from the +# bootpc data. +# Last updated : Mon Mar 10 15:17:01 1997 +# +# Variables + +BOOTPC=/sbin/bootpc +IFCONFIG=/sbin/ifconfig +ROUTE=/sbin/route +BINHOST=/bin/hostname +DEV=eth0 +ASKSERVER="255.255.255.255" +TW="--timeoutwait 320" +RIF="--returniffail" +RIFMESSAGE="Bootp failed -- disabling network." +RCONF=/etc/resolv.conf +EHOSTS=/etc/hosts +LHOSTS=/etc/hosts.local +TMPFILE=/tmp/bootp +# Functions +# Remove the networking by taking down the interface +netdown() { + ${ROUTE} del default + ${IFCONFIG} ${DEV} down +} +## End of the functions + +## Start of the actual work +# Bring up minimal networking use 0.0.0.0 as our address as we don't +# know it yet (Means "Me but I don't know my address or network") +${IFCONFIG} ${DEV} up 0.0.0.0 +${ROUTE} add default dev ${DEV} + +# Perform the bootp -- doesn't return unless it gets an answer +if ${BOOTPC} --dev ${DEV} --server ${ASKSERVER} ${RIF} ${TW} > ${TMPFILE} +then +# Take down networking (use the 0.0.0.0 for as short a time as possible) + netdown +# Read in the values + . ${TMPFILE} + +# To use in mountsmb script later +SMBSERVER=${T100} +# And delete the temporary file +# rm ${TMPFILE} +else +# Take down networking (use the 0.0.0.0 for as short a time as possible) + netdown +# give message and quit + echo ${RIFMESSAGE} + exit 1 +fi + +# Start the loopback interface and add a route to it +# It's already set by standard init? +${IFCONFIG} lo 127.0.0.1 +${ROUTE} add -net 127.0.0.0 + +# Setup of IP stuff needs doing first +# +if [ -z "${NETMASK}" ] ; then +# No netmask info, all this is guessed from the IP number +# If this is wrong for your network FIX the bootpd to know +# what it should send in the RFC1497 cookie! 11/02/94 JSP +# + ${IFCONFIG} ${DEV} up ${IPADDR} broadcast ${BROADCAST} + ${ROUTE} -n add -net ${NETWORK} dev ${DEV} +else +# We will have NETMASK, BROADCAST, and NETWORK defined + ${IFCONFIG} ${DEV} up ${IPADDR} broadcast ${BROADCAST} netmask ${NETMASK} + ${ROUTE} -n add -net ${NETWORK} dev ${DEV} +fi + +# Set the hostname from what we got via bootp or reverse lookup + +echo "127.0.0.1 loopback localhost">${EHOSTS} +${BINHOST} "${HOSTNAME}" +echo "${IPADDR} ${HOSTNAME}" >>${EHOSTS} +echo "${SERVER} ${SMBSERVER}" >>${EHOSTS} + + +</etc/rc.d/rc.local, change to link>: +#!/bin/sh +# This script will be executed *after* all the other init scripts. +# You can put your own initialization stuff in here if you don't +# want to do the full Sys V style init stuff. +# +# 07/02/97 Pavel Tkatchouk +# +echo "Start networking" +insmod /lib/8390.o +insmod /lib/ne.o io=0x300 irq=9 +echo "Install serial" +insmod /lib/serial.o +echo "Install touch" +insmod /lib/touch.o +echo "Install smbfs" +insmod /lib/smbfs.o +echo "Getting TCP/IP parameters from bootp server" +echo "and start networking" +/etc/rc.d/rc.bootp +if [ -f /etc/squirrel-release ]; then + R=$(cat /etc/squirrel-release) +else + R="release 0.02" +fi +echo "Mounting remote fs" +/sbin/mountsmb +echo "XYZ Inc. Diskless Linux $R" +echo "Starting X and Java client without login" +su -c /sbin/xstart root + + +</usr/sbin/xstart, change to link>: +#!/bin/bash +# +# Script to start X and Java client +# 08/07/97 Pavel Tkatchouk +# +# Read bootps response first +. /tmp/bootp +# -s 0 to disable screen-saver +/usr/X11R6/bin/X -s 0 & +export DISPLAY=:0.0 +# /usr is share mounted from Windows workstation +cd /usr/program/ +java SomeJavaApp + + +</sbin/mountsmb, change to link>: +#!/bin/bash +# mountsmb: mounts remote filesystems from NT workstation +# using Microsoft's SMB protocol +# +# Copyright (c) Pavel Tkatchouk 1997. All rights reserved. +# Permission is granted for this material to be freely +# used and distributed, provided the source is acknowledged. +# No warranty of any kind is provided. You use this material +# at your own risk. +# +# Last edit June 29 8:30 1997 +# +MOUNTDIR="usr" +SHRDIR="usr" +BOOTPRES="/tmp/bootp" +# Read botpc response +. ${BOOTPRES} +# Sharename from NT server, uncomment if you want to use +# non-hardcoded "usr" but from bootptab +#SHRDIR=${T104} +SMBSRV="//${T100}" +CLIENT="${HOSTNAME}" +USER="${T101}" +PASSWORD="${T102}" +echo -e "\nMounting $SMBSRV/$SHRDIR to /$MOUNTDIR" +smbmount $SMBSRV/$SHRDIR $MOUNTDIR -c $CLIENT -U $USER -P $PASSWORD +echo -e "\nDone" + +Gotcha's: +Looks like smbmount client from smbfs package used to mount remote Windows shares to local +Linux dirs in pre 2.2.x era isn't maintained anymore so you should use one coming with +Samba package. Also binary smbmount won't work with 2.2.x, so you have to recompile with +2.2.x headers following Samba's readme. Yet even that won't guarantee reliable work until +somebody fixes kernel's smbfs module. + +2.4.1. BOOTP, TFTP. + +There are number of BOOTP, TFTP servers for Windows on the market. You could find them +here: + +- www.walusoft.co.uk (Walusoft's tftp); +- ftp.coast.net/simtel/nt/internet/tftpds12.zip (Millwood AB's tftp); +- ftp.cabletron.com/pub/snmp/bootftp/boottft2.zip (Cabletron's bootp/tftp combo); +- www.tellurian.au.com (Tellurian's bootp, tftp, dhcp servers). +- www.metainfo.com (Metainfo's DHCP server) +- www.nts.com (Network Telesystems's DHCP server in IPserver package) + +My choice was Tellurian's products - very reliable, simple to install, attractively priced +(fully capable evaluation versions are available). + +2.5. Bootprom. + +Ken Yap's Etherboot <etherboot.sourceforge.net> will tell you everything about bootprom. +Here I just want to mention that normally you would have to put bootprom's code into network +adapter's PROM. But if your hardware like mine has BIOS programmed in flash you could +re-program it to add bootprom (some BIOS requires special programmer to do that, others don't) +as BIOS extension. + +This is what I did to add ne.rom (bootprom generated by Etherboot's makerom for NE2000 clone) +to AMI BIOS on my flash: + +- read flash content by programmer into bios.bin binary file; +- use one of available binary editors (say www.simtel.net/Win95/editors/hxp3005.zip to add + ne.rom to bios.bin (and to edit ne.rom if necessary); +- write new bios.bin back to flash. + +Notes: +- makerom generates bootprom for standard EPROM sizes (8k, 16k, 32k, etc.), so if you tight on + space use -s flag to adjust size (or cut it manually to multiple of 512 bytes blocks, just + don't forget to adjust extension's length which is coded in Byte 2 and checksum to 8 bits + of zero; +- valid absolute addresses for BIOS extensions are from 0xC8000 to 0xF4000 (check with + motherboard's manufacturer how flash is mapped onto system memory space); +- Byte 0 must be 0x55, Byte 1 must be 0xAA, Byte 2 must be extension's length in 512 bytes + blocks; +- extension BIOS has to start at a 2k boundary; + + +3. Resources. + +FAQ's: +- tomsrtbt.FAQ (www.toms.net); + +HOWTO's: +- Paul Moody's miniHOWTO (www.linuxembedded.com/pmhowto.html) +- Diskless; +- Diskless-HOWTO; +- NFS-Root; +- NFS-Root-Client; +- Bootdisk-HOWTO; +- BootPrompt-HOWTO; +- NCD-X-Terminal; +- Remote-Boot; +- Remote-X-Apps; + +Web: +- etherboot.sourceforge.net/ +- www.waste.org/~zanshin +- www.tellurian.com.au. +- www.toms.net +- www.trinux.org +- www.linux.org.uk/ELKS-Home +- www.embedded.com +- www.linuxembedded.com +- www.thinlinux.org +- www.linuxrouter.org +- linux-mandrake.com +- www.disklessworkstations.com + +Newsgroups: +- comp.arch.embedded + +Lists: +- netboot-owner@baghira.han.de +- linux-embedded@waste.org + +Magazines: +- Circuit Cellar #100 - 105 + + +4. Copyright. + +Copyright (c) Pavel Tkatchouk 1999. +Permission is granted for this material to be freely used and distributed, provided the source +is acknowledged. Copyright policy is GPL as published by the Free Software Foundation. + +No warranty of any kind is provided. You use this material at your own risk. + + + +5. Feedback and credits. + +Since I am neither have a lot of Linux experience nor native English speaker, there would be +errors in this document. I would accept any help with gratitude whether in form of proof-reading, +techical corrections or otherwise. Please send your comments, suggestions and questions to Pavel +Tkatchouk (ptkatcho@portal.ca) + +I wish to thank Pierre Mondie who convinced me to start this document. I'm also very much in +debt to all those who's work made this project possible: + +Ken Yap <ken_yap@users.sourceforge.net> (Etherboot) +David Newall <www.tellurian.com.au> (Bootpdnt/Ftpdnt) +(to be continued) + diff --git a/contrib/Diskless-From-NT/furtmayr.html b/contrib/Diskless-From-NT/furtmayr.html new file mode 100644 index 0000000..224632d --- /dev/null +++ b/contrib/Diskless-From-NT/furtmayr.html @@ -0,0 +1,82 @@ +<html> + +<head> +<title>Free TFTP / Syslog / NFS Servers for Windows</title> +</head> + +<body> + +<h3 align="center">Free TFTP / Syslog / NFS Servers for Windows</h3> +<div align="center"><center> + +<address> + Stefan Furtmayr (<a href="mailto:sf@paf.net">sf@paf.net</a>) +</address> +</center></div> + +<p>Feel free to send me your comments about these programs or some additions.</p> + +<p>Also have a look at the <a +href="http://www.ltsp.org/contrib/diskless-windows-howto.htm">"Diskless Windows +Cookbook "</a> in the <a href="http://www.ltsp.org/contrib/">LTSP Contrib Area</a>.</p> + +<p><small>From this list I have only used the W2K-TFTP once for a customer with the <a +href="http://support.3com.com/infodeli/tools/nic/mba.htm">3Com MBA Utility Disk</a>, while +it can be used as well with <a href="http://etherboot.sourceforge.net">Etherboot</a> +tagged images for other NIC brands.</small><br> +<small>The solution used a netbooted DOS with MS Client 3.0 to easily restore disk images +with <a href="http://www.ghost.com/">Symantec Ghost</a> (see <a +href="http://appdeploy.com/tools/imaging.shtml">appdeploy.com</a> for similar tools).</small><br> +<small>Sure there are several possibilities to do this with Linux but for cloning NT4/W2K +the NTFS support is rather experimental and automatically changing the SID is another +issue.</small></p> + +<h4>TFTP Servers:</h4> + +<p>In Autumn 2000 i tested some different TFTP servers and found out that most of them do +not install/run as a service, especially under W2K. + +<ul> + <li>TFTP server included with Windows 2000 (remote installation services need to be + installed)<br> + The path for the images has to be specified via registry:<br> + Q232115 - Changing the Drive or Volume on Which Remote Installation Images Reside:<br> + <a href="http://support.microsoft.com/support/kb/articles/Q232/1/15.ASP">http://support.microsoft.com/support/kb/articles/Q232/1/15.ASP</a></li> + <li>3CDaemon version 2.0 revision 10. Freeware. Integrated TFTP/FTP/Syslog Daemon for + Windows 95/98/NT<br> + <a href="ftp://ftp.3com.com/pub/utilbin/win32/3cdv2r10.zip">ftp://ftp.3com.com/pub/utilbin/win32/3cdv2r10.zip</a><br> + - Windows 2000 Server: does not run as service!<br> + - Windows NT Server 4.0: not tested</li> + <li>The TFTP Server portion of 3CServer, altered to run as a system Service under Windows NT<br> + <a href="ftp://ftp.3com.com/pub/utilbin/win32/3CTftpSvc.zip">ftp://ftp.3com.com/pub/utilbin/win32/3CTftpSvc.zip</a><br> + - Windows 2000 Server: only working in debug mode, does not run as service!<br> + - Windows NT Server 4.0: not tested</li> + <li>Cisco TFTP Server v.1.1<br> + <a href="http://www.cisco.com/pcgi-bin/tablebuild.pl/tftp">http://www.cisco.com/pcgi-bin/tablebuild.pl/tftp</a><br> + Does not provide an option itself to install as service.</li> + <li><a href="http://solarwinds.net/Tools/Free_Tools/TFTP_Server/">http://solarwinds.net/Tools/Free_Tools/TFTP_Server/</a><br> + Does not provide an option itself to install as service.</li> +</ul> + +<p><em>Untested:</em></p> + +<p>found on <a href="http://www.nonags.com/nonags/servd32.html">http://www.nonags.com/nonags/servd32.html</a><br> +- <a href="http://www.klever.net/kin/pumpkin.html">http://www.klever.net/kin/pumpkin.html</a><br> +- <a href="http://membres.tripod.fr/phjounin//P_tftpd32.htm">http://membres.tripod.fr/phjounin//P_tftpd32.htm</a></p> + +<h4>Syslog Servers:</h4> + +<ul> + <li>3Com Software Library - Utilities for 32 bit Windows<br> + <a href="http://support.3com.com/software/utilities_for_windows_32_bit.htm">http://support.3com.com/software/utilities_for_windows_32_bit.htm</a></li> + <li><a href="http://www.netal.com/download.htm#SL4NT03">http://www.netal.com/download.htm#SL4NT03</a> + (works as service) </li> +</ul> + +<h4>NFS Servers:</h4> + +<ul> + <li>War NFS Daemon: <a href="http://www.jgaa.com">http://www.jgaa.com</a> (untested)</li> +</ul> +</body> +</html> diff --git a/contrib/auto-default/mail b/contrib/auto-default/mail new file mode 100644 index 0000000..015c789 --- /dev/null +++ b/contrib/auto-default/mail @@ -0,0 +1,40 @@ +Date: 11/9/2001 3:56 PM +Received: 11/9/2001 4:05 PM +From: Steve Tilden, stilden@sicom-sys.com + +... + +2) I have added conditional code to main.c from Etherboot 5.0.4 to add +a new default boot option and I have included the modified main.c as an +attachment to this message. + +As I received Etherboot 5.0.4, in the Config file, if you select +ASK_BOOT with a non zero time-out option, then you also get to set +ANS_DEFAULT = ANS_NETWORK or ANS_DEFAULT = ANS_LOCAL to determine what +will happen if the operator does not respond to the prompt. I have now +added conditional code in main.c such that if you set ANS_DEFAULT = +ANS_AUTO, the default answer will be set according to whether or not +there is a hard disk in the system (as detected by the BIOS). If a hard +disk is present, then if the operator does nothing, the system will boot +from it. If a hard disk does not exist, then again if the operator does +nothing, the system will boot via the network. Either way, for our +particular environment, the operator has to do nothing to get it to boot +correctly. Yet the operator can still override the default selection +to, for example, allow a unit without a hard disk, to boot directly from +a floppy rather than the network, or to allow a unit with a hard disk, +to boot from the network. + +I don't know it the code I have added might be correct for a future +production version of Etherboot, but I thought I'd send it to you and +let you get it into the system if you feel it might be appropriate. + +Thanks, + +Steve Tilden +Sicom Systems Inc. +stilden@sicom-sys.com + +[Ed: On a compliant BIOS, it will actually boot the next device in the +BIOS list if local is selected, either explicitly or by timeout, which +may or may not be the hard disk, which is why it's less than general and +not included in the distribution by default.] diff --git a/contrib/auto-default/main.c.patch b/contrib/auto-default/main.c.patch new file mode 100644 index 0000000..e707b63 --- /dev/null +++ b/contrib/auto-default/main.c.patch @@ -0,0 +1,55 @@ +--- main.c Mon Nov 5 18:58:30 2001 ++++ main.c.new Thu Nov 15 01:45:12 2001 +@@ -149,21 +151,49 @@ + static unsigned short ipchksum(unsigned short *ip, int len); + static unsigned short udpchksum(struct iphdr *packet); + ++ ++#if defined(ASK_BOOT) && ASK_BOOT > 0 && (ANS_DEFAULT == ANS_AUTO) ++/* ++ * Read Installed Hard Disk Count from BIOS memory at 0:0475 ++ */ ++static int hdsk_cnt(void) ++{ ++ int retv; ++ __asm__ __volatile__( ++ "xorw %%ax,%%ax\n\t" ++ "movb 0x475,%%al\n" ++ : "=a" (retv) ++ : /* no inputs */ ++ : "ax", "cc", "memory" ++ ); ++ return(retv); ++} ++#endif /* ASK_BOOT && ANS_AUTO */ ++ ++ + static inline void ask_boot(void) + { + #if defined(ASK_BOOT) && ASK_BOOT > 0 + while(1) { +- int c; ++ int c, deflt; + unsigned long time; ++#if defined(ASK_BOOT) && ASK_BOOT > 0 && (ANS_DEFAULT == ANS_AUTO) ++ if (hdsk_cnt() != 0) ++ deflt = ANS_LOCAL; ++ else ++ deflt = ANS_NETWORK; ++#else ++ deflt = ANS_DEFAULT; ++#endif + printf(ASK_PROMPT); + for (time = currticks() + ASK_BOOT*TICKS_PER_SEC; !iskey(); ) + if (currticks() > time) { +- c = ANS_DEFAULT; ++ c = deflt; + goto done; + } + c = getchar(); + if ((c >= 'a') && (c <= 'z')) c &= 0x5F; +- if (c == '\n') c = ANS_DEFAULT; ++ if (c == '\n') c = deflt; + done: + if ((c >= ' ') && (c <= '~')) putchar(c); + putchar('\n'); diff --git a/contrib/award_plugin_roms/README b/contrib/award_plugin_roms/README new file mode 100644 index 0000000..5f657cf --- /dev/null +++ b/contrib/award_plugin_roms/README @@ -0,0 +1,2 @@ +An Award BIOS ROM lister in Perl contributed by Eric W. Biederman +<ebiederman@lnxi.com>. diff --git a/contrib/award_plugin_roms/award_plugin_roms.pl b/contrib/award_plugin_roms/award_plugin_roms.pl new file mode 100755 index 0000000..2b95eed --- /dev/null +++ b/contrib/award_plugin_roms/award_plugin_roms.pl @@ -0,0 +1,341 @@ +#!/usr/bin/perl -w +use strict; +use FileHandle; +use integer; + +sub unsigned_little_endian_to_value +{ + # Assumes the data is initially little endian + my ($buffer) = @_; + my $bytes = length($buffer); + my $value = 0; + my $i; + for($i = $bytes -1; $i >= 0; $i--) { + my $byte = unpack('C', substr($buffer, $i, 1)); + $value = ($value * 256) + $byte; + } + return $value; +} + +sub decode_fixed_string +{ + my ($data, $bytes) = @_; + return $data; +} + +sub decode_pstring +{ + my ($buf_ref, $offset_ref) = @_; + # Decode a pascal string + my $offset = ${$offset_ref}; + my $len = unpack('C',substr(${$buf_ref}, $offset, 1)); + my $data = substr(${$buf_ref}, $offset +1, $len); + ${$offset_ref} = $offset + $len +1; + return $data; +} + +sub decode_cstring +{ + # Decode a c string + my ($buf_ref, $offset_ref) = @_; + my ($data, $byte); + my $index = ${$offset_ref}; + while(1) { + $byte = substr(${$buf_ref}, $index, 1); + if (!defined($byte) || ($byte eq "\0")) { + last; + } + $data .= $byte; + $index++; + } + ${$offset_ref} = $index; + return $data; +} + +sub type_size +{ + my ($entry) = @_; + my %type_length = ( + byte => 1, + half => 2, + word => 4, + xword => 8, + 'fixed-string' => $entry->[2], + pstring => 0, + cstring => 0, + ); + my $type = $entry->[0]; + if (!exists($type_length{$type})) { + die "unknown type $type"; + } + my $length = $type_length{$type}; + return $length; +} + +sub decode_fixed_type +{ + my ($type, $data, $bytes) = @_; + my %decoders = ( + 'byte' => \&unsigned_little_endian_to_value, + 'half' => \&unsigned_little_endian_to_value, + 'word' => \&unsigned_little_endian_to_value, + 'xword' => \&unsigned_little_endian_to_value, + 'fixed-string' => \&decode_fixed_string, + ); + my $decoder = $decoders{$type} or die "unknow fixed type $type"; + return $decoder->($data, $bytes); +} + +sub decode_variable_type +{ + my ($type, $buf_ref, $offset_ref) = @_; + my %decoders = ( + 'pstring' => \&decode_pstring, + 'cstring' => \&decode_cstring, + ); + my $decoder = $decoders{$type} or die "unknow variable type $type"; + return $decoder->($buf_ref, $offset_ref); +} + +sub decode_struct +{ + my ($buf_ref, $offset, $layout) = @_; + my $initial_offset = $offset; + my ($entry, %results); + foreach $entry (@$layout) { + my ($type, $name) = @$entry; + my $bytes = type_size($entry); + if ($bytes > 0) { + my $data = substr(${$buf_ref}, $offset, $bytes); + $results{$name} = decode_fixed_type($type, $data, $bytes); + $offset += $bytes; + } else { + $results{$name} = decode_variable_type($type, $buf_ref, \$offset); + } + } + return (\%results, $offset - $initial_offset); +} + +sub print_big_hex +{ + my ($min_digits, $value) = @_; + my @digits; + while($min_digits > 0 || ($value > 0)) { + my $digit = $value%16; + $value /= 16; + unshift(@digits, $digit); + $min_digits--; + } + my $digit; + foreach $digit (@digits) { + printf("%01x", $digit); + } +} + + + +my %lha_signatures = ( + '-com-' => 1, + '-lhd-' => 1, + '-lh0-' => 1, + '-lh1-' => 1, + '-lh2-' => 1, + '-lh3-' => 1, + '-lh4-' => 1, + '-lh5-' => 1, + '-lzs-' => 1, + '-lz4-' => 1, + '-lz5-' => 1, + '-afx-' => 1, + '-lzf-' => 1, +); + +my %lha_os = ( + 'M' => 'MS-DOS', + '2' => 'OS/2', + '9' => 'OS9', + 'K' => 'OS/68K', + '3' => 'OS/386', + 'H' => 'HUMAN', + 'U' => 'UNIX', + 'C' => 'CP/M', + 'F' => 'FLEX', + 'm' => 'Mac', + 'R' => 'Runser', + 'T' => 'TownOS', + 'X' => 'XOSK', + 'A' => 'Amiga', + 'a' => 'atari', + ' ' => 'Award ROM', +); + + +my @lha_level_1_header = ( + [ 'byte', 'header_size' ], # 1 + [ 'byte', 'header_sum', ], # 2 + [ 'fixed-string', 'method_id', 5 ], # 7 + [ 'word', 'skip_size', ], # 11 + [ 'word', 'original_size' ], # 15 + [ 'half', 'dos_time' ], # 17 + [ 'half', 'dos_date' ], # 19 + [ 'byte', 'fixed' ], # 20 + [ 'byte', 'level' ], # 21 + [ 'pstring', 'filename' ], # 22 + [ 'half', 'crc' ], + [ 'fixed-string', 'os_id', 1 ], + [ 'half', 'ext_size' ], +); + +# General lha_header +my @lha_header = ( + [ 'byte', 'header_size' ], + [ 'byte', 'header_sum', ], + [ 'fixed-string', 'method_id', 5 ], + [ 'word', 'skip_size', ], + [ 'word', 'original_size' ], + [ 'half', 'dos_time' ], + [ 'half', 'dos_date' ], + [ 'half', 'rom_addr' ], + [ 'half', 'rom_flags' ], + [ 'byte', 'fixed' ], + [ 'byte', 'level' ], + [ 'pstring', 'filename' ], + [ 'half', 'crc' ], + [ 'lha_os', 'os_id', 1 ], + [ 'half', 'ext_size' ], + [ 'byte', 'zero' ], + [ 'byte', 'total_checksum' ], + [ 'half', 'total_size' ], +); + +sub print_struct +{ + my ($layout, $self) = @_; + my $entry; + my $width = 0; + foreach $entry(@$layout) { + my ($type, $name) = @$entry; + if (length($name) > $width) { + $width = length($name); + } + } + foreach $entry (@$layout) { + my ($type, $name) = @$entry; + printf("%*s = ", $width, $name); + my $value = $self->{$name}; + if (!defined($value)) { + print "undefined"; + } + elsif ($type eq "lha_os") { + print "$lha_os{$value}"; + } + elsif ($type =~ m/string/) { + print "$value"; + } + else { + my $len = type_size($entry); + print "0x"; + print_big_hex($len *2, $value); + } + print "\n"; + } +} + +sub checksum +{ + my ($buf_ref, $offset, $length) = @_; + my ($i, $sum); + $sum = 0; + for($i = 0; $i < $length; $i++) { + my $byte = unpack('C', substr($$buf_ref, $offset + $i, 1)); + $sum = ($sum + $byte) %256; + } + return $sum; +} + +sub decode_lha_header +{ + my ($buf_ref, $offset) = @_; + my $level = unpack('C',substr(${$buf_ref}, $offset + 20, 1)); + + my %self; + my ($struct, $bytes); + if ($level == 1) { + ($struct, $bytes) + = decode_struct($buf_ref, $offset, \@lha_level_1_header); + %self = %$struct; + if ($self{fixed} != 0x20) { + die "bad fixed value"; + } + $self{total_size} = $self{header_size} + 2 + $self{skip_size}; + if ($bytes != $self{header_size} +2) { + die "$bytes != $self{header_size} +2"; + } + my $checksum = checksum($buf_ref, $offset +2, $self{header_size}); + if ($checksum != $self{header_sum}) { + printf("WARN: Header bytes checksum to %02lx\n", + $checksum); + } + # If we are an award rom... + if ($self{os_id} eq ' ') { + @self{qw(zero total_checksum)} = + unpack('CC', substr($$buf_ref, + $offset + $self{total_size}, 2)); + if ($self{zero} != 0) { + warn "Award ROM without trailing zero"; + } + else { + $self{total_size}++; + } + my $checksum = + checksum($buf_ref, $offset, $self{total_size}); + if ($self{total_checksum} != $checksum) { + printf("WARN: Image bytes checksum to %02lx\n", + $checksum); + } + else { + $self{total_size}++; + } + $self{rom_addr} = $self{dos_time}; + $self{rom_flags} = $self{dos_date}; + delete @self{qw(dos_time dos_date)}; + } + } + else { + die "Unknown header type"; + } + return \%self; +} + +sub main +{ + my ($filename, $rom_length) = @_; + my $fd = new FileHandle; + if (!defined($rom_length)) { + my ($dev, $ino, $mode, $nlink, $uid, $gid,$rdev,$size, + $atime, $mtime, $ctime, $blksize, $blocks) + = stat($filename); + $rom_length = $size; + } + $fd->open("<$filename") or die "Cannot ope $filename"; + my $data; + $fd->read($data, $rom_length); + $fd->close(); + + my $i; + for($i = 0; $i < $rom_length; $i++) { + my $sig = substr($data, $i, 5); + if (exists($lha_signatures{$sig})) { + my $start = $i -2; + my $header = decode_lha_header(\$data, $start); + + my $length = $header->{total_size}; + print "AT: $start - @{[$start + $length -1]}, $length bytes\n"; + print_struct(\@lha_header, $header); + print "\n"; + + } + } +} + +main(@ARGV); diff --git a/contrib/baremetal/Makefile b/contrib/baremetal/Makefile new file mode 100644 index 0000000..df4de76 --- /dev/null +++ b/contrib/baremetal/Makefile @@ -0,0 +1,475 @@ +# +# Makefile for Etherboot +# +# Most of the time you should edit Config +# +# Common options: +# VERSION=v - Set the version string +# +# NS8390 options: +# -DINCLUDE_NE - Include NE1000/NE2000 support +# -DNE_SCAN=list - Probe for NE base address using list of +# comma separated hex addresses +# -DINCLUDE_3C503 - Include 3c503 support +# -DT503_SHMEM - Use 3c503 shared memory mode (off by default) +# -DINCLUDE_WD - Include Western Digital/SMC support +# -DWD_DEFAULT_MEM- Default memory location for WD/SMC cards +# -DCOMPEX_RL2000_FIX +# +# If you have a Compex RL2000 PCI 32-bit (11F6:1401), +# and the bootrom hangs in "Probing...[NE*000/PCI]", +# try enabling this fix... it worked for me :). +# In the first packet write somehow it somehow doesn't +# get back the expected data so it is stuck in a loop. +# I didn't bother to investigate what or why because it works +# when I interrupt the loop if it takes more then COMPEX_RL2000_TRIES. +# The code will notify if it does a abort. +# SomniOne - somnione@gmx.net +# +# 3C509 option: +# -DINCLUDE_3C509 - Include 3c509 support +# +# 3C90X options: +# -DINCLUDE_3C90X - Include 3c90x support +# -DCFG_3C90X_PRESERVE_XCVR - Reset the transceiver type to the value it +# had initially just before the loaded code is started. +# -DCFG_3C90X_XCVR - Hardcode the tranceiver type Etherboot uses. +# -DCFG_3C90X_BOOTROM_FIX - If you have a 3c905B with buggy ROM +# interface, setting this option might "fix" it. Use +# with caution and read the docs in 3c90x.txt! +# +# See the documentation file 3c90x.txt for more details. +# +# CS89X0 (optional) options: +# -DINCLUDE_CS89X0- Include CS89x0 support +# -DCS_SCAN=list - Probe for CS89x0 base address using list of +# comma separated hex addresses; increasing the +# address by one (0x300 -> 0x301) will force a +# more aggressive probing algorithm. This might +# be neccessary after a soft-reset of the NIC. +# +# LANCE options: +# -DINCLUDE_NE2100- Include NE2100 support +# -DINCLUDE_NI6510- Include NI6510 support +# +# SK_G16 options: +# -DINCLUDE_SK_G16- Include SK_G16 support +# +# I82586 options: +# -DINCLUDE_3C507 - Include 3c507 support +# -DINCLUDE_NI5210- Include NI5210 support +# -DINCLUDE_EXOS205-Include EXOS205 support +# +# SMC9000 options: +# -DINCLUDE_SMC9000 - Include SMC9000 driver +# -DSMC9000_SCAN=list - List of I/O addresses to probe +# +# TIARA (Fujitsu Etherstar) options: +# -DINCLUDE_TIARA - Include Tiara support +# +# NI5010 options: +# -DINCLUDE_NI5010 - Include NI5010 support +# +# TULIP options: +# -DINCLUDE_TULIP - Include Tulip support +# -DUSE_INTERNAL_BUFFER - receuve and transmit buffers within program +# space, not below 0x10000, in case that region is used +# +# RTL8139 options: +# -DINCLUDE_RTL8139 - Include RTL8139 support +# -DUSE_INTERNAL_BUFFER - 8 kB receive buffer within program space, +# not at 0x10000 - 8kB, in case that region is used +# + +include Config + +GCC= gcc +CPP= gcc -E +VERSION= 4.6.12 +CFLAGS16+= -DVERSION=\"$(VERSION)\" -DRELOC=$(RELOCADDR) +CFLAGS32+= -DVERSION=\"$(VERSION)\" -DRELOC=$(RELOCADDR) $(OLDGAS) +LCONFIG+= -DRELOC=$(RELOCADDR) + +IDENT16= 'Etherboot/16 $(VERSION) (GPL) $(@F)' +IDENT32= 'Etherboot/32 $(VERSION) (GPL) $(@F)' + +# Find out if we're using binutils 2.9.1 which uses a different syntax in some +# places (most prominently in the opcode prefix area). +OLDGAS:= $(shell $(AS) --version | grep -q '2\.9\.1' && echo -DGAS291) + +# Check the requested type of build (32, 16 or both families) +ifeq ($(ETHERBOOT),16) +BUILD_LIBS= $(BLIB16) +BUILD_BINS= $(BINS16) +endif +ifeq ($(ETHERBOOT),32) +BUILD_LIBS= $(BLIB32) +BUILD_BINS= $(BINS32) +endif +ifeq ($(ETHERBOOT),both) +BUILD_LIBS= $(BLIB16) $(BLIB32) +BUILD_BINS= $(BINS16) $(BINS32) +endif + +3C503FLAGS= -DINCLUDE_3C503 # -DT503_SHMEM +# Note that the suffix to MAKEROM_ is the (mixed case) basename of the ROM file +MAKEROM_3c503= -3 +3C507FLAGS= -DINCLUDE_3C507 +3C509FLAGS= -DINCLUDE_3C509 +3C529FLAGS= -DINCLUDE_3C529 +3C595FLAGS= -DINCLUDE_3C595 +3C90XFLAGS= -DINCLUDE_3C90X +CS89X0FLAGS= -DINCLUDE_CS89X0 +EEPROFLAGS= -DINCLUDE_EEPRO +EEPRO100FLAGS= -DINCLUDE_EEPRO100 +EPIC100FLAGS= -DINCLUDE_EPIC100 +EXOS205FLAGS= -DINCLUDE_EXOS205 +LANCEFLAGS= -DINCLUDE_LANCE # Lance/PCI! +NE2100FLAGS= -DINCLUDE_NE2100 +NEFLAGS= -DINCLUDE_NE -DNE_SCAN=0x300,0x280,0x320,0x340,0x380 +NS8390FLAGS= -DINCLUDE_NS8390 # NE2000/PCI! +NI5010FLAGS= -DINCLUDE_NI5010 +NI5210FLAGS= -DINCLUDE_NI5210 +NI6510FLAGS= -DINCLUDE_NI6510 +RTL8139FLAGS= -DINCLUDE_RTL8139 +SK_G16FLAGS= -DINCLUDE_SK_G16 +SMC9000FLAGS= -DINCLUDE_SMC9000 +TIARAFLAGS= -DINCLUDE_TIARA +DEPCAFLAGS= -DINCLUDE_DEPCA # -DDEPCA_MODEL=DEPCA -DDEPCA_RAM_BASE=0xd0000 +TULIPFLAGS= -DINCLUDE_TULIP +OTULIPFLAGS= -DINCLUDE_OTULIP +VIA_RHINEFLAGS= -DINCLUDE_VIA_RHINE +WDFLAGS= -DINCLUDE_WD -DWD_DEFAULT_MEM=0xCC000 +W89C840FLAGS= -DINCLUDE_W89C840 + +# If you have not made any changes to the *.S files, AS86 need not be set. +# (most people) +# If you have made changes to the *.S files and you want to rebuild *loader.bin +# and {floppy,com}load.bin and you have as86 from the ELKS Dev86 package (not +# the one that normally comes with Linux) (not most people) +#AS86= as86 +# If you have made changes to the *.S files and you want to rebuild *loader.bin +# and {floppy,com}load.bin and you have nasm (not most people) +#AS86= nasm + +# if your as has trouble with the data32 directive, uncomment this +# but note that the premade start*.o will be larger than necessary because it +# contains some routines which may not be used +#AS_PSEUDOS= n + +SRCS= floppyload.S comload.S liloprefix.S loader.S start16.S start32.S serial.S startmpcc.S +SRCS+= main.c pci.c osloader.c nfs.c misc.c ansiesc.c bootmenu.c config.c +SRCS+= md5.c floppy.c + +# ROM loaders: LZ version (prefix Z), PCI header version (prefix P) +ifndef AS86 +RLOADER= rloader.bin.pre +PRLOADER= prloader.bin.pre +RZLOADER= rzloader.bin.pre +PRZLOADER= przloader.bin.pre +FLOPPYLOAD= floppyload.bin.pre +COMLOAD= comload.bin.pre +LILOPREFIX= liloprefix.bin.pre +else +RLOADER= bin/rloader.bin +PRLOADER= bin/prloader.bin +RZLOADER= bin/rzloader.bin +PRZLOADER= bin/przloader.bin +FLOPPYLOAD= bin/floppyload.bin +COMLOAD= bin/comload.bin +LILOPREFIX= bin/liloprefix.bin +endif + +ifeq ($(AS86),as86) +LCPPFLAGS+= -DUSE_AS86 +LASFLAGS+= $(AS86FLAGS) -0 +LASBINARY:= -b +endif +ifeq ($(AS86),nasm) +LCPPFLAGS+= -DUSE_NASM +LASFLAGS+= $(NASMFLAGS) -fbin +LASBINARY:= -o +endif + +ifeq ($(AS_PSEUDOS),n) +START16= start16.o.pre +START32= start32.o.pre +else +START16= bin16/start16.o +START32= bin32/startmpcc.o +endif + +BOBJS16= bin16/main.o bin16/osloader.o bin16/misc.o bin16/bootmenu.o +BOBJS16+= bin16/floppy.o bin16/timer.o +BOBJS32= bin32/main.o bin32/osloader.o bin32/nfs.o bin32/misc.o +BOBJS32+= bin32/ansiesc.o bin32/bootmenu.o bin32/md5.o bin32/floppy.o +BOBJS32+= bin32/serial.o bin32/timer.o +BLIB16= bin16/bootlib.a +BLIB32= bin32/bootlib.a +LIBS16= $(BLIB16) $(LIBC16) +LIBS32= $(BLIB32) $(LIBC32) /usr/lib/gcc-lib/i386-redhat-linux/2.96/libgcc.a +UTIL_LZHUF:= $(shell if [ -d ../contrib/compressor ]; then echo bin/lzhuf; fi) +UTILS+= bin/makerom $(UTIL_LZHUF) bin/organon +STDDEPS16= $(START16) $(BLIB16) $(UTILS) +STDDEPS32= $(START32) $(BLIB32) $(UTILS) +MAKEDEPS= Makefile Config Roms + +CHECKSIZE= { read d1; read d1 d2 d3 size d4; [ $$size -gt $(ROMLIMIT) ] &&\ + { $(RM) $@; echo "ERROR: code size exceeds limit!"; exit 1; }; exit 0; } + +# Make sure that the relocation address is acceptable for all ROM sizes. +# Setting it to 0x98000 leaves about 29kB of space for the Etherboot program. +# The check is done based running 'size' on the binary, not ROM size, but +# roughly this means a ROM of 16kB or a partially used ROM of 32kB, +# remembering to compressed ROM images into account. +# You may also set RELOCADDR to 0x88000 to avoid using 0x98000 +# because of other drivers (e.g. Disk On Chip). In that case, you may +# only load 512kB of OS, or load in memory above 1MB. +# Don't forget to choose an assembler because the loaders have to be rebuilt. +ifndef RELOCADDR +RELOCADDR=0x98000 +#RELOCADDR=0xe0000 +endif + +# Evaluate ROMLIMIT only once - it is constant during the make run. +# Note that the 3K safety margin below is for the 1K extended BIOS data area +# and for the Etherboot runtime stack. Under normal situations, 2K of stack +# are rarely needed. If you experience strange behaviour in functions that use +# many local variables or that call functions that do, check for stack overrun! +# Make sure that the normal case needs no perl interpreter - if someone uses a +# different RELOCADDR, then he has perl installed anyways (the shell cannot +# deal with hex numbers, as test/eval don't support non-decimal integers). +ifeq ($(RELOCADDR),0x98000) +ROMLIMIT=29696 +else +ROMLIMIT:=$(shell perl -e 'print 0x10000 - 3072 - ($(RELOCADDR) & 0xFFFF), "\n";') +endif + +# Start of targets + +all: $(UTILS) $(BUILD_LIBS) allbins + +include Roms + +# We need allbins because $(BINS16) and $(BINS32) are not defined until +# the Makefile fragment "Roms" is read. + +allbins: $(BUILD_BINS) + +# Common files + +$(BLIB16): $(BOBJS16) + $(AR16) rv $@ $(BOBJS16) + $(RANLIB16) $@ + +$(BLIB32): $(BOBJS32) + $(AR32) rv $@ $(BOBJS32) + $(RANLIB32) $@ + +bin16/main.o: main.c etherboot.h osdep.h nic.h +bin32/main.o: main.c etherboot.h osdep.h nic.h + +bin16/osloader.o: osloader.c etherboot.h osdep.h +bin32/osloader.o: osloader.c etherboot.h osdep.h + +# NFS currently makes no sense for Etherboot/16 +bin32/nfs.o: nfs.c etherboot.h osdep.h nic.h + +bin16/misc.o: misc.c etherboot.h osdep.h +bin32/misc.o: misc.c etherboot.h osdep.h + +# ANSIESC is not supported for Etherboot/16 +bin32/ansiesc.o: ansiesc.c etherboot.h osdep.h + +bin16/bootmenu.o: bootmenu.c etherboot.h osdep.h +bin32/bootmenu.o: bootmenu.c etherboot.h osdep.h + +# Password support is not available for Etherboot/16 +bin32/md5.o: md5.c etherboot.h osdep.h + +bin16/floppy.o: floppy.c etherboot.h osdep.h +bin32/floppy.o: floppy.c etherboot.h osdep.h + +bin16/timer.o: timer.c timer.h etherboot.h osdep.h +bin32/timer.o: timer.c timer.h etherboot.h osdep.h + +bin32/inthw.o: inthw.c + +# PCI support code (common to all PCI drivers) + +bin32/pci.o: pci.c pci.h + +# Do not add driver specific dependencies here unless it's something the +# genrules.pl script *can't* deal with, i.e. if it is not C code. + +# Prepended loaders + +#ifndef AS86 +#$(RLOADER) $(RZLOADER) $(PRLOADER) $(PRZLOADER): $(MAKEDEPS) +# @if [ $(RELOCADDR) != 0x98000 ]; then echo Non-standard RELOCADDR, must assemble $@; exit 1; fi +# $(TOUCH) $@ +#else +#bin/rloader.s: loader.S $(MAKEDEPS) +# $(CPP) $(LCPPFLAGS) $(LCONFIG) -o $@ $< +# +#bin/rzloader.s: loader.S $(MAKEDEPS) +# $(CPP) $(LCPPFLAGS) $(LCONFIG) -DZLOADER -o $@ $< +# +#bin/prloader.s: loader.S $(MAKEDEPS) +# $(CPP) $(LCPPFLAGS) $(LCONFIG) -DPCI_PNP_HEADER -o $@ $< +# +#bin/przloader.s: loader.S $(MAKEDEPS) +# $(CPP) $(LCPPFLAGS) $(LCONFIG) -DPCI_PNP_HEADER -DZLOADER -o $@ $< +#endif + +# Floppy loader + +ifdef AS86 +bin/floppyload.s: floppyload.S $(MAKEDEPS) + $(CPP) $(LCPPFLAGS) -o $@ $< +endif + +# COM loader + +ifdef AS86 +bin/comload.s: comload.S $(MAKEDEPS) + $(CPP) $(LCPPFLAGS) -o $@ $< +endif + +# LILO prefix: + +ifdef AS86 +bin/liloprefix.s: liloprefix.S $(MAKEDEPS) + $(CPP) $(LCPPFLAGS) -o $@ $< +endif + +# Utilities + +bin/makerom: makerom.c + $(GCC) -O2 -o $@ makerom.c + +bin/organon: organon.c + $(GCC) -o $@ organon.c + +bin/lzhuf: ../contrib/compressor/lzhuf.c + $(GCC) -O2 -DENCODE -DDECODE -DMAIN -DVERBOSE -o $@ $< + +# Roms file + +Roms: NIC genrules.pl + @chmod +x genrules.pl + ./genrules.pl NIC > $@ + +# Pattern Rules + +# general rules for compiling/assembling source files +bin16/%.o: %.c $(MAKEDEPS) + $(CC16) $(CFLAGS16) -o $@ -c $< + +bin32/%.o: %.c $(MAKEDEPS) + $(CC32) $(CFLAGS32) -o $@ -c $< + +bin16/%.o: %.S $(MAKEDEPS) + $(CC16) $(CFLAGS16) $(ASFLAGS16) -c -o $@ $< + +bin32/%.o: %.S $(MAKEDEPS) + $(CPP) $(CFLAGS32) $< | $(AS) $(ASFLAGS32) -o $@ + +# general rule for .bin (plain binary loader code), may be overridden +ifdef AS86 +bin/%.bin: bin/%.s + $(AS86) $(LASFLAGS) $(LASBINARY) $@ $< +endif + +# general rule for .huf (compressed binary code), may be overridden +%.huf: %.img + bin/lzhuf e $< $@ + +# general rules for normal/compressed ROM images, may be overridden +bin16/%.rom: bin16/%.img $(RLOADER) + cat $(RLOADER) $< > $@ + bin/makerom $(MAKEROM_$*) -i$(IDENT16) $@ + +bin32/%.rom: bin32/%.img $(RLOADER) + cat $(RLOADER) $< > $@ + bin/makerom $(MAKEROM_$*) -i$(IDENT32) $@ + +bin16/%.lzrom: bin16/%.huf $(RZLOADER) + cat $(RZLOADER) $< > $@ + bin/makerom $(MAKEROM_$*) -i$(IDENT16) $@ + +bin32/%.lzrom: bin32/%.huf $(RZLOADER) + cat $(RZLOADER) $< > $@ + bin/makerom $(MAKEROM_$*) -i$(IDENT32) $@ + +# rules to write the .rom/.lzrom image onto a blank floppy +# You must give the directory name, e.g. use bin32/rtl8139.lzfd0 as the target. +%.fd0: %.rom $(FLOPPYLOAD) + cat $(FLOPPYLOAD) $< > /dev/fd0 + +%.lzfd0: %.lzrom $(FLOPPYLOAD) + cat $(FLOPPYLOAD) $< > /dev/fd0 + +# rules to generate a .com executable +# You must give the directory name, e.g. use bin32/rtl8139.com as the target. +%.com: %.lzrom $(COMLOAD) + cat $(COMLOAD) $< > $@ + +# rules to make a floppy image (padding to fill an even number of cylinders). +# VMware reports floppy image read errors if it cannot read ahead 36 sectors, +# probably because the floppyload.S code reads up to that number of sectors in +# a single request. Not that 18k matters much these days... +# You must give the directory name, e.g. use bin32/rtl8139.fdimg as the target. +%.fdimg: %.rom $(FLOPPYLOAD) + cat $(FLOPPYLOAD) $< > $@.x + dd if=$@.x of=$@ bs=36k conv=sync 2> /dev/null + $(RM) $@.x + +%.lzfdimg: %.lzrom $(FLOPPYLOAD) + cat $(FLOPPYLOAD) $< > $@.x + dd if=$@.x of=$@ bs=36k conv=sync 2> /dev/null + $(RM) $@.x + +# rules to make a LILO-bootable image +%.lilo: %.rom $(LILOPREFIX) + cat $(LILOPREFIX) $< /dev/zero | head -c 64k > $@ + +%.lzlilo: %.lzrom $(LILOPREFIX) + cat $(LILOPREFIX) $< /dev/zero | head -c 64k > $@ + +# Housekeeping + +# To make sure that this actually builds a start32.o.pre with all options set, +# you have to make sure that -DFLOPPY -DANSIESC -DCONSOLE_DUAL are in CFLAGS32. +precompiled: bin/rloader.bin bin/rzloader.bin bin/prloader.bin bin/przloader.bin bin/floppyload.bin bin/comload.bin bin16/start16.o bin32/start32.o bin/liloprefix.bin + cp -p bin/rloader.bin rloader.bin.pre + cp -p bin/rzloader.bin rzloader.bin.pre + cp -p bin/prloader.bin prloader.bin.pre + cp -p bin/przloader.bin przloader.bin.pre + cp -p bin/floppyload.bin floppyload.bin.pre + cp -p bin/comload.bin comload.bin.pre + cp -p bin16/start16.o start16.o.pre + cp -p bin32/start32.o start32.o.pre + cp -p bin/liloprefix.bin liloprefix.bin.pre + +clean: + $(RM) $(UTILS) bin/*.s bin/*.bin + $(RM) $(BLIB16) $(BLIB32) + $(RM) bin16/*.o bin32/*.o bin16/*.tmp bin32/*.tmp + $(RM) bin16/*.img bin32/*.img bin16/*.huf bin32/*.huf + $(RM) bin16/*.rom bin32/*.rom bin16/*.lzrom bin32/*.lzrom + $(RM) bin16/*.com bin32/*.com + $(RM) bin16/*.fdimg bin32/*.fdimg bin16/*.lzfdimg bin32/*.lzfdimg + $(RM) bin16/*.lilo bin32/*.lilo bin16/*.lzlilo bin32/*.lzlilo + $(RM) bin32/*.hex + $(RM) bin32/*.asm + $(RM) bin32/*.map + +tarball: + (echo -n $(VERSION) ''; date -u +'%Y-%m-%d') > ../VERSION + (cd ..; tar cf /tmp/mpccboot-$(VERSION).tar --exclude CVS mpccboot) + bzip2 -9 < /tmp/mpccboot-$(VERSION).tar > /tmp/mpccboot-$(VERSION).tar.bz2 + gzip -9 < /tmp/mpccboot-$(VERSION).tar > /tmp/mpccboot-$(VERSION).tar.gz + +version: + @echo $(VERSION) diff --git a/contrib/baremetal/main.c b/contrib/baremetal/main.c new file mode 100644 index 0000000..7b0de44 --- /dev/null +++ b/contrib/baremetal/main.c @@ -0,0 +1,1119 @@ +/************************************************************************** +ETHERBOOT - BOOTP/TFTP Bootstrap Program + +Author: Martin Renters + Date: Dec/93 + +Literature dealing with the network protocols: + ARP - RFC826 + RARP - RFC903 + UDP - RFC768 + BOOTP - RFC951, RFC2132 (vendor extensions) + DHCP - RFC2131, RFC2132 (options) + TFTP - RFC1350, RFC2347 (options), RFC2348 (blocksize), RFC2349 (tsize) + RPC - RFC1831, RFC1832 (XDR), RFC1833 (rpcbind/portmapper) + NFS - RFC1094, RFC1813 (v3, useful for clarifications, not implemented) + +**************************************************************************/ + +/* #define MDEBUG */ + +#include "etherboot.h" +#include "nic.h" + +int jmp_bootmenu[10]; + +struct arptable_t arptable[MAX_ARP]; + +const char *kernel; +char kernel_buf[128]; +struct rom_info rom; + +#ifdef IMAGE_MENU +static char *imagelist[RFC1533_VENDOR_NUMOFIMG]; +static int useimagemenu; +int menutmo,menudefault; +unsigned char *defparams = NULL; +int defparams_max = 0; +#endif +#ifdef MOTD +char *motd[RFC1533_VENDOR_NUMOFMOTD]; +#endif +#ifdef IMAGE_FREEBSD +int freebsd_howto = 0; +#endif +int vendorext_isvalid; +char config_buffer[TFTP_MAX_PACKET+1]; /* +1 for null byte */ +unsigned long netmask; +char *hostname = ""; +int hostnamelen = 0; +#if defined(ETHERBOOT16) || defined(INTERNAL_BOOTP_DATA) +struct bootpd_t bootp_data; +#endif +unsigned long xid; +unsigned char *end_of_rfc1533 = NULL; +#ifndef NO_DHCP_SUPPORT +int dhcp_reply; +in_addr dhcp_server = { 0L }; +in_addr dhcp_addr = { 0L }; +#endif /* NO_DHCP_SUPPORT */ + +unsigned char vendorext_magic[] = {0xE4,0x45,0x74,0x68}; /* äEth */ +#ifdef NO_DHCP_SUPPORT +char rfc1533_cookie[5] = { RFC1533_COOKIE, RFC1533_END }; +#else +char rfc1533_cookie[] = { RFC1533_COOKIE}; +char rfc1533_end[]={RFC1533_END }; +static const char dhcpdiscover[]={ + RFC2132_MSG_TYPE,1,DHCPDISCOVER, + RFC2132_MAX_SIZE,2, /* request as much as we can */ + sizeof(struct bootpd_t) / 256, sizeof(struct bootpd_t) % 256, + RFC2132_PARAM_LIST,4,RFC1533_NETMASK,RFC1533_GATEWAY, + RFC1533_HOSTNAME + }; +static const char dhcprequest []={ + RFC2132_MSG_TYPE,1,DHCPREQUEST, + RFC2132_SRV_ID,4,0,0,0,0, + RFC2132_REQ_ADDR,4,0,0,0,0, + RFC2132_MAX_SIZE,2, /* request as much as we can */ + sizeof(struct bootpd_t) / 256, sizeof(struct bootpd_t) % 256, + /* request parameters */ + RFC2132_PARAM_LIST, +#ifdef IMAGE_FREEBSD + /* 4 standard + 6 vendortags + 8 motd + 16 menu items */ + 4 + 6 + 8 + 16, +#else + /* 4 standard + 5 vendortags + 8 motd + 16 menu items */ + 4 + 5 + 8 + 16, +#endif + /* Standard parameters */ + RFC1533_NETMASK, RFC1533_GATEWAY, + RFC1533_HOSTNAME, + RFC1533_ROOTPATH, /* only passed to the booted image */ + /* Etherboot vendortags */ + RFC1533_VENDOR_MAGIC, + RFC1533_VENDOR_ADDPARM, + RFC1533_VENDOR_ETHDEV, +#ifdef IMAGE_FREEBSD + RFC1533_VENDOR_HOWTO, +#endif + RFC1533_VENDOR_MNUOPTS, RFC1533_VENDOR_SELECTION, + /* 8 MOTD entries */ + RFC1533_VENDOR_MOTD, + RFC1533_VENDOR_MOTD+1, + RFC1533_VENDOR_MOTD+2, + RFC1533_VENDOR_MOTD+3, + RFC1533_VENDOR_MOTD+4, + RFC1533_VENDOR_MOTD+5, + RFC1533_VENDOR_MOTD+6, + RFC1533_VENDOR_MOTD+7, + /* 16 image entries */ + RFC1533_VENDOR_IMG, + RFC1533_VENDOR_IMG+1, + RFC1533_VENDOR_IMG+2, + RFC1533_VENDOR_IMG+3, + RFC1533_VENDOR_IMG+4, + RFC1533_VENDOR_IMG+5, + RFC1533_VENDOR_IMG+6, + RFC1533_VENDOR_IMG+7, + RFC1533_VENDOR_IMG+8, + RFC1533_VENDOR_IMG+9, + RFC1533_VENDOR_IMG+10, + RFC1533_VENDOR_IMG+11, + RFC1533_VENDOR_IMG+12, + RFC1533_VENDOR_IMG+13, + RFC1533_VENDOR_IMG+14, + RFC1533_VENDOR_IMG+15, + }; + +#endif /* NO_DHCP_SUPPORT */ +static const char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + +/************************************************************************** +MAIN - Kick off routine +**************************************************************************/ +int main(void) +{ + char *p; + static int card_retries = 0; + int i; + + for (p=_edata; p<_end; p++) + *p = 0; /* Zero BSS */ + +#ifdef CONSOLE_SERIAL + (void)serial_init(); +#endif + +#ifdef DELIMITERLINES + for (i=0; i<80; i++) putchar('='); +#endif + +#ifdef ETHERBOOT32 + rom = *(struct rom_info *)ROM_INFO_LOCATION; + printf("ROM segment %#x length %#x reloc %#x\n", rom.rom_segment, + rom.rom_length << 1, ((unsigned long)_start) >> 4); +#endif +#ifdef ETHERBOOT16 + fmemcpy(&rom, (Address)ROM_INFO_LOCATION, sizeof(rom)); + printf("ROM segment %#x length %#x\n", rom.rom_segment, + rom.rom_length << 1); +#endif +#ifdef ASK_BOOT + while (1) { + int c; + unsigned long time; + printf(ASK_PROMPT); +#if ASK_BOOT > 0 + for (time = currticks() + ASK_BOOT*TICKS_PER_SEC; !iskey(); ) + if (currticks() > time) { + c = ANS_DEFAULT; + goto done; + } +#endif + c = getchar(); + if ((c >= 'a') && (c <= 'z')) c &= 0x5F; + if (c == '\n') c = ANS_DEFAULT; +done: + if ((c >= ' ') && (c <= '~')) putchar(c); + putchar('\n'); + if (c == ANS_LOCAL) + exit(0); + if (c == ANS_NETWORK) + break; + } +#endif +#if (TRY_FLOPPY_FIRST > 0) && defined(FLOPPY) + disk_init(); + printf("Trying floppy"); + for (i = TRY_FLOPPY_FIRST; i-- > 0; ) { + putchar('.'); + if (disk_read(0, 0, 0, 0, ((char *) FLOPPY_BOOT_LOCATION)) != 0x8000) { + printf("using floppy\n"); + exit(0); + } + } + printf("no floppy\n"); +#endif /* TRY_FLOPPY_FIRST && FLOPPY */ + print_config(); + gateA20_set(); +#ifdef EMERGENCYDISKBOOT + if (!eth_probe()) { + printf("No adapter found\n"); + exit(0); + } +#else + while (!eth_probe()) { + printf("No adapter found"); + if (!setjmp(jmp_bootmenu)) + rfc951_sleep(++card_retries); + } +#endif + kernel = DEFAULT_BOOTFILE; + while (1) { + if ((i = setjmp(jmp_bootmenu)) != 0) { +#if defined(ANSIESC) && defined(CONSOLE_CRT) + ansi_reset(); +#endif + bootmenu(--i); + } else { + load(); + } +#if defined(ANSIESC) && defined(CONSOLE_CRT) + ansi_reset(); +#endif + } +} + +/************************************************************************** +LOADKERNEL - Try to load kernel image +**************************************************************************/ +#ifndef FLOPPY +#define loadkernel(s) download((s),downloadkernel) +#else +static int loadkernel(const char *fname) +{ + if (!memcmp(fname,"/dev/",5) && fname[6] == 'd') { + int dev, part = 0; + if (fname[5] == 'f') { + if ((dev = fname[7] - '0') < 0 || dev > 3) + goto nodisk; } + else if (fname[5] == 'h' || fname[5] == 's') { + if ((dev = 0x80 + fname[7] - 'a') < 0x80 || dev > 0x83) + goto nodisk; + if (fname[8]) { + part = fname[8] - '0'; + if (fname[9]) + part = 10*part + fname[9] - '0'; } + /* bootdisk cannot cope with more than eight partitions */ + if (part < 0 || part > 8) + goto nodisk; } + else + goto nodisk; + return(bootdisk(dev,part)); } +nodisk: + return download(fname, downloadkernel); +} +#endif + +/************************************************************************** +LOAD - Try to get booted +**************************************************************************/ +void load() +{ + static int bootp_completed = 0; + + /* Find a server to get BOOTP reply from */ + if (!bootp_completed || + !arptable[ARP_CLIENT].ipaddr.s_addr || !arptable[ARP_SERVER].ipaddr.s_addr) { +retry: + bootp_completed = 0; +#ifdef RARP_NOT_BOOTP + printf("Searching for server (RARP)...\n"); +#else +#ifndef NO_DHCP_SUPPORT + printf("Searching for server (DHCP)...\n"); +#else + printf("Searching for server (BOOTP)...\n"); +#endif +#endif + +#ifdef RARP_NOT_BOOTP + if (!rarp()) { +#else + if (!bootp()) { +#endif + printf("No Server found\n"); +#ifdef EMERGENCYDISKBOOT + exit(0); +#else + goto retry; +#endif + } + bootp_completed++; + } + printf("Me: %I, Server: %I", + arptable[ARP_CLIENT].ipaddr.s_addr, + arptable[ARP_SERVER].ipaddr.s_addr); + if (BOOTP_DATA_ADDR->bootp_reply.bp_giaddr.s_addr) + printf(", Relay: %I", + BOOTP_DATA_ADDR->bootp_reply.bp_giaddr.s_addr); + if (arptable[ARP_GATEWAY].ipaddr.s_addr) + printf(", Gateway %I", arptable[ARP_GATEWAY].ipaddr.s_addr); + putchar('\n'); + +#ifdef MDEBUG + printf("\n=>>"); getchar(); +#endif + +#ifdef MOTD + if (vendorext_isvalid) + show_motd(); +#endif + /* Now use TFTP to load file */ +#ifdef IMAGE_MENU + if (vendorext_isvalid && useimagemenu) { + selectImage(imagelist); + bootp_completed = 0; + } +#endif +#ifdef DOWNLOAD_PROTO_NFS + rpc_init(); +#endif + for (;;) { + printf("Loading %s ",kernel); + while (!loadkernel(kernel)) { + printf("Unable to load file.\n"); + sleep(2); /* lay off server for a while */ + } + } +} + +/************************************************************************** +DEFAULT_NETMASK - Return default netmask for IP address +**************************************************************************/ +static inline unsigned long default_netmask(void) +{ + int net = ntohl(arptable[ARP_CLIENT].ipaddr.s_addr) >> 24; + if (net <= 127) + return(htonl(0xff000000)); + else if (net < 192) + return(htonl(0xffff0000)); + else + return(htonl(0xffffff00)); +} + +/************************************************************************** +UDP_TRANSMIT - Send a UDP datagram +**************************************************************************/ +int udp_transmit(unsigned long destip, unsigned int srcsock, + unsigned int destsock, int len, const void *buf) +{ + struct iphdr *ip; + struct udphdr *udp; + struct arprequest arpreq; + int arpentry, i; + int retry; + + ip = (struct iphdr *)buf; + udp = (struct udphdr *)((long)buf + sizeof(struct iphdr)); + ip->verhdrlen = 0x45; + ip->service = 0; + ip->len = htons(len); + ip->ident = 0; + ip->frags = 0; + ip->ttl = 60; + ip->protocol = IP_UDP; + ip->chksum = 0; + ip->src.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr; + ip->dest.s_addr = destip; + ip->chksum = ipchksum((unsigned short *)buf, sizeof(struct iphdr)); + udp->src = htons(srcsock); + udp->dest = htons(destsock); + udp->len = htons(len - sizeof(struct iphdr)); + udp->chksum = 0; + if (destip == IP_BROADCAST) { + eth_transmit(broadcast, IP, len, buf); + } else { + if (((destip & netmask) != + (arptable[ARP_CLIENT].ipaddr.s_addr & netmask)) && + arptable[ARP_GATEWAY].ipaddr.s_addr) + destip = arptable[ARP_GATEWAY].ipaddr.s_addr; + for(arpentry = 0; arpentry<MAX_ARP; arpentry++) + if (arptable[arpentry].ipaddr.s_addr == destip) break; + if (arpentry == MAX_ARP) { + printf("%I is not in my arp table!\n", destip); + return(0); + } + for (i = 0; i<ETHER_ADDR_SIZE; i++) + if (arptable[arpentry].node[i]) break; + if (i == ETHER_ADDR_SIZE) { /* Need to do arp request */ + arpreq.hwtype = htons(1); + arpreq.protocol = htons(IP); + arpreq.hwlen = ETHER_ADDR_SIZE; + arpreq.protolen = 4; + arpreq.opcode = htons(ARP_REQUEST); + memcpy(arpreq.shwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE); + memcpy(arpreq.sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr)); + memset(arpreq.thwaddr, 0, ETHER_ADDR_SIZE); + memcpy(arpreq.tipaddr, &destip, sizeof(in_addr)); + for (retry = 1; retry <= MAX_ARP_RETRIES; retry++) { + eth_transmit(broadcast, ARP, sizeof(arpreq), + &arpreq); + if (await_reply(AWAIT_ARP, arpentry, + arpreq.tipaddr, TIMEOUT)) goto xmit; + rfc951_sleep(retry); + /* We have slept for a while - the packet may + * have arrived by now. If not, we have at + * least some room in the Rx buffer for the + * next reply. */ + if (await_reply(AWAIT_ARP, arpentry, + arpreq.tipaddr, 0)) goto xmit; + } + return(0); + } +xmit: + eth_transmit(arptable[arpentry].node, IP, len, buf); + } + return(1); +} + +/************************************************************************** +DOWNLOADKERNEL - Try to load file +**************************************************************************/ +int downloadkernel(data, block, len, eof) + unsigned char *data; + int block, len, eof; +{ +#ifdef SIZEINDICATOR + static int rlen = 0; + + if (!(block % 4) || eof) { + int size; + size = ((block-1) * rlen + len) / 1024; + + putchar('\b'); + putchar('\b'); + putchar('\b'); + putchar('\b'); + + putchar('0' + (size/1000)%10); + putchar('0' + (size/100)%10); + putchar('0' + (size/10)%10); + putchar('0' + (size/1)%10); + } +#endif + if (block == 1) + { +#ifdef SIZEINDICATOR + rlen=len; +#endif + if (!eof && ( +#ifdef TAGGED_IMAGE + *((unsigned long *)data) == 0x1B031336L || +#endif +#ifdef ELF_IMAGE + *((unsigned long *)data) == 0x464C457FL || +#endif +#ifdef AOUT_IMAGE + *((unsigned short *)data) == 0x010BL || +#endif + ((unsigned short *)data)[255] == 0xAA55)) + { + ; + } + else if (eof) + { + memcpy(config_buffer, data, len); + config_buffer[len] = 0; + return (1); /* done */ + } + else + { + printf("error: not a tagged image\n"); + return(0); /* error */ + } + } + if (len != 0) { + if (!os_download(block, data, len)) + return(0); /* error */ + } + if (eof) { + os_download(block+1, data, 0); /* does not return */ + return(0); /* error */ + } + return(-1); /* there is more data */ +} + +#ifdef DOWNLOAD_PROTO_TFTP +/************************************************************************** +TFTP - Download extended BOOTP data, or kernel image +**************************************************************************/ +int tftp(const char *name, int (*fnc)(unsigned char *, int, int, int)) +{ + int retry = 0; + static unsigned short iport = 2000; + unsigned short oport; + unsigned short len, block = 0, prevblock = 0; + int bcounter = 0; + struct tftp_t *tr; + struct tftp_t tp; + int rc; + int packetsize = TFTP_DEFAULTSIZE_PACKET; + + /* Clear out the Rx queue first. It contains nothing of interest, + * except possibly ARP requests from the DHCP/TFTP server. We use + * polling throughout Etherboot, so some time may have passed since we + * last polled the receive queue, which may now be filled with + * broadcast packets. This will cause the reply to the packets we are + * about to send to be lost immediately. Not very clever. */ + await_reply(AWAIT_QDRAIN, 0, NULL, 0); + + tp.opcode = htons(TFTP_RRQ); + len = (sprintf((char *)tp.u.rrq, "%s%coctet%cblksize%c%d", + name, 0, 0, 0, TFTP_MAX_PACKET) - ((char *)&tp)) + 1; + if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, ++iport, + TFTP_PORT, len, &tp)) + return (0); + for (;;) + { +#ifdef CONGESTED + if (!await_reply(AWAIT_TFTP, iport, NULL, (block ? TFTP_REXMT : TIMEOUT))) +#else + if (!await_reply(AWAIT_TFTP, iport, NULL, TIMEOUT)) +#endif + { + if (!block && retry++ < MAX_TFTP_RETRIES) + { /* maybe initial request was lost */ + rfc951_sleep(retry); + if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, + ++iport, TFTP_PORT, len, &tp)) + return (0); + continue; + } +#ifdef CONGESTED + if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT)) + { /* we resend our last ack */ +#ifdef MDEBUG + printf("<REXMT>\n"); +#endif + udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, + iport, oport, + TFTP_MIN_PACKET, &tp); + continue; + } +#endif + break; /* timeout */ + } + tr = (struct tftp_t *)&nic.packet[ETHER_HDR_SIZE]; + if (tr->opcode == ntohs(TFTP_ERROR)) + { + printf("TFTP error %d (%s)\n", + ntohs(tr->u.err.errcode), + tr->u.err.errmsg); + break; + } + + if (tr->opcode == ntohs(TFTP_OACK)) { + char *p = tr->u.oack.data, *e; + + if (prevblock) /* shouldn't happen */ + continue; /* ignore it */ + len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 2; + if (len > TFTP_MAX_PACKET) + goto noak; + e = p + len; + while (*p != '\000' && p < e) { + if (!strcasecmp("blksize", p)) { + p += 8; + if ((packetsize = getdec(&p)) < + TFTP_DEFAULTSIZE_PACKET) + goto noak; + while (p < e && *p) p++; + if (p < e) + p++; + } + else { + noak: + tp.opcode = htons(TFTP_ERROR); + tp.u.err.errcode = 8; + len = (sprintf((char *)tp.u.err.errmsg, + "RFC1782 error") + - ((char *)&tp)) + 1; + udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, + iport, ntohs(tr->udp.src), + len, &tp); + return (0); + } + } + if (p > e) + goto noak; + block = tp.u.ack.block = 0; /* this ensures, that */ + /* the packet does not get */ + /* processed as data! */ + } + else if (tr->opcode == ntohs(TFTP_DATA)) { + len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 4; + if (len > packetsize) /* shouldn't happen */ + continue; /* ignore it */ + block = ntohs(tp.u.ack.block = tr->u.data.block); } + else /* neither TFTP_OACK nor TFTP_DATA */ + break; + + if ((block || bcounter) && (block != prevblock+1)) { + /* Block order should be continuous */ + tp.u.ack.block = htons(block = prevblock); + } + tp.opcode = htons(TFTP_ACK); + oport = ntohs(tr->udp.src); + udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, iport, + oport, TFTP_MIN_PACKET, &tp); /* ack */ + if ((unsigned short)(block-prevblock) != 1) { + /* Retransmission or OACK, don't process via callback + * and don't change the value of prevblock. */ + continue; + } + prevblock = block; + retry = 0; /* It's the right place to zero the timer? */ + if ((rc = fnc(tr->u.data.download, + ++bcounter, len, len < packetsize)) >= 0) + return(rc); + if (len < packetsize) /* End of data */ + return (1); + } + return (0); +} +#endif /* DOWNLOAD_PROTO_TFTP */ + +#ifdef RARP_NOT_BOOTP +/************************************************************************** +RARP - Get my IP address and load information +**************************************************************************/ +int rarp() +{ + int retry; + + /* arp and rarp requests share the same packet structure. */ + struct arprequest rarpreq; + + memset(&rarpreq, 0, sizeof(rarpreq)); + + rarpreq.hwtype = htons(1); + rarpreq.protocol = htons(IP); + rarpreq.hwlen = ETHER_ADDR_SIZE; + rarpreq.protolen = 4; + rarpreq.opcode = htons(RARP_REQUEST); + memcpy(&rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE); + /* sipaddr is already zeroed out */ + memcpy(&rarpreq.thwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE); + /* tipaddr is already zeroed out */ + + for (retry = 0; retry < MAX_ARP_RETRIES; rfc951_sleep(++retry)) { + eth_transmit(broadcast, RARP, sizeof(rarpreq), &rarpreq); + + if (await_reply(AWAIT_RARP, 0, rarpreq.shwaddr, TIMEOUT)) + break; + } + + if (retry < MAX_ARP_RETRIES) { + sprintf(kernel = kernel_buf, "/tftpboot/kernel.%I", arptable[ARP_CLIENT].ipaddr); + + return (1); + } + return (0); +} + +#else + +/************************************************************************** +BOOTP - Get my IP address and load information +**************************************************************************/ +int bootp() +{ + int retry; +#ifndef NO_DHCP_SUPPORT + int retry1; +#endif /* NO_DHCP_SUPPORT */ + struct bootp_t bp; + unsigned long starttime; +#ifdef T509HACK + int flag; + + flag = 1; +#endif + memset(&bp, 0, sizeof(struct bootp_t)); + bp.bp_op = BOOTP_REQUEST; + bp.bp_htype = 1; + bp.bp_hlen = ETHER_ADDR_SIZE; + bp.bp_xid = xid = starttime = currticks(); + memcpy(bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE); +#ifdef NO_DHCP_SUPPORT + memcpy(bp.bp_vend, rfc1533_cookie, 5); /* request RFC-style options */ +#else + memcpy(bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); /* request RFC-style options */ + memcpy(bp.bp_vend+sizeof rfc1533_cookie, dhcpdiscover, sizeof dhcpdiscover); + memcpy(bp.bp_vend+sizeof rfc1533_cookie +sizeof dhcpdiscover, rfc1533_end, sizeof rfc1533_end); +#endif /* NO_DHCP_SUPPORT */ + + for (retry = 0; retry < MAX_BOOTP_RETRIES; ) { + + /* Clear out the Rx queue first. It contains nothing of + * interest, except possibly ARP requests from the DHCP/TFTP + * server. We use polling throughout Etherboot, so some time + * may have passed since we last polled the receive queue, + * which may now be filled with broadcast packets. This will + * cause the reply to the packets we are about to send to be + * lost immediately. Not very clever. */ + await_reply(AWAIT_QDRAIN, 0, NULL, 0); + + udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER, + sizeof(struct bootp_t), &bp); +#ifdef T509HACK + if (flag) { + flag--; + } else { + if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT)) + return(1); + rfc951_sleep(++retry); + + } +#else +#ifdef NO_DHCP_SUPPORT + if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT)) +#else + if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT)){ + if (dhcp_reply==DHCPOFFER){ + dhcp_reply=0; + memcpy(bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); + memcpy(bp.bp_vend+sizeof rfc1533_cookie, dhcprequest, sizeof dhcprequest); + memcpy(bp.bp_vend+sizeof rfc1533_cookie +sizeof dhcprequest, rfc1533_end, sizeof rfc1533_end); + memcpy(bp.bp_vend+9, &dhcp_server, sizeof(in_addr)); + memcpy(bp.bp_vend+15, &dhcp_addr, sizeof(in_addr)); + for (retry1 = 0; retry1 < MAX_BOOTP_RETRIES;) { + udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER, + sizeof(struct bootp_t), &bp); + dhcp_reply=0; + if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT)) + if (dhcp_reply==DHCPACK) + return(1); + rfc951_sleep(++retry1); + } + } else +#endif /* NO_DHCP_SUPPORT */ + return(1); +#ifndef NO_DHCP_SUPPORT + } + rfc951_sleep(++retry); + +#endif /* NO_DHCP_SUPPORT */ +#endif + bp.bp_secs = htons((currticks()-starttime)/20); + } + return(0); +} +#endif /* RARP_NOT_BOOTP */ + +/************************************************************************** +AWAIT_REPLY - Wait until we get a response for our request +**************************************************************************/ +int await_reply(int type, int ival, void *ptr, int timeout) +{ + unsigned long time; + struct iphdr *ip; + struct udphdr *udp; + struct arprequest *arpreply; + struct bootp_t *bootpreply; + struct rpc_t *rpc; + unsigned short ptype; + + unsigned int protohdrlen = ETHER_HDR_SIZE + sizeof(struct iphdr) + + sizeof(struct udphdr); + time = timeout + currticks(); + /* The timeout check is done below. The timeout is only checked if + * there is no packet in the Rx queue. This assumes that eth_poll() + * needs a negligible amount of time. */ + for (;;) { + if (eth_poll()) { /* We have something! */ + /* Check for ARP - No IP hdr */ + if (nic.packetlen >= ETHER_HDR_SIZE) { + ptype = ((unsigned short) nic.packet[12]) << 8 + | ((unsigned short) nic.packet[13]); + } else continue; /* what else could we do with it? */ + if ((nic.packetlen >= ETHER_HDR_SIZE + + sizeof(struct arprequest)) && + (ptype == ARP) ) { + unsigned long tmp; + + arpreply = (struct arprequest *) + &nic.packet[ETHER_HDR_SIZE]; + if ((arpreply->opcode == ntohs(ARP_REPLY)) && + !memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) && + (type == AWAIT_ARP)) { + memcpy(arptable[ival].node, arpreply->shwaddr, ETHER_ADDR_SIZE); + return(1); + } + memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr)); + if ((arpreply->opcode == ntohs(ARP_REQUEST)) && + (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) { + arpreply->opcode = htons(ARP_REPLY); + memcpy(arpreply->tipaddr, arpreply->sipaddr, sizeof(in_addr)); + memcpy(arpreply->thwaddr, arpreply->shwaddr, ETHER_ADDR_SIZE); + memcpy(arpreply->sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr)); + memcpy(arpreply->shwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE); + eth_transmit(arpreply->thwaddr, ARP, + sizeof(struct arprequest), + arpreply); +#ifdef MDEBUG + memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr)); + printf("Sent ARP reply to: %I\n",tmp); +#endif MDEBUG + } + continue; + } + + if (type == AWAIT_QDRAIN) { + continue; + } + + /* Check for RARP - No IP hdr */ + if ((type == AWAIT_RARP) && + (nic.packetlen >= ETHER_HDR_SIZE + + sizeof(struct arprequest)) && + (ptype == RARP)) { + arpreply = (struct arprequest *) + &nic.packet[ETHER_HDR_SIZE]; + if ((arpreply->opcode == ntohs(RARP_REPLY)) && + !memcmp(arpreply->thwaddr, ptr, ETHER_ADDR_SIZE)) { + memcpy(arptable[ARP_SERVER].node, arpreply->shwaddr, ETHER_ADDR_SIZE); + memcpy(& arptable[ARP_SERVER].ipaddr, arpreply->sipaddr, sizeof(in_addr)); + memcpy(& arptable[ARP_CLIENT].ipaddr, arpreply->tipaddr, sizeof(in_addr)); + return(1); + } + continue; + } + + /* Anything else has IP header */ + if ((nic.packetlen < protohdrlen) || + (ptype != IP) ) continue; + ip = (struct iphdr *)&nic.packet[ETHER_HDR_SIZE]; + if ((ip->verhdrlen != 0x45) || + ipchksum((unsigned short *)ip, sizeof(struct iphdr)) || + (ip->protocol != IP_UDP)) continue; + udp = (struct udphdr *)&nic.packet[ETHER_HDR_SIZE + + sizeof(struct iphdr)]; + + /* BOOTP ? */ + bootpreply = (struct bootp_t *)&nic.packet[ETHER_HDR_SIZE]; + if ((type == AWAIT_BOOTP) && + (nic.packetlen >= (ETHER_HDR_SIZE + +#ifdef NO_DHCP_SUPPORT + sizeof(struct bootp_t))) && +#else + sizeof(struct bootp_t))-DHCP_OPT_LEN) && +#endif /* NO_DHCP_SUPPORT */ + (ntohs(udp->dest) == BOOTP_CLIENT) && + (bootpreply->bp_op == BOOTP_REPLY) && + (bootpreply->bp_xid == xid)) { + arptable[ARP_CLIENT].ipaddr.s_addr = + bootpreply->bp_yiaddr.s_addr; +#ifndef NO_DHCP_SUPPORT + dhcp_addr.s_addr = bootpreply->bp_yiaddr.s_addr; +#endif /* NO_DHCP_SUPPORT */ + netmask = default_netmask(); + arptable[ARP_SERVER].ipaddr.s_addr = + bootpreply->bp_siaddr.s_addr; + memset(arptable[ARP_SERVER].node, 0, ETHER_ADDR_SIZE); /* Kill arp */ + arptable[ARP_GATEWAY].ipaddr.s_addr = + bootpreply->bp_giaddr.s_addr; + memset(arptable[ARP_GATEWAY].node, 0, ETHER_ADDR_SIZE); /* Kill arp */ + if (bootpreply->bp_file[0]) { + memcpy(kernel_buf, bootpreply->bp_file, 128); + kernel = kernel_buf; + } + memcpy((char *)BOOTP_DATA_ADDR, (char *)bootpreply, sizeof(struct bootpd_t)); + decode_rfc1533(BOOTP_DATA_ADDR->bootp_reply.bp_vend, +#ifdef NO_DHCP_SUPPORT + 0, BOOTP_VENDOR_LEN + MAX_BOOTP_EXTLEN, 1); +#else + 0, DHCP_OPT_LEN + MAX_BOOTP_EXTLEN, 1); +#endif /* NO_DHCP_SUPPORT */ + return(1); + } + +#ifdef DOWNLOAD_PROTO_TFTP + /* TFTP ? */ + if ((type == AWAIT_TFTP) && + (ntohs(udp->dest) == ival)) return(1); +#endif /* DOWNLOAD_PROTO_TFTP */ + +#ifdef DOWNLOAD_PROTO_NFS + /* RPC ? */ + rpc = (struct rpc_t *)&nic.packet[ETHER_HDR_SIZE]; + if ((type == AWAIT_RPC) && + (ntohs(udp->dest) == ival) && + (*(unsigned long *)ptr == ntohl(rpc->u.reply.id)) && + (ntohl(rpc->u.reply.type) == MSG_REPLY)) { + return (1); + } +#endif /* DOWNLOAD_PROTO_NFS */ + + } else { + /* Check for abort key only if the Rx queue is empty - + * as long as we have something to process, don't + * assume that something failed. It is unlikely that + * we have no processing time left between packets. */ + if (iskey() && (getchar() == ESC)) +#ifdef EMERGENCYDISKBOOT + exit(0); +#else + longjmp(jmp_bootmenu,1); +#endif + /* Do the timeout after at least a full queue walk. */ + if ((timeout == 0) || (currticks() > time)) { + break; + } + } + } + return(0); +} + +/************************************************************************** +DECODE_RFC1533 - Decodes RFC1533 header +**************************************************************************/ +int decode_rfc1533(p, block, len, eof) + register unsigned char *p; + int block, len, eof; +{ + static unsigned char *extdata = NULL, *extend = NULL; + unsigned char *extpath = NULL; + unsigned char *endp; + + if (block == 0) { +#ifdef IMAGE_MENU + memset(imagelist, 0, sizeof(imagelist)); + menudefault = useimagemenu = 0; + menutmo = -1; +#endif +#ifdef MOTD + memset(motd, 0, sizeof(motd)); +#endif + end_of_rfc1533 = NULL; + vendorext_isvalid = 0; + if (memcmp(p, rfc1533_cookie, 4)) + return(0); /* no RFC 1533 header found */ + p += 4; + endp = p + len; } + else { + if (block == 1) { + if (memcmp(p, rfc1533_cookie, 4)) + return(0); /* no RFC 1533 header found */ + p += 4; + len -= 4; } + if (extend + len <= (unsigned char *)&(BOOTP_DATA_ADDR->bootp_extension[MAX_BOOTP_EXTLEN])) { + memcpy(extend, p, len); + extend += len; + } else { + printf("Overflow in vendor data buffer! Aborting...\n"); + *extdata = RFC1533_END; + return(0); + } + p = extdata; endp = extend; + } + if (eof) { + while(p < endp) { + unsigned char c = *p; + if (c == RFC1533_PAD) {p++; continue;} + else if (c == RFC1533_END) { + end_of_rfc1533 = endp = p; continue; } + else if (c == RFC1533_NETMASK) {memcpy(&netmask, p+2, sizeof(in_addr));} + + else if (c == RFC1533_GATEWAY) { + /* This is a little simplistic, but it will + usually be sufficient. + Take only the first entry */ + if (TAG_LEN(p) >= sizeof(in_addr)) + memcpy(&arptable[ARP_GATEWAY].ipaddr, p+2, sizeof(in_addr)); + } + else if (c == RFC1533_EXTENSIONPATH) + extpath = p; +#ifndef NO_DHCP_SUPPORT + else if (c == RFC2132_MSG_TYPE) + { dhcp_reply=*(p+2); + } + else if (c == RFC2132_SRV_ID) + { + memcpy(&dhcp_server, p+2, sizeof(in_addr)); + } +#endif /* NO_DHCP_SUPPORT */ + else if (c == RFC1533_HOSTNAME) + { + hostname = p + 2; + hostnamelen = *(p + 1); + } + else if (c == RFC1533_VENDOR_MAGIC +#ifndef IMAGE_FREEBSD /* since FreeBSD uses tag 128 for swap definition */ + && TAG_LEN(p) >= 6 && + !memcmp(p+2,vendorext_magic,4) && + p[6] == RFC1533_VENDOR_MAJOR +#endif + ) + vendorext_isvalid++; +#ifdef IMAGE_FREEBSD + else if (c == RFC1533_VENDOR_HOWTO) { + freebsd_howto = ((p[2]*256+p[3])*256+p[4])*256+p[5]; + } +#endif +#ifdef IMAGE_MENU + else if (c == RFC1533_VENDOR_MNUOPTS) { + parse_menuopts(p+2, TAG_LEN(p)); + } + else if (c >= RFC1533_VENDOR_IMG && + c<RFC1533_VENDOR_IMG+RFC1533_VENDOR_NUMOFIMG){ + imagelist[c - RFC1533_VENDOR_IMG] = p; + useimagemenu++; + } +#endif +#ifdef MOTD + else if (c >= RFC1533_VENDOR_MOTD && + c < RFC1533_VENDOR_MOTD + + RFC1533_VENDOR_NUMOFMOTD) + motd[c - RFC1533_VENDOR_MOTD] = p; +#endif + else { +#if 0 + unsigned char *q; + printf("Unknown RFC1533-tag "); + for(q=p;q<p+2+TAG_LEN(p);q++) + printf("%x ",*q); + putchar('\n'); +#endif + } + p += TAG_LEN(p) + 2; + } + extdata = extend = endp; + if (block == 0 && extpath != NULL) { + char fname[64]; + memcpy(fname, extpath+2, TAG_LEN(extpath)); + fname[(int)TAG_LEN(extpath)] = '\000'; + printf("Loading BOOTP-extension file: %s\n",fname); + download(fname,decode_rfc1533); + } + } + return(-1); /* proceed with next block */ +} + +/************************************************************************** +IPCHKSUM - Checksum IP Header +**************************************************************************/ +unsigned short ipchksum(ip, len) + register unsigned short *ip; + register int len; +{ + unsigned long sum = 0; + len >>= 1; + while (len--) { + sum += *(ip++); + if (sum > 0xFFFF) + sum -= 0xFFFF; + } + return((~sum) & 0x0000FFFF); +} + +/************************************************************************** +RFC951_SLEEP - sleep for expotentially longer times +**************************************************************************/ +void rfc951_sleep(exp) + int exp; +{ + static long seed = 0; + long q; + unsigned long tmo; + +#ifdef BACKOFF_LIMIT + if (exp > BACKOFF_LIMIT) + exp = BACKOFF_LIMIT; +#endif + if (!seed) /* Initialize linear congruential generator */ + seed = currticks() + *(long *)&arptable[ARP_CLIENT].node + + ((short *)arptable[ARP_CLIENT].node)[2]; + /* simplified version of the LCG given in Bruce Scheier's + "Applied Cryptography" */ + q = seed/53668; + if ((seed = 40014*(seed-53668*q) - 12211*q) < 0) seed += 2147483563l; + /* compute mask */ + for (tmo = 63; tmo <= 60*TICKS_PER_SEC && --exp > 0; tmo = 2*tmo+1); + /* sleep */ + printf("<sleep>\n"); + + for (tmo = (tmo&seed)+currticks(); currticks() < tmo; ) + if (iskey() && (getchar() == ESC)) longjmp(jmp_bootmenu,1); + return; +} + +/************************************************************************** +CLEANUP_NET - shut down networking +**************************************************************************/ +void cleanup_net(void) +{ +#ifdef DOWNLOAD_PROTO_NFS + nfs_umountall(ARP_SERVER); +#endif + eth_disable(); + eth_reset(); +} + +/************************************************************************** +CLEANUP - shut down etherboot so that the OS may be called right away +**************************************************************************/ +void cleanup(void) +{ +#if defined(ANSIESC) && defined(CONSOLE_CRT) + ansi_reset(); +#endif +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/contrib/baremetal/marini.txt b/contrib/baremetal/marini.txt new file mode 100644 index 0000000..464f148 --- /dev/null +++ b/contrib/baremetal/marini.txt @@ -0,0 +1,52 @@ +From: "Paolo Marini" <paolom@prisma-eng.it> +Subject: Etherboot on bare metal +Date: Tue, 10 Apr 2001 23:19:19 +0200 +Organization: Prisma Engineering srl + +Hi Ken, +I have ported Etherboot on an embedded, biosless platform and would like +to contribute the code. + +Essentially, the hardware I was running Etherboot is a Pentium based +embedded system, with an Intel Chipset, *but* without serial, VGA, +keyboard etc., only an 82559 Intel (custom) Ethernet controller (I debug +it with the etheral Ethernet packet analyser and an emulator). + +What I did was: + + a.. integrate the init.s file within the firmware, with GDT +(re)initialisation (a simple and single entry point taking control of +the boot process) + b.. provide some stupid BIOS stubs in order to let the OS boot and +still belive that an INT10 call goes to the BIOS + c.. provide some basic functions to Etherboot, like timer (I used the +Pentium TSC internal counter) + d.. hardwire in the code information about the RAM size +The BIOS stubs are enough to boot Linux, pSOS and QNX with bootp. QNX is +somewhat difficult to load, because the i82559 driver tries to find the +component using the BIOS32 calls, so I had to patch it. + +what i I got from the original firmware is the PCI initialisation and +resource (I/O, interrupts, memory) allocation. + +I send you what I changed, that is, the initialisation code and the +misc.c file containing the timer, and the makefile (I don't remember +exactly the options I used to compile all). + +Of course, it is only a good starting point for anyone wanting to +implement a bootp client on a biosless platform; some integration work +still needs to be done. + +Ciao +Paolo + +And in a subsequent email: + +I worked with version 4.6.12, but the real modifications involve the +init.S file, which I think is quite sstable between releases. I forgot +to say that my entry point (symbol _start in init.s) assumes the +processor is already in protected mode. + +[The only difference between main.c and misc.c from those in Etherboot +4.6.12 seems to be the deletion of eth_reset(). This may be of use to +others trying to make these changes work on more recent releases. Ken] diff --git a/contrib/baremetal/misc.c b/contrib/baremetal/misc.c new file mode 100644 index 0000000..924ccd6 --- /dev/null +++ b/contrib/baremetal/misc.c @@ -0,0 +1,351 @@ +/************************************************************************** +MISC Support Routines +**************************************************************************/ + +#include "etherboot.h" + +/************************************************************************** +SLEEP +**************************************************************************/ +void sleep(int secs) +{ + unsigned long tmo; + + for (tmo = currticks()+secs*TICKS_PER_SEC; currticks() < tmo; ) + /* Nothing */; +} + +/************************************************************************** +TWIDDLE +**************************************************************************/ +void twiddle() +{ + static unsigned long lastticks = 0; + static int count=0; + static const char tiddles[]="-\\|/"; + unsigned long ticks; + if ((ticks = currticks()) == lastticks) + return; + lastticks = ticks; + putchar(tiddles[(count++)&3]); + putchar('\b'); +} + +/************************************************************************** +STRCASECMP (not entirely correct, but this will do for our purposes) +**************************************************************************/ +int strcasecmp(a,b) + char *a, *b; +{ + while (*a && *b && (*a & ~0x20) == (*b & ~0x20)) {a++; b++; } + return((*a & ~0x20) - (*b & ~0x20)); +} + +/************************************************************************** +PRINTF and friends + + Formats: + %[#]X - 4 bytes long (8 hex digits) + %[#]x - 2 bytes int (4 hex digits) + - optional # prefixes 0x + %b - 1 byte int (2 hex digits) + %d - decimal int + %c - char + %s - string + %I - Internet address in x.x.x.x notation + Note: width specification not supported +**************************************************************************/ +static char *do_printf(char *buf, const char *fmt, const int *dp) +{ + register char *p; + int alt; + char tmp[16]; + static const char hex[]="0123456789ABCDEF"; + + while (*fmt) { + if (*fmt == '%') { /* switch() uses more space */ + alt = 0; + fmt++; + if (*fmt == '#') { + alt = 1; + fmt++; + } + if (*fmt == 'X') { + const long *lp = (const long *)dp; + register long h = *lp++; + dp = (const int *)lp; + if (alt) { + *buf++ = '0'; + *buf++ = 'x'; + } + *(buf++) = hex[(h>>28)& 0x0F]; + *(buf++) = hex[(h>>24)& 0x0F]; + *(buf++) = hex[(h>>20)& 0x0F]; + *(buf++) = hex[(h>>16)& 0x0F]; + *(buf++) = hex[(h>>12)& 0x0F]; + *(buf++) = hex[(h>>8)& 0x0F]; + *(buf++) = hex[(h>>4)& 0x0F]; + *(buf++) = hex[h& 0x0F]; + } + if (*fmt == 'x') { + register int h = *(dp++); + if (alt) { + *buf++ = '0'; + *buf++ = 'x'; + } + *(buf++) = hex[(h>>12)& 0x0F]; + *(buf++) = hex[(h>>8)& 0x0F]; + *(buf++) = hex[(h>>4)& 0x0F]; + *(buf++) = hex[h& 0x0F]; + } + if (*fmt == 'b') { + register int h = *(dp++); + *(buf++) = hex[(h>>4)& 0x0F]; + *(buf++) = hex[h& 0x0F]; + } + if (*fmt == 'd') { + register int dec = *(dp++); + p = tmp; + if (dec < 0) { + *(buf++) = '-'; + dec = -dec; + } + do { + *(p++) = '0' + (dec%10); + dec = dec/10; + } while(dec); + while ((--p) >= tmp) *(buf++) = *p; + } + if (*fmt == 'I') { + union { + long l; + unsigned char c[4]; + } u; + const long *lp = (const long *)dp; + u.l = *lp++; + dp = (const int *)lp; + buf = sprintf(buf,"%d.%d.%d.%d", + u.c[0], u.c[1], u.c[2], u.c[3]); + } + if (*fmt == 'c') + *(buf++) = *(dp++); + if (*fmt == 's') { + p = (char *)*dp++; + while (*p) *(buf++) = *p++; + } + } else *(buf++) = *fmt; + fmt++; + } + *buf = '\0'; + return(buf); +} + +char *sprintf(char *buf, const char *fmt, ...) +{ + return do_printf(buf, fmt, ((const int *)&fmt)+1); +} + +void printf(const char *fmt, ...) +{ + char buf[120], *p; + + p = buf; + do_printf(buf, fmt, ((const int *)&fmt)+1); + while (*p) putchar(*p++); +} + +#ifdef IMAGE_MENU +/************************************************************************** +INET_ATON - Convert an ascii x.x.x.x to binary form +**************************************************************************/ +int inet_aton(char *p, in_addr *i) +{ + unsigned long ip = 0; + int val; + if (((val = getdec(&p)) < 0) || (val > 255)) return(0); + if (*p != '.') return(0); + p++; + ip = val; + if (((val = getdec(&p)) < 0) || (val > 255)) return(0); + if (*p != '.') return(0); + p++; + ip = (ip << 8) | val; + if (((val = getdec(&p)) < 0) || (val > 255)) return(0); + if (*p != '.') return(0); + p++; + ip = (ip << 8) | val; + if (((val = getdec(&p)) < 0) || (val > 255)) return(0); + i->s_addr = htonl((ip << 8) | val); + return(1); +} + +#endif /* IMAGE_MENU */ + +int getdec(char **ptr) +{ + char *p = *ptr; + int ret=0; + if ((*p < '0') || (*p > '9')) return(-1); + while ((*p >= '0') && (*p <= '9')) { + ret = ret*10 + (*p - '0'); + p++; + } + *ptr = p; + return(ret); +} + +#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */ +#define K_STATUS 0x64 /* keyboard status */ +#define K_CMD 0x64 /* keybd ctlr command (write-only) */ + +#define K_OBUF_FUL 0x01 /* output buffer full */ +#define K_IBUF_FUL 0x02 /* input buffer full */ + +#define KC_CMD_WIN 0xd0 /* read output port */ +#define KC_CMD_WOUT 0xd1 /* write output port */ +#define KB_SET_A20 0xdf /* enable A20, + enable output buffer full interrupt + enable data line + disable clock line */ +#define KB_UNSET_A20 0xdd /* enable A20, + enable output buffer full interrupt + enable data line + disable clock line */ +#ifndef IBM_L40 +static void empty_8042(void) +{ + unsigned long time; + char st; + + time = currticks() + TICKS_PER_SEC; /* max wait of 1 second */ + while ((((st = inb(K_CMD)) & K_OBUF_FUL) || + (st & K_IBUF_FUL)) && + currticks() < time) + inb(K_RDWR); +} +#endif IBM_L40 + +/* + * Gate A20 for high memory + */ +void gateA20_set(void) +{ +#ifdef IBM_L40 + outb(0x2, 0x92); +#else /* IBM_L40 */ + empty_8042(); + outb(KC_CMD_WOUT, K_CMD); + empty_8042(); + outb(KB_SET_A20, K_RDWR); + empty_8042(); +#endif /* IBM_L40 */ +} + +#ifdef TAGGED_IMAGE +/* + * Unset Gate A20 for high memory - some operating systems (mainly old 16 bit + * ones) don't expect it to be set by the boot loader. + */ +void gateA20_unset(void) +{ +#ifdef IBM_L40 + outb(0x0, 0x92); +#else /* IBM_L40 */ + empty_8042(); + outb(KC_CMD_WOUT, K_CMD); + empty_8042(); + outb(KB_UNSET_A20, K_RDWR); + empty_8042(); +#endif /* IBM_L40 */ +} +#endif + +#ifdef ETHERBOOT32 +/* Serial console is only implemented in ETHERBOOT32 for now */ +void +putchar(int c) +{ +#ifndef ANSIESC + if (c == '\n') + putchar('\r'); +#endif + +#ifdef CONSOLE_CRT +#ifdef ANSIESC + handleansi(c); +#else + putc(c); +#endif +#endif +#ifdef CONSOLE_SERIAL +#ifdef ANSIESC + if (c == '\n') + serial_putc('\r'); +#endif + serial_putc(c); +#endif +} + +/************************************************************************** +GETCHAR - Read the next character from the console WITHOUT ECHO +**************************************************************************/ +int +getchar(void) +{ + int c = 256; + +#if defined CONSOLE_CRT || defined CONSOLE_SERIAL + do { +#ifdef CONSOLE_CRT + if (ischar()) + c = getc(); +#endif +#ifdef CONSOLE_SERIAL + if (serial_ischar()) + c = serial_getc(); +#endif + } while (c==256); + if (c == '\r') + c = '\n'; +#endif + return c; +} + +int +iskey(void) +{ +#ifdef CONSOLE_CRT + if (ischar()) + return 1; +#endif +#ifdef CONSOLE_SERIAL + if (serial_ischar()) + return 1; +#endif + return 0; +} +#endif /* ETHERBOOT32 */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ + +#include <asm/msr.h> + +#define CPUCLOCK 166 + +unsigned long currticks(void) +{ + register unsigned long l, h; + long long unsigned p; + long long unsigned hh,ll; + + rdtsc(l, h); + ll = l, hh = h; + + p = (ll + hh * 0x100000000LL) * 182 / (CPUCLOCK * 100000LL); + return (unsigned)p; +} + diff --git a/contrib/baremetal/startmpcc.S b/contrib/baremetal/startmpcc.S new file mode 100644 index 0000000..07486ce --- /dev/null +++ b/contrib/baremetal/startmpcc.S @@ -0,0 +1,756 @@ +/* #defines because ljmp wants a number, probably gas bug */ +/* .equ KERN_CODE_SEG,_pmcs-_gdt */ +#define KERN_CODE_SEG 0x08 + .equ KERN_DATA_SEG,_pmds-_gdt +/* .equ REAL_CODE_SEG,_rmcs-_gdt */ +#define REAL_CODE_SEG 0x18 + .equ REAL_DATA_SEG,_rmds-_gdt + .equ CR0_PE,1 + +#ifdef GAS291 +#define DATA32 data32; +#define ADDR32 addr32; +#define LJMPI(x) ljmp x +#else +#define DATA32 data32 +#define ADDR32 addr32 +/* newer GAS295 require #define LJMPI(x) ljmp *x */ +#define LJMPI(x) ljmp x +#endif + +#define PIC1_VBS 0x08 /* PIC1 interrupts start at vector 64 */ +#define PIC2_VBS 0x70 /* PIC1 interrupts start at vector 112 */ + +/* + * NOTE: if you write a subroutine that is called from C code (gcc/egcs), + * then you only have to take care of %ebx, %esi, %edi and %ebp. These + * registers must not be altered under any circumstance. All other registers + * may be clobbered without any negative side effects. If you don't follow + * this rule then you'll run into strange effects that only occur on some + * gcc versions (because the register allocator may use different registers). + * + * All the data32 prefixes for the ljmp instructions are necessary, because + * the assembler emits code with a relocation address of 0. This means that + * all destinations are initially negative, which the assembler doesn't grok, + * because for some reason negative numbers don't fit into 16 bits. The addr32 + * prefixes are there for the same reasons, because otherwise the memory + * references are only 16 bit wide. Theoretically they are all superfluous. + * One last note about prefixes: the data32 prefixes on all call _real_to_prot + * instructions could be removed if the _real_to_prot function is changed to + * deal correctly with 16 bit return addresses. I tried it, but failed. + */ + +/************************************************************************** +START - Where all the fun begins.... +**************************************************************************/ +/* this must be the first thing in the file because we enter from the top */ + .global _start + .code32 +_start: + cli + + /* load new IDT and GDT */ + lgdt gdtarg + lidt Idt_Reg + /* flush prefetch queue, and reload %cs:%eip */ + ljmp $KERN_CODE_SEG,$1f +1: + + /* reload other segment registers */ + movl $KERN_DATA_SEG,%eax + movl %eax,%ds + movl %eax,%es + movl %eax,%ss + movl $stktop,%esp + + /* program the PITs in order to stop them */ + mov $0x30,%al + out %al,$0x43 + out %al,$0x40 + mov $0x70,%al + out %al,$0x43 + out %al,$0x41 + mov $0xf0,%al + out %al,$0x43 + out %al,$0x42 + + call main + /* fall through */ + + .globl exit +exit: +2: + ljmp $KERN_CODE_SEG,$2b + +/************************************************************************** +MEMSIZE - Determine size of extended memory +**************************************************************************/ + .globl memsize +memsize: +#if 0 + pushl %ebx + pushl %esi + pushl %edi + call _prot_to_real + .code16 + movw $0xe801,%ax + stc + int $0x15 + jc 1f + andl $0xffff,%eax + andl $0xffff,%ebx + shll $6,%ebx + addl %ebx,%eax + jmp 2f +1: + movw $0x8800,%ax + int $0x15 + andl $0xffff,%eax +2: + movl %eax,%esi + DATA32 call _real_to_prot + .code32 + movl %esi,%eax + popl %edi + popl %esi + popl %ebx +#else + mov $32768,%eax +#endif + ret + +/************************************************************************** +XSTART - Transfer control to the kernel just loaded +**************************************************************************/ + .code16 + + .globl _int08_handler +_int08_handler: + movb $0x20, %al + outb %al, $0x20 + iret + + .globl _int10_handler +_int10_handler: + cmp $0x3, %ah + jnz _int10_04 + mov $0x0, %dx + mov $0x0, %cx + iret +_int10_04: + cmp $0x4, %ah + jnz _int10_05 + mov $0x0, %ah + iret +_int10_05: + cmp $0x5, %ah + jnz _int10_08 + mov $0x0, %al + iret +_int10_08: + cmp $0x8, %ah + jnz _int10_0D + mov $0x20, %al + mov $0x7, %ah + iret +_int10_0D: + cmp $0xD, %ah + jnz _int10_0F + mov $0x0, %al + iret +_int10_0F: + cmp $0xF, %ah + jnz _int10_XX + mov $0xb, %al + mov $80, %ah + mov $0, %bh +_int10_XX: + iret + + .globl _int11_handler +_int11_handler: + mov $0x22, %ax + iret + + .globl _int12_handler +_int12_handler: + mov $640, %ax + iret + + .globl _int13_handler +_int13_handler: + clc + mov $0, %ah + iret + + .globl _int14_handler +_int14_handler: + iret + + .globl _int15_handler +_int15_handler: + cmp $0xe801,%ax + jz _int15_008 + cmp $0x0, %ah + jz _int15_000 + cmp $0x1, %ah + jz _int15_000 + cmp $0x2, %ah + jz _int15_000 + cmp $0x3, %ah + jz _int15_000 + cmp $0xf, %ah + jz _int15_000 + cmp $0x21, %ah + jz _int15_000 + cmp $0x40, %ah + jz _int15_000 + cmp $0x41, %ah + jz _int15_000 + cmp $0x42, %ah + jz _int15_000 + cmp $0x43, %ah + jz _int15_000 + cmp $0x44, %ah + jz _int15_000 + cmp $0x80, %ah + jz _int15_001 + cmp $0x81, %ah + jz _int15_001 + cmp $0x82, %ah + jz _int15_002 + cmp $0x83, %ah + jz _int15_003 + cmp $0x84, %ah + jz _int15_000 + cmp $0x85, %ah + jz _int15_004 + cmp $0x86, %ah + jz _int15_003 + cmp $0x87, %ah + jz _int15_005 + cmp $0x88, %ah + jz _int15_006 + cmp $0x89, %ah + jz _int15_005 + cmp $0x90, %ah + jz _int15_007 + cmp $0xc0, %ah + jz _int15_000 + cmp $0xc1, %ah + jz _int15_000 + cmp $0xc2, %ah + jz _int15_000 + cmp $0xc3, %ah + jz _int15_000 + cmp $0xc4, %ah + jz _int15_000 + iret + +_int15_000: + mov $0x86, %ah + stc + iret + +_int15_001: + mov $0, %bx + mov $0, %cx + iret + +_int15_002: + mov $0, %bx + iret + +_int15_003: + clc + iret + +_int15_004: + mov $0, %al + iret + +_int15_005: + mov $0, %ah + clc + cmp $0, %ah + iret + +_int15_006: + mov $0xf000, %ax + iret + +_int15_007: + stc + iret + +_int15_008: + clc + mov $1024, %dx /* dx -> extended memory size (in 64K chuncks) */ + mov $640, %cx /* cx -> conventional memory size (in 1 Kbytes chuncks) */ + iret + + .globl _int16_handler +_int16_handler: + cmp $0x0, %ah + jnz _int16_01 + mov $0x20, %al + mov $0x39, %ah + iret +_int16_01: + cmp $0x1, %ah + jnz _int16_02 + iret +_int16_02: + cmp $0x2, %ah + jnz _int16_05 + mov $0, %al + iret +_int16_05: + cmp $0x5, %ah + jnz _int16_10 + mov $0, %al + iret +_int16_10: + cmp $0x10, %ah + jnz _int16_11 + mov $0x20, %al + mov $0x39, %ah + iret +_int16_11: + cmp $0x11, %ah + jnz _int16_12 + iret +_int16_12: + cmp $0x12, %ah + jnz _int16_XX + mov $0, %ax + iret +_int16_XX: + iret + + .globl _int17_handler +_int17_handler: + mov $0xd0, %ah + iret + + .globl _int19_handler +_int19_handler: + hlt + iret + + .globl _int1A_handler +_int1A_handler: + stc + iret + + .code32 + .globl xstart +xstart: + /* reprogram the PICs so that interrupt are masked */ + movb $0x11,%al /* ICW1 [ICW4 NEEDED, EDGE TRIGGERED]*/ + outb %al,$0x20 + movb $PIC1_VBS, %al + outb %al,$0x21 + movb $0x4,%al + outb %al,$0x21 + movb $0x1,%al + outb %al,$0x21 + movb $0xff,%al + outb %al,$0x21 + + movb $0x11,%al /* ICW1 [ICW4 NEEDED, EDGE TRIGGERED]*/ + outb %al,$0xa0 + movb $PIC2_VBS, %al + outb %al,$0xa1 + movb $0x2,%al + outb %al,$0xa1 + movb $0x1,%al + outb %al,$0xa1 + movb $0xff,%al + outb %al,$0xa1 + + pushl %ebp + movl %esp,%ebp + pushl %ebx + pushl %esi + pushl %edi + movl 8(%ebp),%eax + movl %eax,_execaddr + movl 12(%ebp),%ebx + movl 16(%ebp),%ecx /* bootp record (32bit pointer) */ + addl $28,%ecx /* ip, udp header */ + shll $12,%ecx + shrw $12,%cx + call _prot_to_real + .code16 +/* MP: add int10 handler */ + push %eax + push %ebx + push %es + mov $0,%ax + mov %ax,%es + mov %cs,%ax + shl $16,%eax + + ADDR32 mov $(_int08_handler-_start),%ax + mov $0x20,%ebx + mov %eax,%es:(%bx) + + ADDR32 mov $(_int10_handler-_start),%ax + mov $0x40,%ebx + mov %eax,%es:(%bx) + + ADDR32 mov $(_int11_handler-_start),%ax + mov $0x44,%ebx + mov %eax,%es:(%bx) + + ADDR32 mov $(_int12_handler-_start),%ax + mov $0x48,%ebx + mov %eax,%es:(%bx) + + ADDR32 mov $(_int13_handler-_start),%ax + mov $0x4c,%ebx + mov %eax,%es:(%bx) + + ADDR32 mov $(_int14_handler-_start),%ax + mov $0x50,%ebx + mov %eax,%es:(%bx) + + ADDR32 mov $(_int15_handler-_start),%ax + mov $0x54,%ebx + mov %eax,%es:(%bx) + + ADDR32 mov $(_int16_handler-_start),%ax + mov $0x58,%ebx + mov %eax,%es:(%bx) + + ADDR32 mov $(_int17_handler-_start),%ax + mov $0x5c,%ebx + mov %eax,%es:(%bx) + + ADDR32 mov $(_int19_handler-_start),%ax + mov $0x64,%ebx + mov %eax,%es:(%bx) + + ADDR32 mov $(_int1A_handler-_start),%ax + mov $0x68,%ebx + mov %eax,%es:(%bx) + + pop %es + pop %ebx + pop %eax +/* */ + pushl %ecx /* bootp record */ + pushl %ebx /* file header */ + movl $((RELOC<<12)+(1f-RELOC)),%eax + pushl %eax + ADDR32 LJMPI(_execaddr-_start) +1: + addw $8,%sp /* XXX or is this 10 in case of a 16bit "ret" */ + DATA32 call _real_to_prot + .code32 + popl %edi + popl %esi + popl %ebx + popl %ebp + ret + +_execaddr: + .long 0 + +#ifdef IMAGE_MULTIBOOT +/************************************************************************** +XEND - Restart Etherboot from the beginning (from protected mode) +**************************************************************************/ + + .globl xend +xend: + cs + lidt idtarg_realmode-_start+RELOC + cs + lgdt gdtarg-_start+RELOC +#ifdef GAS291 + ljmp $REAL_CODE_SEG,$1f-RELOC /* jump to a 16 bit segment */ +#else + ljmp $REAL_CODE_SEG,$1f-_start /* jump to a 16 bit segment */ +#endif /* GAS291 */ +1: + .code16 + movw $REAL_DATA_SEG,%ax + movw %ax,%ds + movw %ax,%ss + movw %ax,%es + + /* clear the PE bit of CR0 */ + movl %cr0,%eax + andl $0!CR0_PE,%eax + movl %eax,%cr0 + + /* make intersegment jmp to flush the processor pipeline + * and reload %cs:%eip (to clear upper 16 bits of %eip). + */ + DATA32 ljmp $(RELOC)>>4,$2f-_start +2: + /* we are in real mode now + * set up the real mode segment registers : %ds, %ss, %es + */ + movw %cs,%ax + movw %ax,%ds + movw %ax,%es + movw %ax,%ss + xorl %esp,%esp + ADDR32 movw initsp-RELOC,%sp + + movw $0,%ax + movw %ax,%fs + movw %ax,%gs + + sti + jmp _start + + .code32 +#endif /* IMAGE_MULTIBOOT */ + +.global get_cs +get_cs: + xorl %eax,%eax + movw %cs,%ax + ret + +.global get_ds +get_ds: + xorl %eax,%eax + movw %ds,%ax + ret + +.global getsp +getsp: + movl %esp,%eax /* GET STACK POINTER */ + subl $4, %eax /* ACCOUNT FOR RETURN ADDRESS ON */ + ret + +.global get_gdtbase +get_gdtbase: + sub $8,%esp /* ALLOCATE ROOM ON THE STACK */ + sgdt (%esp,1) /*STORE IGDT REGISTER ON STACK */ + mov 2(%esp),%eax /* READ GDT BASE ADDRESS */ + mov $KERN_DATA_SEG,%dx /* ASSUME UNIVERSAL DS. */ + add $8,%esp /* RESTORE STACK */ + ret /* DONE */ + +.global get_gdtsize +get_gdtsize: + sub $8,%esp /* ALLOCATE ROOM ON THE STACK */ + sgdt (%esp,1) /*STORE IGDT REGISTER ON STACK */ + xor %eax,%eax + mov 2(%esp),%eax /* READ GDT BASE ADDRESS */ + mov (%ESP),%ax + shr $3,%ax + add $8,%esp /* RESTORE STACK */ + ret /* DONE */ + +.global get_idtbase +get_idtbase: + sub $8,%esp + sidt (%esp,1) /* STORE IIDT REGISTER ON STACK */ + mov 2(%esp),%eax + mov $KERN_DATA_SEG,%dx + add $8,%esp + ret + +.global get_lw +get_lw: + xor %edx,%edx + mov 8(%esp),%eax + mov 4(%esp),%dx + ret + +/************************************************************************** +SETJMP - Save stack context for non-local goto +**************************************************************************/ + .globl setjmp +setjmp: + mov 4(%esp),%ecx + mov 0(%esp),%edx + mov %edx,0(%ecx) + mov %ebx,4(%ecx) + mov %esp,8(%ecx) + mov %ebp,12(%ecx) + mov %esi,16(%ecx) + mov %edi,20(%ecx) + mov %eax,24(%ecx) + mov $0,%eax + ret + +/************************************************************************** +LONGJMP - Non-local jump to a saved stack context +**************************************************************************/ + .globl longjmp +longjmp: + mov 4(%esp),%edx + mov 8(%esp),%eax + mov 0(%edx),%ecx + mov 4(%edx),%ebx + mov 8(%edx),%esp + mov 12(%edx),%ebp + mov 16(%edx),%esi + mov 20(%edx),%edi + cmp $0,%eax + jne 1f + mov $1,%eax +1: mov %ecx,0(%esp) + ret + +/************************************************************************** +_REAL_TO_PROT - Go from REAL mode to Protected Mode +**************************************************************************/ + .globl _real_to_prot +_real_to_prot: + .code16 + cli + cs + ADDR32 lgdt gdtarg-_start + movl %cr0,%eax + orl $CR0_PE,%eax + movl %eax,%cr0 /* turn on protected mode */ + + /* flush prefetch queue, and reload %cs:%eip */ + DATA32 ljmp $KERN_CODE_SEG,$1f +1: + .code32 + /* reload other segment registers */ + movl $KERN_DATA_SEG,%eax + movl %eax,%ds + movl %eax,%es + movl %eax,%ss + addl $RELOC,%esp /* Fix up stack pointer */ + xorl %eax,%eax + movl %eax,%fs + movl %eax,%gs + popl %eax /* Fix up return address */ + addl $RELOC,%eax + pushl %eax + ret + +/************************************************************************** +_PROT_TO_REAL - Go from Protected Mode to REAL Mode +**************************************************************************/ + .globl _prot_to_real +_prot_to_real: + .code32 + popl %eax + subl $RELOC,%eax /* Adjust return address */ + pushl %eax + subl $RELOC,%esp /* Adjust stack pointer */ +#ifdef GAS291 + ljmp $REAL_CODE_SEG,$1f-RELOC /* jump to a 16 bit segment */ +#else + ljmp $REAL_CODE_SEG,$1f-_start /* jump to a 16 bit segment */ +#endif /* GAS291 */ +1: + .code16 + movw $REAL_DATA_SEG,%ax + movw %ax,%ds + movw %ax,%ss + movw %ax,%es + movw %ax,%fs + movw %ax,%gs + cli + + /* clear the PE bit of CR0 */ + movl %cr0,%eax + andl $0!CR0_PE,%eax + movl %eax,%cr0 + + /* make intersegment jmp to flush the processor pipeline + * and reload %cs:%eip (to clear upper 16 bits of %eip). + */ + DATA32 ljmp $(RELOC)>>4,$2f-_start +2: + /* we are in real mode now + * set up the real mode segment registers : %ds, $ss, %es + */ + movw %cs,%ax + movw %ax,%ds + movw %ax,%es + movw %ax,%ss +#if 0 + sti +#endif + DATA32 ret /* There is a 32 bit return address on the stack */ + .code32 + +/************************************************************************** +GLOBAL DESCRIPTOR TABLE +**************************************************************************/ + .align 4 +Idt_Reg: + .word 0x3ff + .long 0 + + .align 4 +_gdt: +gdtarg: +Gdt_Table: + .word 0x27 /* limit */ + .long _gdt /* addr */ + .word 0 +_pmcs: + /* 32 bit protected mode code segment */ + .word 0xffff,0 + .byte 0,0x9f,0xcf,0 + +_pmds: + /* 32 bit protected mode data segment */ + .word 0xffff,0 + .byte 0,0x93,0xcf,0 + +_rmcs: + /* 16 bit real mode code segment */ + .word 0xffff,(RELOC&0xffff) + .byte (RELOC>>16),0x9b,0x00,(RELOC>>24) + +_rmds: + /* 16 bit real mode data segment */ + .word 0xffff,(RELOC&0xffff) + .byte (RELOC>>16),0x93,0x00,(RELOC>>24) + + .align 4 +RUN_GDT: /* POINTER TO GDT IN RAM */ + .byte 0x7f,0 /* [BSP_GDT_NUM*8]-1 */ + .long Gdt_Table + + .align 4 + + .section ".rodata" +err_not386: + .ascii "Etherboot/32 requires 386+" + .byte 0x0d, 0x0a +err_not386_end: + +days: .long 0 +irq_num: .long + + .data + .align 4 + .org 2048 +.global stktop +stktop: + .long + +.section ".armando" +/* 1:::::::::2:::::::::3:::::::3 */ +/* 12345678901234567890123456789012345678 */ +/* v----+----v----+----v----+----v----+--- */ + +.global EtherbootString +EtherbootString: +.ascii "EtherBoot MPCC " /* fw identifier */ + +.byte 0, 0 /* mandatory hole */ + +.long _start /* entry point */ +.word 0 +.byte 'E' /* type */ +.byte 0 /* selector */ +.word 0 /* CRC */ diff --git a/contrib/bin2intelhex/Makefile b/contrib/bin2intelhex/Makefile new file mode 100644 index 0000000..7406968 --- /dev/null +++ b/contrib/bin2intelhex/Makefile @@ -0,0 +1,9 @@ + +CC=gcc +CFLAGS=-Wall -O2 + +bin2intelhex: + + +clean: + rm -f bin2intelhex core *.o diff --git a/contrib/bin2intelhex/bin2intelhex.c b/contrib/bin2intelhex/bin2intelhex.c new file mode 100644 index 0000000..75b88c1 --- /dev/null +++ b/contrib/bin2intelhex/bin2intelhex.c @@ -0,0 +1,148 @@ +/* name : bin2intelhex.c + * from : Jean Marc Lacroix <jeanmarc.lacroix@free.fr> + * date : 06/12/1997. + * abstract : Y have rewrite this program from ????? with some modifications + * to add : + * - the Intel specification. + * - correct a bug because my prom programmer don't understand the + * initial format. Y suspect a bug in the calcul of the lrc + * in the original program. + * - correct the format of printf . In the original program, it was + * %x, and it is in fact %X, because in the Intel Format, all the + * char are in upper case. + * - correct the lrc calculation. + * usage: + *------- + * this program read the standard input and put to the standard output + * the result of the conversion. + * an example of use : + * cat my_bin | bin2intelhex > my_bin.hex or..... + * bin2intelhex < my_bin > my_bin.hex + */ + + +/* + * $Id$ + * $Log$ + * Revision 1.1 2005/05/17 16:45:06 mcb30 + * Initial revision + * + * Revision 1.9 1997/12/14 05:14:54 install + * - some documentation.... + * + */ + +#include <stdio.h> +#include <unistd.h> + +/* Intel Hex format specifications + +The 8-bit Intel Hex File Format is a printable ASCII format consisting of one + or more data records followed by an end of file record. Each +record consists of one line of information. Data records may appear in any + order. Address and data values are represented as 2 or 4 hexadecimal +digit values. + +Record Format +:LLAAAARRDDDD......DDDDCC + + +LL +AAAA +RR +DD +CC +Length field. Number of data bytes. +Address field. Address of first byte. +Record type field. 00 for data and 01 for end of record. +Data field. +Checksum field. One's complement of length, address, record type and data + fields modulo 256. +CC = LL + AAAA + RR + all DD = 0 + +Example: +:06010000010203040506E4 +:00000001FF + +The first line in the above example Intel Hex file is a data record addressed + at location 100H with data values 1 to 6. The second line is the end +of file record, so that the LL field is 0 + +*/ + + +typedef unsigned char t_u8; +typedef unsigned short t_u16; +/* + * the choice for the total length (16) of a line, but the specification + * can support an another value + */ +#define LL_MAX_LINE 16 +typedef struct +{ + t_u8 intel_lg_data; + t_u16 intel_adr; + t_u8 intel_type; + t_u8 intel_data [LL_MAX_LINE]; + t_u8 intel_lrc; +} t_one_line; +#define INTEL_DATA_TYPE 0 +#define EXIT_OK 0 +int main (const int argc, const char ** const argv) +{ + t_one_line line; + /* + * init for the adress, please note that it is assume that the program begin at 0 + */ + line.intel_adr = 0; + line.intel_type = INTEL_DATA_TYPE; + /* + * read the data on the standard input + */ + while ((line.intel_lg_data = read (0, &line.intel_data [0] ,LL_MAX_LINE )) > 0) + { + t_u8 i; + /* + * and now for this line, calculate the lrc. + */ + line.intel_lrc = line.intel_lg_data; + line.intel_lrc += ((line.intel_adr >> 8) & 0xff); + line.intel_lrc += (line.intel_adr &0xff); + line.intel_lrc += line.intel_type; + /* + * the structure is ready, print it to stdout in the + * right format + */ + (void) printf (":%02X%04X%02X", + line.intel_lg_data, + line.intel_adr, + line.intel_type); + /* + * edit all the data read + */ + for (i=0; i<line.intel_lg_data; i++) + { + (void) printf ("%02X", + (line.intel_data [i] & 0xff)); + /* + * add to the lrc the data print + */ + line.intel_lrc +=line.intel_data [i]; + } + /* + * edit the value of the lrc and new line for the next + */ + (void) printf ("%02X\n", + (0x100 - line.intel_lrc) & 0xff); + /* + * prepare the new adress for the next line + */ + line.intel_adr+=line.intel_lg_data; + } + /* + * print the last line with a length of 0 data, so that the lrc is easy to + * calculate (ff+01 =0) + */ + printf (":00000001FF\n"); + exit (EXIT_OK); +} diff --git a/contrib/bin2intelhex/bin2intelhex.c.simple b/contrib/bin2intelhex/bin2intelhex.c.simple new file mode 100644 index 0000000..3cb279a --- /dev/null +++ b/contrib/bin2intelhex/bin2intelhex.c.simple @@ -0,0 +1,74 @@ +/* + + Quick and dirty program to make intel-hex from a binary. + + Written by R.E.Wolff@BitWizard.nl + This file is in the public domain + + Typing started: + + Mon Jun 16 00:24:15 MET DST 1997 + + programming stopped: + + Mon Jun 16 00:31:27 MET DST 1997 + + debugging finished (2 bugs found): + Mon Jun 16 00:32:52 MET DST 1997 + +--------------------------------------------------------- + + Doc written in timeout. Everything else in this file was done while + the timer was running. + + I promised "Mark Kopecki" that writing the bin-to-intel-hex + converter would cost less than 15 minutes, and that it would be more + trouble to find a converter on the net than to write the converter + myself. I ended up spending over half an hour searching for + spec/converter/docs because of unreachable hosts on the internet. I + got a file with docs, after that it was 8 minutes..... + +--------------------------------------------------------- + +*/ + + +#include <stdio.h> +#include <unistd.h> + +/* Intel Hex format: + + ll aaaa tt dd....dd cc + + ll = length + aaaa = address + tt = type + dd....dd = data + cc = checksum. +*/ + + +int main (int argc, char **argv) +{ + unsigned char buf[32]; + int addr = 0; + int n,i; + + while ((n = read (0, buf+4, 16)) > 0) { + buf[0] = n; + buf[1] = addr >> 8; + buf[2] = addr & 0xff; + buf[3] = 0x00; + buf[4+n] = 0x00; + + for (i=0;i<4+n;i++) + buf[4+n] -= buf[i]; + printf (":"); + for (i=0;i<= 4+n;i++) + printf ("%02x", buf[i]); + printf ("\n"); + addr += n; + } + printf (":0000000001ff\n"); + exit (0); +} diff --git a/contrib/bochs/.cvsignore b/contrib/bochs/.cvsignore new file mode 100644 index 0000000..baadb8c --- /dev/null +++ b/contrib/bochs/.cvsignore @@ -0,0 +1,5 @@ +bochsout.txt +parport.out +ne2k-tx.log +ne2k-txdump.txt + diff --git a/contrib/bochs/Makefile b/contrib/bochs/Makefile new file mode 100644 index 0000000..3c0e645 --- /dev/null +++ b/contrib/bochs/Makefile @@ -0,0 +1,7 @@ +all : serial-console.1 + +%.1 : % + pod2man $< > $@ + +clean : + rm -f serial-console.1 diff --git a/contrib/bochs/README b/contrib/bochs/README new file mode 100644 index 0000000..80e1529 --- /dev/null +++ b/contrib/bochs/README @@ -0,0 +1,121 @@ +Running Etherboot within Bochs +============================== + +Michael Brown <mbrown@fensystems.co.uk> +Based on an idea suggested by H. Peter Anvin <hpa@zytor.com>. + +$Id$ + +Bochs is a program that simulates a complete Intel x86 computer, +including hardware. It can be used to test Etherboot. There is a +special pseudo NIC ("pnic") implemented in Bochs, with a corresponding +driver in Etherboot. (There is also an NE2000 ISA driver in Bochs, +but it doesn't seem to quite work.) + +To get bochs running is fairly simple: + +1. Get the bochs source code: + a) cvs -d:pserver:anonymous:@cvs.sourceforge.net:/cvsroot/bochs login + b) cvs -d:pserver:anonymous:@cvs.sourceforge.net:/cvsroot/bochs co bochs + +2. Configure bochs with + ./configure --enable-all-optimisations --enable-pci \ + --enable-ne2000 --enable-pnic + Other potentially useful configure options: + --prefix=/usr + to force use of standard file locations + --enable-debugger + to enable the internal debugger + +3. Build bochs: + make + +4. Configure Etherboot with CONFIG_PCI_DIRECT: add the line + CFLAGS += -DCONFIG_PCI_DIRECT + to the end of src/arch/i386/Config. + +5. Build bin/pnic.zrom: + make bin/pnic.zrom + +6. Load the TUN/TAP kernel module: + modprobe tun + You should see the device /dev/net/tun is created automatically if + you're using devfs, otherwise you may have to create it by hand with: + mknod /dev/net/tun c 10 200 + +7. Grant yourself write access to /dev/net/tun: + su -c 'chown <your user id> /dev/net/tun' + The alternative to this is to run Bochs as root. Don't do that. + +8. Add the following fragment to /etc/dhcpd.conf: + subnet 10.254.254.0 netmask 255.255.255.252 { + range dynamic-bootp 10.254.254.1 10.254.254.1; + } + You will also need to add in any of your usual declarations for + Etherboot, e.g. 'filename "vmlinuz.ltsp";'. Note that this setup + assumes that your DHCP server, TFTP server etc. all live on the + machine you are using for running Bochs. If not, then you're on + your own. + +9. Change back to this directory and run bochs from your Bochs source tree: + cd /path/to/Etherboot/contrib/bochs + /path/to/bochs/source/tree/bochs + +10. Select option 5 (Begin simulation). You will be prompted for your + root password. This is required in order to configure the tun1 + network interface and to restart the DHCP server. + +11. You should see Bochs start up and attempt to boot from the network, + with a screen that looks like: + +VGA BIOS - Version 2.40 +Copyright (C) 1990-2000 Elpin Systems, Inc. +All rights reserved. + +Licensed for use with bochs, courtesy of MandrakeSoft. + +For information on this or other VGA development products, contact +Elpin Systems at: (800) 723-9038 or www.elpin.com + +Bochs BIOS, 1 cpu, $Revision$ $Date$ + + +Etherboot 5.3.6 (GPL) http://etherboot.org Tagged ELF for [PNIC] +Relocating _text from: [00091020,0009fb50) to [01ef14d0,01f00000) +Boot from (N)etwork or (Q)uit? + +Probing pci nic... +[pnic] - Detected Bochs Pseudo NIC MAC FE:FD:00:00:00:01 (API v1.0) at 0xdc00 +Searching for server (DHCP)... +..Me: 10.254.254.1, Server: 10.254.254.2 +Loading 10.254.254.2:/tftpboot/kernel + + + + +Serial console +============== + +You can use the program "serial-console" to obtain a virtual serial +console for Etherboot running within Bochs. Simply run +"./serial-console" on a spare tty (e.g. a separate xterm window) +before starting Bochs, and ensure that you have compiled Etherboot +with appropriate settings such as + CFLAGS+= -DCONSOLE_DUAL -DCOMCONSOLE=0x3F8 -DCONSPEED=9600 + +There is a manual page for "serial-console"; use +"man ./serial-console.1" to view it. + + + +TODO +==== + +Packet forwarding/masquerading - document what must be set up. + +Mention possibility of using RFB as the display device - in +conjunction with the serial console, gives you a test facility that +can be accessed remotely. + +Mention use of BOCHSBP instruction (xchgw %bx,%bx) to avoid need to +calculate breakpoints. diff --git a/contrib/bochs/bochsrc.txt b/contrib/bochs/bochsrc.txt new file mode 100644 index 0000000..d7ba043 --- /dev/null +++ b/contrib/bochs/bochsrc.txt @@ -0,0 +1,658 @@ +# You many now use double quotes around pathnames, in case +# your pathname includes spaces. + +#======================================================================= +# CONFIG_INTERFACE +# +# The configuration interface is a series of menus or dialog boxes that +# allows you to change all the settings that control Bochs's behavior. +# There are two choices of configuration interface: a text mode version +# called "textconfig" and a graphical version called "wx". The text +# mode version uses stdin/stdout and is always compiled in. The graphical +# version is only available when you use "--with-wx" on the configure +# command. If you do not write a config_interface line, Bochs will +# choose a default for you. +# +# NOTE: if you use the "wx" configuration interface, you must also use +# the "wx" display library. +#======================================================================= +#config_interface: textconfig +#config_interface: wx + +#======================================================================= +# DISPLAY_LIBRARY +# +# The display library is the code that displays the Bochs VGA screen. Bochs +# has a selection of about 10 different display library implementations for +# different platforms. If you run configure with multiple --with-* options, +# the display_library command lets you choose which one you want to run with. +# If you do not write a display_library line, Bochs will choose a default for +# you. +# +# The choices are: +# x use X windows interface, cross platform +# win32 use native win32 libraries +# carbon use Carbon library (for MacOS X) +# beos use native BeOS libraries +# macintosh use MacOS pre-10 +# amigaos use native AmigaOS libraries +# sdl use SDL library, cross platform +# svga use SVGALIB library for Linux, allows graphics without X11 +# term text only, uses curses/ncurses library, cross platform +# rfb provides an interface to AT&T's VNC viewer, cross platform +# wx use wxWindows library, cross platform +# nogui no display at all +# +# NOTE: if you use the "wx" configuration interface, you must also use +# the "wx" display library. +#======================================================================= +#display_library: amigaos +#display_library: beos +#display_library: carbon +#display_library: macintosh +#display_library: nogui +#display_library: rfb +#display_library: sdl +#display_library: term +#display_library: win32 +#display_library: wx +#display_library: x + +#======================================================================= +# ROMIMAGE: +# You now need to load a ROM BIOS into F0000-FFFFF. I've wiped +# out most of the BIOS hooks, and replace them with real BIOS +# support. Normally, you can use a precompiled BIOS in the bios/ +# directory, named BIOS-bochs-latest. +#======================================================================= +#romimage: bios/BIOS-bochs-970717a +#romimage: file=bios/BIOS-bochs-latest, address=0xf0000 +romimage: file=$BXSHARE/BIOS-bochs-latest, address=0xf0000 +#romimage: file=bios/BIOS-bochs-2-processors, address=0xf0000 +#romimage: file=bios/BIOS-bochs-4-processors, address=0xf0000 +#romimage: file=bios/rombios.bin, address=0xf0000 + +#======================================================================= +# MEGS +# set this to the default number of Megabytes of memory you want +# to emulate. You may also pass the '-megs xyz' option to bochs +# +# The default is 32MB, most OS's won't need more than that. +#======================================================================= +#megs: 256 +#megs: 128 +#megs: 64 +megs: 32 +#megs: 16 +#megs: 8 + +#======================================================================= +# OPTROMIMAGE[1-4]: +# You may now load up to 4 optional ROM images. Be sure to use a +# read-only area, typically between C8000 and EFFFF. These optional +# ROM images should not overwrite the rombios (located at +# F0000-FFFFF) and the videobios (located at C0000-C7FFF). +# Those ROM images will be initialized by the bios if they contain +# the right signature (0x55AA). +# It can also be a convenient way to upload some arbitary code/data +# in the simulation, that can be retrieved by the boot loader +#======================================================================= +#optromimage1: file=optionalrom.bin, address=0xd0000 +#optromimage2: file=optionalrom.bin, address=0xd1000 +#optromimage3: file=optionalrom.bin, address=0xd2000 +#optromimage4: file=optionalrom.bin, address=0xd3000 +#optromimage1: file=../../src/bin/ne.zrom, address=0xd0000 +optromimage1: file=../../src/bin/pnic.zrom, address=0xd0000 + +#======================================================================= +# VGAROMIMAGE +# You now need to load a VGA ROM BIOS into C0000. +#======================================================================= +#vgaromimage: bios/VGABIOS-lgpl-latest +#vgaromimage: bios/VGABIOS-elpin-2.40 +vgaromimage: $BXSHARE/VGABIOS-elpin-2.40 + +#======================================================================= +# FLOPPYA: +# Point this to pathname of floppy image file or device +# This should be of a bootable floppy(image/device) if you're +# booting from 'a'. +# +# You can set the initial status of the media to 'ejected' or 'inserted'. +# floppya: 2_88=path, status=ejected (2.88M 3.5" floppy) +# floppya: 1_44=path, status=inserted (1.44M 3.5" floppy) +# floppya: 1_2=path, status=ejected (1.2M 5.25" floppy) +# floppya: 720k=path, status=inserted (720K 3.5" floppy) +# floppya: 360k=path, status=inserted (360K 5.25" floppy) +# +# The path should be the name of a disk image file. On unix, you can use +# a raw device name such as /dev/fd0 on Linux. On WinNT and Win2k, use +# drive letters such as a: or b: as the path. Raw floppy access is not +# supported on Windows 95 and 98. +#======================================================================= +floppya: 1_44=/dev/fd0, status=inserted +#floppya: file=../1.44, status=inserted +#floppya: 1_44=/dev/fd0H1440, status=inserted +#floppya: 1_2=../1_2, status=inserted +#floppya: 1_44=a:, status=inserted +#floppya: 1_44=a.img, status=inserted + +#======================================================================= +# FLOPPYB: +# See FLOPPYA above for syntax +#======================================================================= +#floppyb: 1_44=b:, status=inserted +floppyb: 1_44=b.img, status=inserted + +#======================================================================= +# ATA0, ATA1, ATA2, ATA3 +# ATA controller for hard disks and cdroms +# +# ata[0-3]: enabled=[0|1], ioaddr1=addr, ioaddr2=addr, irq=number +# +# These options enables up to 4 ata channels. For each channel +# the two base io address and the irq must be specified. +# +# ata0 is enabled by default, with ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 +# +# Examples: +# ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 +# ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15 +# ata2: enabled=1, ioaddr1=0x1e8, ioaddr2=0x3e8, irq=11 +# ata3: enabled=1, ioaddr1=0x168, ioaddr2=0x368, irq=9 +#======================================================================= +ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 +ata1: enabled=0, ioaddr1=0x170, ioaddr2=0x370, irq=15 +ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e8, irq=11 +ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x368, irq=9 + +#======================================================================= +# ATA[0-3]-MASTER, ATA[0-3]-SLAVE +# +# This defines the type and characteristics of all attached ata devices: +# type= type of attached device [disk|cdrom] +# path= path of the image +# cylinders= only valid for disks +# heads= only valid for disks +# spt= only valid for disks +# status= only valid for cdroms [inserted|ejected] +# biosdetect= type of biosdetection [none|auto], only for disks on ata0 [cmos] +# translation=type of transation of the bios, only for disks [none|lba|large|rechs|auto] +# model= string returned by identify device command +# +# Point this at a hard disk image file, cdrom iso file, or physical cdrom +# device. To create a hard disk image, try running bximage. It will help you +# choose the size and then suggest a line that works with it. +# +# In UNIX it may be possible to use a raw device as a Bochs hard disk, +# but WE DON'T RECOMMEND IT. In Windows there is no easy way. +# +# In windows, the drive letter + colon notation should be used for cdroms. +# Depending on versions of windows and drivers, you may only be able to +# access the "first" cdrom in the system. On MacOSX, use path="drive" +# to access the physical drive. +# +# The path, cylinders, heads, and spt are mandatory for type=disk +# The path is mandatory for type=cdrom +# +# Default values are: +# biosdetect=auto, translation=auto, model="Generic 1234" +# +# The biosdetect option has currently no effect on the bios +# +# Examples: +# ata0-master: type=disk, path=10M.sample, cylinders=306, heads=4, spt=17 +# ata0-slave: type=disk, path=20M.sample, cylinders=615, heads=4, spt=17 +# ata1-master: type=disk, path=30M.sample, cylinders=615, heads=6, spt=17 +# ata1-slave: type=disk, path=46M.sample, cylinders=940, heads=6, spt=17 +# ata2-master: type=disk, path=62M.sample, cylinders=940, heads=8, spt=17 +# ata2-slave: type=disk, path=112M.sample, cylinders=900, heads=15, spt=17 +# ata3-master: type=disk, path=483M.sample, cylinders=1024, heads=15, spt=63 +# ata3-slave: type=cdrom, path=iso.sample, status=inserted +#======================================================================= +#ata0-master: type=disk, path="30M.sample", cylinders=615, heads=6, spt=17 +#ata0-slave: type=cdrom, path=D:, status=inserted +#ata0-slave: type=cdrom, path=/dev/cdrom, status=inserted +#ata0-slave: type=cdrom, path="drive", status=inserted + +#======================================================================= +# +# The DISKC option is deprecated. Use ATA* options instead. +# +# DISKC: file=, cyl=, heads=, spt= +# Point this at a hard disk image file. To create +# a hard disk image, try running bximage. It will help you choose the +# size and then suggest a diskc line that works with it. +# +# In UNIX it may be possible to use a raw device as a Bochs hard disk, +# but WE DON'T RECOMMEND IT. In Windows there is no easy way. +# +# Examples: +# diskc: file=10M.sample, cyl=306, heads=4, spt=17 +# diskc: file=20M.sample, cyl=615, heads=4, spt=17 +# diskc: file=30M.sample, cyl=615, heads=6, spt=17 +# diskc: file=46M.sample, cyl=940, heads=6, spt=17 +# diskc: file=62M.sample, cyl=940, heads=8, spt=17 +# diskc: file=112M.sample, cyl=900, heads=15, spt=17 +# diskc: file=483M.sample, cyl=1024, heads=15, spt=63 +#======================================================================= +#diskc: file="30M.sample", cyl=615, heads=6, spt=17 + +#======================================================================= +# +# The DISKD option is deprecated. Use ATA* options instead. +# +# DISKD: +# See DISKC above for syntax +# +# NOTE: diskd and cdromd must not be used together! +#======================================================================= +#diskd: file="diskd.img", cyl=615, heads=6, spt=17 + +#======================================================================= +# +# The CDROMD option is deprecated. Use ATA* options instead. +# +# CDROMD: +# +# cdromd: dev=/dev/cdrom, status=inserted +# cdromd: dev=/dev/cdrom, status=ejected +# cdromd: dev=e:, status=ejected +# +# In windows, the drive letter + colon notation should be used for cdroms. +# Depending on versions of windows and drivers, you may only be able to +# access the "first" cdrom in the system. On MacOSX, use path="drive" +# to access the physical drive. +# +# NOTE: diskd and cdromd must not be used together! +#======================================================================= +#cdromd: dev=D:, status=inserted +#cdromd: dev=/dev/cdrom, status=inserted +#cdromd: dev="drive", status=inserted + +#======================================================================= +# NEWHARDDRIVESUPPORT: enabled=[0|1] +# As of cvs version on 5/17/2001, newharddrivesupport is on by default. +#======================================================================= +#newharddrivesupport: enabled=1 + +#======================================================================= +# BOOT: +# This defines your boot drive. +# You can either boot from 'floppy', 'disk' or 'cdrom' +# legacy 'a' and 'c' are also supported +# Examples: +# boot: floppy +# boot: disk +# boot: cdrom +# boot: c +# boot: a +#======================================================================= +#boot: floppy +#boot: disk + +#======================================================================= +# FLOPPY_BOOTSIG_CHECK: disabled=[0|1] +# Enables or disables the 0xaa55 signature check on boot floppies +# Defaults to disabled=0 +# Examples: +# floppy_bootsig_check: disabled=0 +# floppy_bootsig_check: disabled=1 +#======================================================================= +#floppy_bootsig_check: disabled=1 +floppy_bootsig_check: disabled=0 + +#======================================================================= +# LOG: +# Give the path of the log file you'd like Bochs debug and misc. verbage +# to be written to. If you really don't want it, make it /dev/null. :^( +# +# Examples: +# log: ./bochs.out +# log: /dev/tty +#======================================================================= +#log: /dev/null +log: bochsout.txt + +#======================================================================= +# LOGPREFIX: +# This handles the format of the string prepended to each log line. +# You may use those special tokens : +# %t : 11 decimal digits timer tick +# %i : 8 hexadecimal digits of cpu0 current eip +# %e : 1 character event type ('i'nfo, 'd'ebug, 'p'anic, 'e'rror) +# %d : 5 characters string of the device, between brackets +# +# Default : %t%e%d +# Examples: +# logprefix: %t-%e-@%i-%d +# logprefix: %i%e%d +#======================================================================= +#logprefix: %t%e%d + +#======================================================================= +# LOG CONTROLS +# +# Bochs now has four severity levels for event logging. +# panic: cannot proceed. If you choose to continue after a panic, +# don't be surprised if you get strange behavior or crashes. +# error: something went wrong, but it is probably safe to continue the +# simulation. +# info: interesting or useful messages. +# debug: messages useful only when debugging the code. This may +# spit out thousands per second. +# +# For events of each level, you can choose to crash, report, or ignore. +# TODO: allow choice based on the facility: e.g. crash on panics from +# everything except the cdrom, and only report those. +# +# If you are experiencing many panics, it can be helpful to change +# the panic action to report instead of fatal. However, be aware +# that anything executed after a panic is uncharted territory and can +# cause bochs to become unstable. The panic is a "graceful exit," so +# if you disable it you may get a spectacular disaster instead. +#======================================================================= +panic: action=ask +error: action=report +info: action=report +debug: action=ignore + +#======================================================================= +# DEBUGGER_LOG: +# Give the path of the log file you'd like Bochs to log debugger output. +# If you really don't want it, make it /dev/null or '-'. :^( +# +# Examples: +# debugger_log: ./debugger.out +#======================================================================= +#debugger_log: /dev/null +#debugger_log: debugger.out +debugger_log: - + +#======================================================================= +# com1: +# This defines a serial (COM) port. You can specify a device to use as com1. +# This can be a real serial line, or a pty. To use a pty (under X/Unix), +# create two windows (xterms, usually). One of them will run bochs, and the +# other will act as com1. Find out the tty the com1 window using the `tty' +# command, and use that as the `dev' parameter. Then do `sleep 1000000' in +# the com1 window to keep the shell from messing with things, and run bochs in +# the other window. Serial I/O to com1 (port 0x3f8) will all go to the other +# window. +#======================================================================= +#com1: enabled=1, dev=/dev/ttyp9 +#com1: enabled=1, dev=/tmp/serial.log + + +#======================================================================= +# PARPORT1: +# This defines a parallel (printer) port. When turned on and an output file is +# defined the emulated printer port sends characters printed by the guest OS +# into the output file. On some platforms a device filename can be used to +# send the data to the real parallel port (e.g. "/dev/lp0" on Linux, "lpt1" on +# win32 platforms). +# +# Examples: +# parport1: enabled=1, file="parport.out" +# parport1: enabled=1, file="/dev/lp0" +# parport1: enabled=0 +#======================================================================= +parport1: enabled=1, file="parport.out" + +#======================================================================= +# SB16: +# This defines the SB16 sound emulation. It can have several of the +# following properties. +# All properties are in the format sb16: property=value +# midi: The filename is where the midi data is sent. This can be a +# device or just a file if you want to record the midi data. +# midimode: +# 0=no data +# 1=output to device (system dependent. midi denotes the device driver) +# 2=SMF file output, including headers +# 3=output the midi data stream to the file (no midi headers and no +# delta times, just command and data bytes) +# wave: This is the device/file where wave output is stored +# wavemode: +# 0=no data +# 1=output to device (system dependent. wave denotes the device driver) +# 2=VOC file output, incl. headers +# 3=output the raw wave stream to the file +# log: The file to write the sb16 emulator messages to. +# loglevel: +# 0=no log +# 1=only midi program and bank changes +# 2=severe errors +# 3=all errors +# 4=all errors plus all port accesses +# 5=all errors and port accesses plus a lot of extra info +# dmatimer: +# microseconds per second for a DMA cycle. Make it smaller to fix +# non-continous sound. 750000 is usually a good value. This needs a +# reasonably correct setting for IPS. +# +# For an example look at the next line: +#======================================================================= + +#sb16: midimode=1, midi=/dev/midi00, wavemode=1, wave=/dev/dsp, loglevel=2, log=sb16.log, dmatimer=600000 + +#======================================================================= +# VGA_UPDATE_INTERVAL: +# Video memory is scanned for updates and screen updated every so many +# virtual seconds. The default is 300000, about 3Hz. This is generally +# plenty. Keep in mind that you must tweak the 'ips:' directive +# to be as close to the number of emulated instructions-per-second +# your workstation can do, for this to be accurate. +# +# Examples: +# vga_update_interval: 250000 +#======================================================================= +vga_update_interval: 300000 + +# using for Winstone '98 tests +#vga_update_interval: 100000 + +#======================================================================= +# KEYBOARD_SERIAL_DELAY: +# Approximate time in microseconds that it takes one character to +# be transfered from the keyboard to controller over the serial path. +# Examples: +# keyboard_serial_delay: 200 +#======================================================================= +keyboard_serial_delay: 250 + +#======================================================================= +# KEYBOARD_PASTE_DELAY: +# Approximate time in microseconds between attempts to paste +# characters to the keyboard controller. This leaves time for the +# guest os to deal with the flow of characters. The ideal setting +# depends on how your operating system processes characters. The +# default of 100000 usec (.1 seconds) was chosen because it works +# consistently in Windows. +# +# If your OS is losing characters during a paste, increase the paste +# delay until it stops losing characters. +# +# Examples: +# keyboard_paste_delay: 100000 +#======================================================================= +keyboard_paste_delay: 100000 + +#======================================================================= +# FLOPPY_COMMAND_DELAY: +# Time in microseconds to wait before completing some floppy commands +# such as read/write/seek/etc, which normally have a delay associated. +# I had this hardwired to 50,000 before. +# +# Examples: +# floppy_command_delay: 50000 +#======================================================================= +floppy_command_delay: 500 + +#======================================================================= +# IPS: +# Emulated Instructions Per Second. This is the number of IPS that bochs +# is capable of running on your machine. Read the note in config.h +# on how to find this. Make sure to recompile after. +# +# IPS is used to calibrate many time-dependent events within the bochs +# simulation. For example, changing IPS affects the frequency of VGA +# updates, the duration of time before a key starts to autorepeat, and +# the measurement of BogoMips and other benchmarks. +# +# Examples: +# Machine Mips +# ________________________________________________________________ +# 650Mhz Athlon K-7 with Linux 2.4.4/egcs-2.91.66 2 to 2.5 Mips +# 400Mhz Pentium II with Linux 2.0.36/egcs-1.0.3 1 to 1.8 Mips +# 166Mhz 64bit Sparc with Solaris 2.x approx 0.75 Mips +# 200Mhz Pentium with Linux 2.x approx 0.5 Mips +# +#======================================================================= +ips: 1000000 + +#======================================================================= +# PIT: +# The PIT is the programmable interval timer. It has an option that tries to +# keep the PIT in sync with real time. This feature is still experimental, +# but it may be useful if you want to prevent Bochs from running too fast, for +# example a DOS video game. Be aware that with the realtime pit option, your +# simulation will not be repeatable; this can a problem if you are debugging. +#======================================================================= +#pit: realtime=1 + +#======================================================================= +# mouse: Not used in any of the GUI specific modules, but the option +# bx_options.mouse_enabled is set to this value. The idea, +# is that the GUI code should not generate mouse events when +# not enabled. The hardware emualation itself is not disabled +# by this. This is to facilitate deterministic runs of bochs. +# +# Examples: +# mouse: enabled=1 +# mouse: enabled=0 +# +# I wouldn't recommend enabling the mouse by default, unless you have a +# really good reason to do so. +#======================================================================= +mouse: enabled=0 + +#======================================================================= +# private_colormap: Request that the GUI create and use it's own +# non-shared colormap. This colormap will be used +# when in the bochs window. If not enabled, a +# shared colormap scheme may be used. Not implemented +# on all GUI's. +# +# Examples: +# private_colormap: enabled=1 +# private_colormap: enabled=0 +#======================================================================= +private_colormap: enabled=0 + +#======================================================================= +# fullscreen: ONLY IMPLEMENTED ON AMIGA +# Request that Bochs occupy the entire screen instead of a +# window. +# +# Examples: +# fullscreen: enabled=0 +# fullscreen: enabled=1 +#======================================================================= +fullscreen: enabled=0 +screenmode: name="sample" + +#======================================================================= +# ne2k: NE2000 compatible ethernet adapter +# +# Examples: +# ne2k: ioaddr=IOADDR, irq=IRQ, mac=MACADDR, ethmod=MODULE, ethdev=DEVICE, script=SCRIPT +# +# ioaddr, irq: You probably won't need to change ioaddr and irq, unless there +# are IRQ conflicts. +# +# mac: The MAC address MUST NOT match the address of any machine on the net. +# Also, the first byte must be an even number (bit 0 set means a multicast +# address), and you cannot use ff:ff:ff:ff:ff:ff because that's the broadcast +# address. For the ethertap module, you must use fe:fd:00:00:00:01. There may +# be other restrictions too. To be safe, just use the b0:c4... address. +# +# ethdev: The ethdev value is the name of the network interface on your host +# platform. On UNIX machines, you can get the name by running ifconfig. On +# Windows machines, you must run niclist to get the name of the ethdev. +# Niclist source code is in misc/niclist.c and it is included in Windows +# binary releases. +# +# script: The script value is optionnal, and is the name of a script that +# is executed after bochs initialize the network interface. You can use +# this script to configure this network interface, or enable masquerading. +# This is mainly useful for the tun/tap devices that only exist during +# Bochs execution. The network interface name is supplied to the script +# as first parameter +#======================================================================= +# ne2k: ioaddr=0x280, irq=9, mac=b0:c4:20:00:00:00, ethmod=fbsd, ethdev=xl0 +# ne2k: ioaddr=0x280, irq=9, mac=b0:c4:20:00:00:00, ethmod=linux, ethdev=eth0 +# ne2k: ioaddr=0x280, irq=9, mac=b0:c4:20:00:00:01, ethmod=win32, ethdev=MYCARD +# ne2k: ioaddr=0x280, irq=9, mac=fe:fd:00:00:00:01, ethmod=tap, ethdev=tap0 +# ne2k: ioaddr=0x280, irq=9, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=tun0, script=./ifup.tun +# ne2k: ioaddr=0x280, irq=9, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=tun0 + +# Pseudo NIC adaptor. The way bochs is structured at the moment means +# that you need to enable ne2k support in order to compile in any of +# the networking code. +pnic: ioaddr=0xdc00, irq=11, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=tun1, script=./ifup.tun + +#======================================================================= +# KEYBOARD_MAPPING: +# This enables a remap of a physical localized keyboard to a +# virtualized us keyboard, as the PC architecture expects. +# If enabled, the keymap file must be specified. +# +# Examples: +# keyboard_mapping: enabled=1, map=gui/keymaps/x11-pc-de.map +#======================================================================= +keyboard_mapping: enabled=0, map= + +#======================================================================= +# KEYBOARD_TYPE: +# Type of keyboard return by a "identify keyboard" command to the +# keyboard controler. It must be one of "xt", "at" or "mf". +# Defaults to "mf". It should be ok for almost everybody. A known +# exception is french macs, that do have a "at"-like keyboard. +# +# Examples: +# keyboard_type: mf +#======================================================================= +#keyboard_type: mf + +#======================================================================= +# USER_SHORTCUT: +# This defines the keyboard shortcut to be sent when you press the "user" +# button in the headerbar. The shortcut string can be a combination of +# these key names: "alt", "ctrl", "del", "esc", "f1", "f4", "tab", "win". +# Up to 3 keys can be pressed at a time. +# +# Example: +# user_shortcut: keys=ctrlaltdel +#======================================================================= +user_shortcut: keys=ctrlaltdel + +#======================================================================= +# other stuff +#======================================================================= +magic_break: enabled=1 + +#load32bitOSImage: os=nullkernel, path=../kernel.img, iolog=../vga_io.log +#load32bitOSImage: os=linux, path=../linux.img, iolog=../vga_io.log, initrd=../initrd.img +i440fxsupport: enabled=1 +#time0: 938581955 + +#======================================================================= +# for Macintosh, use the style of pathnames in the following +# examples. +# +# vgaromimage: :bios:VGABIOS-elpin-2.20 +# romimage: file=:bios:BIOS-bochs-981222a, address=0xf0000 +# floppya: 1_44=[fd:], status=inserted +#======================================================================= + diff --git a/contrib/bochs/ifup.tun b/contrib/bochs/ifup.tun new file mode 100755 index 0000000..8e2ede2 --- /dev/null +++ b/contrib/bochs/ifup.tun @@ -0,0 +1,21 @@ +#!/bin/sh + +SCRIPT=$0 +INTERFACE=$1 + +if [ `id -u` != 0 ]; then + echo "" + echo "Enter root password for configuring network interface $INTERFACE" + echo "(To avoid this prompt, make the script $SCRIPT setuid-root)" + /bin/su -c "$SCRIPT $INTERFACE" || exit 1 + exit 0 +fi + +/sbin/ifconfig $INTERFACE 10.254.254.2 netmask 255.255.255.252 + +# Force dhcpd to notice the new network interface +if [ -x /etc/init.d/dhcpd ]; then + /etc/init.d/dhcpd reload # Redhat +elif [ -x /etc/init.d/dhcp ]; then + /etc/init.d/dhcp restart # Debian +fi diff --git a/contrib/bochs/serial-console b/contrib/bochs/serial-console new file mode 100755 index 0000000..3ea877c --- /dev/null +++ b/contrib/bochs/serial-console @@ -0,0 +1,278 @@ +#!/usr/bin/perl -w + +=head1 NAME + +serial-console + +=head1 SYNOPSIS + +serial-console [options] + +Options: + + -h,--help Display brief help message + -v,--verbose Increase verbosity + -q,--quiet Decrease verbosity + -l,--log FILE Log output to file + -r,--rcfile FILE Modify specified bochsrc file + +=head1 DESCRIPTION + +C<serial-console> provides a virtual serial console for use with +Bochs. Running C<serial-console> creates a pseudo-tty. The master +side of this pty is made available to the user for interaction; the +slave device is written to the Bochs configuration file +(C<bochsrc.txt>) for use by a subsequent Bochs session. + +=head1 EXAMPLES + +=over 4 + +=item C<serial-console> + +Create a virtual serial console for Bochs, modify C<bochsrc.txt> +appropriately. + +=item C<serial-console -r ../.bochsrc -l serial.log> + +Create a virtual serial console for Bochs, modify C<../.bochsrc> +appropriately, log output to C<serial.log>. + +=back + +=head1 INVOCATION + +Before starting Bochs, run C<serial-console> in a different session +(e.g. a different xterm window). When you subsequently start Bochs, +anything that the emulated machine writes to its serial port will +appear in the window running C<serial-console>, and anything typed in +the C<serial-console> window will arrive on the emulated machine's +serial port. + +You do B<not> need to rerun C<serial-console> afresh for each Bochs +session. + +=head1 OPTIONS + +=over 4 + +=item B<-l,--log FILE> + +Log all output (i.e. everything that is printed in the +C<serial-console> window) to the specified file. + +=item B<-r,--rcfile FILE> + +Modify the specified bochsrc file. The file will be updated to +contain the path to the slave side of the psuedo tty that we create. +The original file will be restored when C<serial-console> exits. The +default is to modify the file C<bochsrc.txt> in the current directory. + +To avoid modifying any bochsrc file, use C<--norcfile>. + +=back + +=cut + +use IO::Pty; +use IO::Select; +use File::Spec::Functions qw ( :ALL ); +use Getopt::Long; +use Pod::Usage; +use POSIX qw ( :termios_h ); +use strict; +use warnings; + +my $o; +my $restore_file = {}; +my $restore_termios; +use constant BLOCKSIZE => 8192; + +############################################################################## +# +# Parse command line options into options hash ($o) +# +# $o = parse_opts(); + +sub parse_opts { + # $o is the hash that will hold the options + my $o = { + verbosity => 1, + rcfile => 'bochsrc.txt', + }; + # Special handlers for some options + my $opt_handlers = { + verbose => sub { $o->{verbosity}++; }, + quiet => sub { $o->{verbosity}--; }, + help => sub { pod2usage(1); }, + norcfile => sub { delete $o->{rcfile}; }, + }; + # Merge handlers into main options hash (so that Getopt::Long can find them) + $o->{$_} = $opt_handlers->{$_} foreach keys %$opt_handlers; + # Option specifiers for Getopt::Long + my @optspec = ( 'help|h|?', + 'quiet|q+', + 'verbose|v+', + 'log|l=s', + 'rcfile|r=s', + 'norcfile', + ); + # Do option parsing + Getopt::Long::Configure ( 'bundling' ); + pod2usage("Error parsing command-line options") unless GetOptions ( + $o, @optspec ); + # Clean up $o by removing the handlers + delete $o->{$_} foreach keys %$opt_handlers; + return $o; +} + +############################################################################## +# +# Modify bochsrc file + +sub patch_bochsrc { + my $active = shift; + my $pty = shift; + + # Rename active file to backup file + ( my $vol, my $dir, my $file ) = splitpath ( $active ); + $file = '.'.$file.".serial-console"; + my $backup = catpath ( $vol, $dir, $file ); + rename $active, $backup + or die "Could not back up $active to $backup: $!\n"; + + # Derive line to be inserted + my $patch = "com1: enabled=1, dev=$pty\n"; + + # Modify file + open my $old, "<$backup" or die "Could not open $backup: $!\n"; + open my $new, ">$active" or die "Could not open $active: $!\n"; + print $new <<"EOF"; +################################################## +# +# This file has been modified by serial-console. +# +# Do not modify this file; it will be erased when +# serial-console (pid $$) exits and will be +# replaced with the backup copy held in +# $backup. +# +################################################## + + +EOF + my $patched; + while ( my $line = <$old> ) { + if ( $line =~ /^\s*\#?\s*com1:\s*\S/ ) { + if ( ! $patched ) { + $line = $patch; + $patched = 1; + } else { + $line = '# '.$line unless $line =~ /^\s*\#/; + } + } + print $new $line; + } + print $new $patch unless $patched; + close $old; + close $new; + + return $backup; +} + +############################################################################## +# +# Attach/detach message printing and terminal settings + +sub bochs_attached { + print STDERR "Bochs attached.\n\n\n" + if $o->{verbosity} >= 1; +} + +sub bochs_detached { + print STDERR "\n\nWaiting for bochs to attach...\n" + if $o->{verbosity} >= 1; +} + +############################################################################## +# +# Main program + +$o = parse_opts(); +pod2usage(1) if @ARGV; + +# Catch signals +my $sigdie = sub { die "Exiting via signal\n"; }; +$SIG{INT} = $sigdie; + +# Create Pty, close slave side +my $pty = IO::Pty->new(); +$pty->close_slave(); +$pty->set_raw(); +print STDERR "Slave pty is ".$pty->ttyname."\n" if $o->{verbosity} >= 1; + +# Open logfile +my $log; +if ( $o->{log} ) { + open $log, ">$o->{log}" or die "Could not open $o->{log}: $!\n"; +} + +# Set up terminal +my $termios; +if ( -t STDIN ) { + $termios = POSIX::Termios->new; + $restore_termios = POSIX::Termios->new; + $termios->getattr ( fileno(STDIN) ); + $restore_termios->getattr ( fileno(STDIN) ); + $termios->setlflag ( $termios->getlflag & + ~(ICANON) & ~(ECHO) ); + $termios->setattr ( fileno(STDIN), TCSANOW ); +} + +# Modify bochsrc file +$restore_file = { $o->{rcfile} => + patch_bochsrc ( $o->{rcfile}, $pty->ttyname ) } + if $o->{rcfile}; + +# Start character shunt +my $attached = 1; +my $select = IO::Select->new ( \*STDIN, $pty ); +while ( 1 ) { + my %can_read = map { $_ => 1 } + $select->can_read ( $attached ? undef : 1 ); + if ( $can_read{\*STDIN} ) { + sysread ( STDIN, my $data, BLOCKSIZE ) + or die "Cannot read from STDIN: $!\n"; + $pty->syswrite ( $data ); + } + if ( $can_read{$pty} ) { + if ( $pty->sysread ( my $data, BLOCKSIZE ) ) { + # Actual data available + bochs_attached() if $attached == 0; + $attached = 1; + syswrite ( STDOUT, $data ); + $log->syswrite ( $data ) if $log; + } else { + # No data available but select() says we can read. This almost + # certainly indicates that nothing is attached to the slave. + bochs_detached() if $attached == 1; + $attached = 0; + sleep ( 1 ); + } + } else { + bochs_attached() if $attached == 0; + $attached = 1; + } +} + +END { + # Restore bochsrc file if applicable + if ( ( my $orig_file, my $backup_file ) = %$restore_file ) { + unlink $orig_file; + rename $backup_file, $orig_file; + } + # Restore terminal settings if applicable + if ( $restore_termios ) { + $restore_termios->setattr ( fileno(STDIN), TCSANOW ); + } +} diff --git a/contrib/bochs/serial-console.1 b/contrib/bochs/serial-console.1 new file mode 100644 index 0000000..210de55 --- /dev/null +++ b/contrib/bochs/serial-console.1 @@ -0,0 +1,191 @@ +.\" Automatically generated by Pod::Man v1.34, Pod::Parser v1.13 +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sh \" Subsection heading +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. | will give a +.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to +.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' +.\" expand to `' in nroff, nothing in troff, for use with C<>. +.tr \(*W-|\(bv\*(Tr +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.\" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.hy 0 +.if n .na +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "SERIAL-CONSOLE 1" +.TH SERIAL-CONSOLE 1 "2004-03-10" "perl v5.8.0" "User Contributed Perl Documentation" +.SH "NAME" +serial\-console +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +serial-console [options] +.PP +Options: +.PP +.Vb 5 +\& -h,--help Display brief help message +\& -v,--verbose Increase verbosity +\& -q,--quiet Decrease verbosity +\& -l,--log FILE Log output to file +\& -r,--rcfile FILE Modify specified bochsrc file +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\f(CW\*(C`serial\-console\*(C'\fR provides a virtual serial console for use with +Bochs. Running \f(CW\*(C`serial\-console\*(C'\fR creates a pseudo\-tty. The master +side of this pty is made available to the user for interaction; the +slave device is written to the Bochs configuration file +(\f(CW\*(C`bochsrc.txt\*(C'\fR) for use by a subsequent Bochs session. +.SH "EXAMPLES" +.IX Header "EXAMPLES" +.ie n .IP """serial\-console""" 4 +.el .IP "\f(CWserial\-console\fR" 4 +.IX Item "serial-console" +Create a virtual serial console for Bochs, modify \f(CW\*(C`bochsrc.txt\*(C'\fR +appropriately. +.ie n .IP """serial\-console \-r ../.bochsrc \-l serial.log""" 4 +.el .IP "\f(CWserial\-console \-r ../.bochsrc \-l serial.log\fR" 4 +.IX Item "serial-console -r ../.bochsrc -l serial.log" +Create a virtual serial console for Bochs, modify \f(CW\*(C`../.bochsrc\*(C'\fR +appropriately, log output to \f(CW\*(C`serial.log\*(C'\fR. +.SH "INVOCATION" +.IX Header "INVOCATION" +Before starting Bochs, run \f(CW\*(C`serial\-console\*(C'\fR in a different session +(e.g. a different xterm window). When you subsequently start Bochs, +anything that the emulated machine writes to its serial port will +appear in the window running \f(CW\*(C`serial\-console\*(C'\fR, and anything typed in +the \f(CW\*(C`serial\-console\*(C'\fR window will arrive on the emulated machine's +serial port. +.PP +You do \fBnot\fR need to rerun \f(CW\*(C`serial\-console\*(C'\fR afresh for each Bochs +session. +.SH "OPTIONS" +.IX Header "OPTIONS" +.IP "\fB\-l,\-\-log \s-1FILE\s0\fR" 4 +.IX Item "-l,--log FILE" +Log all output (i.e. everything that is printed in the +\&\f(CW\*(C`serial\-console\*(C'\fR window) to the specified file. +.IP "\fB\-r,\-\-rcfile \s-1FILE\s0\fR" 4 +.IX Item "-r,--rcfile FILE" +Modify the specified bochsrc file. The file will be updated to +contain the path to the slave side of the psuedo tty that we create. +The original file will be restored when \f(CW\*(C`serial\-console\*(C'\fR exits. The +default is to modify the file \f(CW\*(C`bochsrc.txt\*(C'\fR in the current directory. +.Sp +To avoid modifying any bochsrc file, use \f(CW\*(C`\-\-norcfile\*(C'\fR. diff --git a/contrib/bootptodhcp/bootptodhcp.pl b/contrib/bootptodhcp/bootptodhcp.pl new file mode 100755 index 0000000..c8d6465 --- /dev/null +++ b/contrib/bootptodhcp/bootptodhcp.pl @@ -0,0 +1,42 @@ +#!/usr/bin/perl -w +# +# Quick hack to convert /etc/bootptab to format required by ISC DHCPD +# This only outputs the fixed hosts portion of the config file +# You still have to provide the global options and the subnet scoping +# +# Turn $useipaddr on if you prefer to use IP addresses in the config file +# I run DNS so I prefer domain names +$useipaddr = 0; +# This will be appended to get the FQDN unless the hostname is already FQDN +$domainname = "ken.com.au"; +$tftpdir = "/tftpdir/"; +open(B, "/etc/bootptab") or die "/etc/bootptab: $!\n"; +while(<B>) { + if (/^[^a-z]/) { + $prevline = $_; + next; + } + chomp($_); + ($hostname, @tags) = split(/:/, $_, 5); + ($fqdn = $hostname) .= ".$domainname" unless($hostname =~ /\./); + ($macaddr) = grep(/^ha=/, @tags); + $macaddr =~ s/ha=//; + $macaddr =~ s/(..)(..)(..)(..)(..)(..)/$1:$2:$3:$4:$5:$6/g; + ($ipaddr) = grep(/^ip=/, @tags); + $ipaddr =~ s/ip=//; + ($bootfile) = grep(/^bf=/, @tags); + $bootfile =~ s/bf=//; + $bootfile = $tftpdir . $bootfile; +# I have a comment line above most entries and I like to carry this over + print $prevline if ($prevline =~ /^#/); + $address = $useipaddr ? $ipaddr : $fqdn; + print <<EOF + host $hostname { + hardware ethernet $macaddr; + fixed-address $address; + filename "$bootfile"; + } +EOF +; + $prevline = $_; +} diff --git a/contrib/compressor/COPYING b/contrib/compressor/COPYING new file mode 100644 index 0000000..e574f7c --- /dev/null +++ b/contrib/compressor/COPYING @@ -0,0 +1,23 @@ +The compression code as implemented in "lzhuf.c" was taken from a BBS +program written by Joachim Schurig <jschurig@zedat.fu-berlin.de>. He +states that the code can be used freely for programs that are covered +by a "freeware" license. This probably includes both BSD style +licenses and the GPL. + +The code in "loader.asm" is a reimplementation of the uncompressor. It +has been written from scratch and is hereby placed under the +conditions of the GNU General Public License (GPL). The algorithm is +outlined in "algorithm.doc". + +Thus, there are no copyright problems with using this code, but there +still might be difficulties with software patents. These patents are +not legal in most parts of the world, but if you live in a country +that honors software patents then you should verify that using these +algorithms is legally permitted. Unless you are absolutely sure, that +there are no legal obstacles, you should use the code for educational +purposes only (this assumes that your educational institution is +exempted from patent laws). The author cannot be held responsible for +using the program code in violation of applicable local laws. + +If you are aware of patents that might affect the legality of using +the code in some parts of the world, please let me know. diff --git a/contrib/compressor/algorithm.doc b/contrib/compressor/algorithm.doc new file mode 100644 index 0000000..74a7646 --- /dev/null +++ b/contrib/compressor/algorithm.doc @@ -0,0 +1,58 @@ +The compressor achieves an average compression rate of 60% of the +original size which is on par with "gzip". It seems that you cannot do +much better for compressing compiled binaries. This means that the +break even point for using compressed images is reached, once the +uncompressed size approaches 1.5kB. We can stuff more than 12kB into +an 8kB EPROM and more than 25kB into an 16kB EPROM. As there is only +32kB of RAM for both the uncompressed image and its BSS area, this +means that 32kB EPROMs will hardly ever be required. + +The compression algorithm uses a 4kB ring buffer for buffering the +uncompressed data. Before compression starts, the ring buffer is +filled with spaces (ASCII character 0x20). The algorithm tries to +find repeated input sequences of a maximum length of 60 bytes. All +256 different input bytes plus the 58 (60 minus a threshold of 2) +possible repeat lengths form a set of 314 symbols. These symbols are +adaptively Huffman encoded. The algorithm starts out with a Huffmann +tree that assigns equal code lengths to each of the 314 symbols +(slightly favoring the repeat symbols over symbols for regular input +characters), but it will be changed whenever the frequency of any of +the symbols changes. Frequency counts are kept in 16bit words until +the total number of compressed codes totals 2^15. Then, all frequency +counts will be halfed (rounding to the bigger number). For unrepeated +characters (symbols 0..255) the Huffman code is written to the output +stream. For repeated characters the Huffmann code, which denotes the +length of the repeated character sequence, is written out and then the +index in the ring buffer is computed. From this index, the algorithm +computes the offset relative to the current index into the ring +buffer. Thus, for typical input data, one would expect that short to +medium range offsets are more frequent than extremely short or medium +range to long range offsets. Thus the 12bit (for a 4kB buffer) offset +value is statically Huffman encoded using a precomputed Huffman tree +that favors those offset values that are deemed to be more +frequent. The Huffman encoded offset is written to the output data +stream, directly following the code that determines the length of +repeated characters. + +This algorithm, as implemented in the C example code, looks very good +and its operating parameters are already well optimized. This also +explains why it achieves compression ratios comparable with +"gzip". Depending on the input data, it sometimes excells considerably +beyond what "gzip -9" does, but this phenomenon does not appear to be +typical. There are some flaws with the algorithm, such as the limited +buffer sizes, the adaptive Huffman tree which takes very long to +change, if the input characters experience a sudden change in +distribution, and the static Huffman tree for encoding offsets into +the buffer. The slow changes of the adaptive Huffman tree are +partially counteracted by artifically keeping a 16bit precision for +the frequency counts, but this does not come into play until 32kB of +compressed data is output, so it does not have any impact on our use +for "etherboot", because the BOOT Prom does not support uncompressed +data of more then 32kB (c.f. doc/spec.doc). + +Nonetheless, these problems do not seem to affect compression of +compiled programs very much. Mixing object code with English text, +would not work too well though, and the algorithm should be reset in +between. Actually, we might gain a little improvement, if text and +data segments were compressed individually, but I have not +experimented with this option, yet. diff --git a/contrib/compressor/loader.h b/contrib/compressor/loader.h new file mode 100644 index 0000000..20fa9af --- /dev/null +++ b/contrib/compressor/loader.h @@ -0,0 +1,14 @@ +/* Do not change these values unless you really know what you are doing; + the pre-computed lookup tables rely on the buffer size being 4kB or + smaller. The buffer size must be a power of two. The lookahead size has + to fit into 6 bits. If you change any of these numbers, you will also + have to adjust the decompressor accordingly. + */ + +#define BUFSZ 4096 +#define LOOKAHEAD 60 +#define THRESHOLD 2 +#define NCHAR (256+LOOKAHEAD-THRESHOLD) +#define TABLESZ (NCHAR+NCHAR-1) +#define NIL ((unsigned short)-1) + diff --git a/contrib/compressor/lzhuf.c b/contrib/compressor/lzhuf.c new file mode 100644 index 0000000..ea65b5e --- /dev/null +++ b/contrib/compressor/lzhuf.c @@ -0,0 +1,764 @@ +/* +---------------------------------------------------------------------------- + +M. LZHuf Compression + +This is the LZHuf compression algorithm as used in DPBOX and F6FBB. + +---------------------------------------------------------------------------- +*/ +/************************************************************** + lzhuf.c + written by Haruyasu Yoshizaki 11/20/1988 + some minor changes 4/6/1989 + comments translated by Haruhiko Okumura 4/7/1989 + + minor beautifications and adjustments for compiling under Linux + by Markus Gutschke <gutschk@math.uni-muenster.de> + 1997-01-27 + + Modifications to allow use as a filter by Ken Yap <ken_yap@users.sourceforge.net>. + 1997-07-01 + + Small mod to cope with running on big-endian machines + by Jim Hague <jim.hague@acm.org) + 1998-02-06 + + Make compression statistics report shorter + by Ken Yap <ken_yap@users.sourceforge.net>. + 2001-04-25 +**************************************************************/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#ifndef VERBOSE +#define Fprintf(x) +#define wterr 0 +#else +#define Fprintf(x) fprintf x +#if defined(ENCODE) || defined(DECODE) +static char wterr[] = "Can't write."; +#ifdef ENCODE +static unsigned long int codesize = 0; +#endif +static unsigned long int printcount = 0; +#endif +#endif + +#ifndef MAIN +extern +#endif +FILE *infile, *outfile; + +#if defined(ENCODE) || defined(DECODE) +static unsigned long int textsize = 0; + +static __inline__ void Error(char *message) +{ + Fprintf((stderr, "\n%s\n", message)); + exit(EXIT_FAILURE); +} + +/* These will be a complete waste of time on a lo-endian */ +/* system, but it only gets done once so WTF. */ +static unsigned long i86ul_to_host(unsigned long ul) +{ + unsigned long res = 0; + int i; + union + { + unsigned char c[4]; + unsigned long ul; + } u; + + u.ul = ul; + for (i = 3; i >= 0; i--) + res = (res << 8) + u.c[i]; + return res; +} + +static unsigned long host_to_i86ul(unsigned long ul) +{ + int i; + union + { + unsigned char c[4]; + unsigned long ul; + } u; + + for (i = 0; i < 4; i++) + { + u.c[i] = ul & 0xff; + ul >>= 8; + } + return u.ul; +} +#endif + +/********** LZSS compression **********/ + +#define N 4096 /* buffer size */ +/* Attention: When using this file for f6fbb-type compressed data exchange, + set N to 2048 ! (DL8HBS) */ +#define F 60 /* lookahead buffer size */ +#define THRESHOLD 2 +#define NIL N /* leaf of tree */ + +#if defined(ENCODE) || defined(DECODE) +static unsigned char + text_buf[N + F - 1]; +#endif + +#ifdef ENCODE +static int match_position, match_length, + lson[N + 1], rson[N + 257], dad[N + 1]; + +static void InitTree(void) /* initialize trees */ +{ + int i; + + for (i = N + 1; i <= N + 256; i++) + rson[i] = NIL; /* root */ + for (i = 0; i < N; i++) + dad[i] = NIL; /* node */ +} + +static void InsertNode(int r) /* insert to tree */ +{ + int i, p, cmp; + unsigned char *key; + unsigned c; + + cmp = 1; + key = &text_buf[r]; + p = N + 1 + key[0]; + rson[r] = lson[r] = NIL; + match_length = 0; + for ( ; ; ) { + if (cmp >= 0) { + if (rson[p] != NIL) + p = rson[p]; + else { + rson[p] = r; + dad[r] = p; + return; + } + } else { + if (lson[p] != NIL) + p = lson[p]; + else { + lson[p] = r; + dad[r] = p; + return; + } + } + for (i = 1; i < F; i++) + if ((cmp = key[i] - text_buf[p + i]) != 0) + break; + if (i > THRESHOLD) { + if (i > match_length) { + match_position = ((r - p) & (N - 1)) - 1; + if ((match_length = i) >= F) + break; + } + if (i == match_length) { + if ((c = ((r - p) & (N - 1)) - 1) < match_position) { + match_position = c; + } + } + } + } + dad[r] = dad[p]; + lson[r] = lson[p]; + rson[r] = rson[p]; + dad[lson[p]] = r; + dad[rson[p]] = r; + if (rson[dad[p]] == p) + rson[dad[p]] = r; + else + lson[dad[p]] = r; + dad[p] = NIL; /* remove p */ +} + +static void DeleteNode(int p) /* remove from tree */ +{ + int q; + + if (dad[p] == NIL) + return; /* not registered */ + if (rson[p] == NIL) + q = lson[p]; + else + if (lson[p] == NIL) + q = rson[p]; + else { + q = lson[p]; + if (rson[q] != NIL) { + do { + q = rson[q]; + } while (rson[q] != NIL); + rson[dad[q]] = lson[q]; + dad[lson[q]] = dad[q]; + lson[q] = lson[p]; + dad[lson[p]] = q; + } + rson[q] = rson[p]; + dad[rson[p]] = q; + } + dad[q] = dad[p]; + if (rson[dad[p]] == p) + rson[dad[p]] = q; + else + lson[dad[p]] = q; + dad[p] = NIL; +} +#endif + +/* Huffman coding */ + +#define N_CHAR (256 - THRESHOLD + F) + /* kinds of characters (character code = 0..N_CHAR-1) */ +#define T (N_CHAR * 2 - 1) /* size of table */ +#define R (T - 1) /* position of root */ +#define MAX_FREQ 0x8000 /* updates tree when the */ + /* root frequency comes to this value. */ +typedef unsigned char uchar; + +/* table for encoding and decoding the upper 6 bits of position */ + +/* for encoding */ + +#ifdef ENCODE +static uchar p_len[64] = { + 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 +}; + +static uchar p_code[64] = { + 0x00, 0x20, 0x30, 0x40, 0x50, 0x58, 0x60, 0x68, + 0x70, 0x78, 0x80, 0x88, 0x90, 0x94, 0x98, 0x9C, + 0xA0, 0xA4, 0xA8, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC, + 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, + 0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE, + 0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF +}; +#endif + +#ifdef DECODE +/* for decoding */ +static uchar d_code[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, + 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, + 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, + 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, + 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, + 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F, + 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, + 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, + 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, + 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, +}; + +static uchar d_len[256] = { + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, +}; +#endif + +#if defined(ENCODE) || defined(DECODE) +static unsigned freq[T + 1]; /* frequency table */ + +static int prnt[T + N_CHAR]; /* pointers to parent nodes, except for the */ + /* elements [T..T + N_CHAR - 1] which are used to get */ + /* the positions of leaves corresponding to the codes. */ + +static int son[T]; /* pointers to child nodes (son[], son[] + 1) */ +#endif + +#ifdef DECODE +static unsigned getbuf = 0; +static uchar getlen = 0; + +static int GetBit(void) /* get one bit */ +{ + int i; + + while (getlen <= 8) { + if ((i = getc(infile)) < 0) i = 0; + getbuf |= i << (8 - getlen); + getlen += 8; + } + i = getbuf; + getbuf <<= 1; + getlen--; + return ((signed short)i < 0); +} + +static int GetByte(void) /* get one byte */ +{ + unsigned short i; + + while (getlen <= 8) { + if ((signed short)(i = getc(infile)) < 0) i = 0; + getbuf |= i << (8 - getlen); + getlen += 8; + } + i = getbuf; + getbuf <<= 8; + getlen -= 8; + return i >> 8; +} +#endif + +#ifdef ENCODE +static unsigned putbuf = 0; +static uchar putlen = 0; + +static void Putcode(int l, unsigned c) /* output c bits of code */ +{ + putbuf |= c >> putlen; + if ((putlen += l) >= 8) { + if (putc(putbuf >> 8, outfile) == EOF) { + Error(wterr); + } + if ((putlen -= 8) >= 8) { + if (putc(putbuf, outfile) == EOF) { + Error(wterr); + } +#ifdef VERBOSE + codesize += 2; +#endif + putlen -= 8; + putbuf = c << (l - putlen); + } else { + putbuf <<= 8; +#ifdef VERBOSE + codesize++; +#endif + } + } +} +#endif + +/* initialization of tree */ + +#if defined(ENCODE) || defined(DECODE) +static void StartHuff(void) +{ + int i, j; + + for (i = 0; i < N_CHAR; i++) { + freq[i] = 1; + son[i] = i + T; + prnt[i + T] = i; + } + i = 0; j = N_CHAR; + while (j <= R) { + freq[j] = freq[i] + freq[i + 1]; + son[j] = i; + prnt[i] = prnt[i + 1] = j; + i += 2; j++; + } + freq[T] = 0xffff; + prnt[R] = 0; +} + +/* reconstruction of tree */ + +static void reconst(void) +{ + int i, j, k; + unsigned f, l; + + /* collect leaf nodes in the first half of the table */ + /* and replace the freq by (freq + 1) / 2. */ + j = 0; + for (i = 0; i < T; i++) { + if (son[i] >= T) { + freq[j] = (freq[i] + 1) / 2; + son[j] = son[i]; + j++; + } + } + /* begin constructing tree by connecting sons */ + for (i = 0, j = N_CHAR; j < T; i += 2, j++) { + k = i + 1; + f = freq[j] = freq[i] + freq[k]; + for (k = j - 1; f < freq[k]; k--); + k++; + l = (j - k) * 2; + memmove(&freq[k + 1], &freq[k], l); + freq[k] = f; + memmove(&son[k + 1], &son[k], l); + son[k] = i; + } + /* connect prnt */ + for (i = 0; i < T; i++) { + if ((k = son[i]) >= T) { + prnt[k] = i; + } else { + prnt[k] = prnt[k + 1] = i; + } + } +} + +/* increment frequency of given code by one, and update tree */ + +static void update(int c) +{ + int i, j, k, l; + + if (freq[R] == MAX_FREQ) { + reconst(); + } + c = prnt[c + T]; + do { + k = ++freq[c]; + + /* if the order is disturbed, exchange nodes */ + if (k > freq[l = c + 1]) { + while (k > freq[++l]); + l--; + freq[c] = freq[l]; + freq[l] = k; + + i = son[c]; + prnt[i] = l; + if (i < T) prnt[i + 1] = l; + + j = son[l]; + son[l] = i; + + prnt[j] = c; + if (j < T) prnt[j + 1] = c; + son[c] = j; + + c = l; + } + } while ((c = prnt[c]) != 0); /* repeat up to root */ +} +#endif + +#ifdef ENCODE +#if 0 +static unsigned code, len; +#endif + +static void EncodeChar(unsigned c) +{ + unsigned i; + int j, k; + + i = 0; + j = 0; + k = prnt[c + T]; + + /* travel from leaf to root */ + do { + i >>= 1; + + /* if node's address is odd-numbered, choose bigger brother node */ + if (k & 1) i += 0x8000; + + j++; + } while ((k = prnt[k]) != R); + Putcode(j, i); +#if 0 + code = i; + len = j; +#endif + update(c); +} + +static void EncodePosition(unsigned c) +{ + unsigned i; + + /* output upper 6 bits by table lookup */ + i = c >> 6; + Putcode(p_len[i], (unsigned)p_code[i] << 8); + + /* output lower 6 bits verbatim */ + Putcode(6, (c & 0x3f) << 10); +} + +static void EncodeEnd(void) +{ + if (putlen) { + if (putc(putbuf >> 8, outfile) == EOF) { + Error(wterr); + } +#ifdef VERBOSE + codesize++; +#endif + } +} +#endif + +#ifdef DECODE +static int DecodeChar(void) +{ + unsigned c; + + c = son[R]; + + /* travel from root to leaf, */ + /* choosing the smaller child node (son[]) if the read bit is 0, */ + /* the bigger (son[]+1} if 1 */ + while (c < T) { + c += GetBit(); + c = son[c]; + } + c -= T; + update(c); + return c; +} + +static int DecodePosition(void) +{ + unsigned i, j, c; + + /* recover upper 6 bits from table */ + i = GetByte(); + c = (unsigned)d_code[i] << 6; + j = d_len[i]; + + /* read lower 6 bits verbatim */ + j -= 2; + while (j--) { + i = (i << 1) + GetBit(); + } + return c | (i & 0x3f); +} +#endif + +#ifdef ENCODE +/* compression */ + +void Encode(void) /* compression */ +{ + int i, c, len, r, s, last_match_length; + unsigned long tw; + + fseek(infile, 0L, 2); + textsize = ftell(infile); +#ifdef VERBOSE + if ((signed long)textsize < 0) + Fprintf((stderr, "Errno: %d", errno)); +#endif + tw = host_to_i86ul(textsize); + if (fwrite(&tw, sizeof tw, 1, outfile) < 1) + Error(wterr); /* output size of text */ + if (textsize == 0) + return; + rewind(infile); + textsize = 0; /* rewind and re-read */ + StartHuff(); + InitTree(); + s = 0; + r = N - F; + for (i = s; i < r; i++) + text_buf[i] = ' '; + for (len = 0; len < F && (c = getc(infile)) != EOF; len++) + text_buf[r + len] = c; + textsize = len; + for (i = 1; i <= F; i++) + InsertNode(r - i); + InsertNode(r); + do { + if (match_length > len) + match_length = len; + if (match_length <= THRESHOLD) { + match_length = 1; + EncodeChar(text_buf[r]); + } else { + EncodeChar(255 - THRESHOLD + match_length); + EncodePosition(match_position); + } + last_match_length = match_length; + for (i = 0; i < last_match_length && + (c = getc(infile)) != EOF; i++) { + DeleteNode(s); + text_buf[s] = c; + if (s < F - 1) + text_buf[s + N] = c; + s = (s + 1) & (N - 1); + r = (r + 1) & (N - 1); + InsertNode(r); + } + if ((textsize += i) > printcount) { +#if defined(VERBOSE) && defined(EXTRAVERBOSE) + Fprintf((stderr, "%12ld\r", textsize)); +#endif + printcount += 1024; + } + while (i++ < last_match_length) { + DeleteNode(s); + s = (s + 1) & (N - 1); + r = (r + 1) & (N - 1); + if (--len) InsertNode(r); + } + } while (len > 0); + EncodeEnd(); +#ifdef LONG_REPORT + Fprintf((stderr, "input size %ld bytes\n", codesize)); + Fprintf((stderr, "output size %ld bytes\n", textsize)); + Fprintf((stderr, "input/output %.3f\n", (double)codesize / textsize)); +#else + Fprintf((stderr, "input/output = %ld/%ld = %.3f\n", codesize, textsize, + (double)codesize / textsize)); +#endif +} +#endif + +#ifdef DECODE +void Decode(void) /* recover */ +{ + int i, j, k, r, c; + unsigned long int count; + unsigned long tw; + + if (fread(&tw, sizeof tw, 1, infile) < 1) + Error("Can't read"); /* read size of text */ + textsize = i86ul_to_host(tw); + if (textsize == 0) + return; + StartHuff(); + for (i = 0; i < N - F; i++) + text_buf[i] = ' '; + r = N - F; + for (count = 0; count < textsize; ) { + c = DecodeChar(); + if (c < 256) { + if (putc(c, outfile) == EOF) { + Error(wterr); + } + text_buf[r++] = c; + r &= (N - 1); + count++; + } else { + i = (r - DecodePosition() - 1) & (N - 1); + j = c - 255 + THRESHOLD; + for (k = 0; k < j; k++) { + c = text_buf[(i + k) & (N - 1)]; + if (putc(c, outfile) == EOF) { + Error(wterr); + } + text_buf[r++] = c; + r &= (N - 1); + count++; + } + } + if (count > printcount) { +#if defined(VERBOSE) && defined(EXTRAVERBOSE) + Fprintf((stderr, "%12ld\r", count)); +#endif + printcount += 1024; + } + } + Fprintf((stderr, "%12ld\n", count)); +} +#endif + +#ifdef MAIN +int main(int argc, char *argv[]) +{ + char *s; + FILE *f; + int c; + + if (argc == 2) { + outfile = stdout; + if ((f = tmpfile()) == NULL) { + perror("tmpfile"); + return EXIT_FAILURE; + } + while ((c = getchar()) != EOF) + fputc(c, f); + rewind(infile = f); + } + else if (argc != 4) { + Fprintf((stderr, "'lzhuf e file1 file2' encodes file1 into file2.\n" + "'lzhuf d file2 file1' decodes file2 into file1.\n")); + return EXIT_FAILURE; + } + if (argc == 4) { + if ((s = argv[1], s[1] || strpbrk(s, "DEde") == NULL) + || (s = argv[2], (infile = fopen(s, "rb")) == NULL) + || (s = argv[3], (outfile = fopen(s, "wb")) == NULL)) { + Fprintf((stderr, "??? %s\n", s)); + return EXIT_FAILURE; + } + } + if (toupper(*argv[1]) == 'E') + Encode(); + else + Decode(); + fclose(infile); + fclose(outfile); + return EXIT_SUCCESS; +} +#endif diff --git a/contrib/dhcpdconfeg/dhcpd.conf b/contrib/dhcpdconfeg/dhcpd.conf new file mode 100644 index 0000000..4d13e0f --- /dev/null +++ b/contrib/dhcpdconfeg/dhcpd.conf @@ -0,0 +1,16 @@ +This is an example of using vendor tags in DHCPD config, supplied by +Bernd Wiebelt. + + +subnet 10.97.0.0 netmask 255.255.0.0 { + range 10.97.0.2 10.97.0.254; + option option-128 e4:45:74:68:0:0; + option option-160 "default=193"; + option option-184 "HALLO"; + option option-192 "Linux:::linux.tagged:"; + option option-193 "DOS Bootdisk:::dosboot.tagged"; + option option-194 "RH61 Bootdisk:::boot.tagged"; + option option-195 "Local Disk:::/dev/hda:85b103482a20682da703aa388933a6d8"; +} + + diff --git a/contrib/dhcpdconfeg/vendorclassid.txt b/contrib/dhcpdconfeg/vendorclassid.txt new file mode 100644 index 0000000..7b1f391 --- /dev/null +++ b/contrib/dhcpdconfeg/vendorclassid.txt @@ -0,0 +1,140 @@ +From: Dax Kelson +To: Etherboot users list +Subject: [Etherboot-users] Example ISC DHCP v3 dhcpd.conf using conditional operations +Date: Wed, 13 Jun 2001 20:22:21 -0600 + +Hopefully someone will find this useful. I spent a long time tracking +down and figuring out all the pieces. To the powers that be, feel free to +stick this in contrib if you like it. + +Goal: Use the vendor-class-identifier and ISC DHCP v3 "match" option to +conditionally send proper options only when the DHCP discover/request from +etherboot comes in. We use static-MAC-to-IP mappings for classroom +computers, and dynamic dhcp ranges for other clients (student laptops, +etc). + +I used Etherboot 5.0.1 and the patch (required) in this email: + +http://www.geocrawler.com/lists/3/SourceForge/5299/0/5952625/ + +Furture versions of Etherboot will likely already have this patch +included. + +Dax Kelson +Guru Labs + +######### Begin ISC DHCP v3 dhcpd.conf ############# + +ddns-update-style ad-hoc; + +# Global default, can be overridden +filename "/exports/kickstart/class1-rh7.1.ks"; + +# Define options for Etherboot +# There are more, these are just the ones I'm using +option ebootmagic code 128 = string; +option cmdline code 129 = string; +option menudflts code 160 = string; +option menuline1 code 192 = string; +option menuline2 code 193 = string; +option menuline3 code 194 = string; +option menuline4 code 195 = string; +option menuline5 code 196 = string; +option menuline6 code 197 = string; +option menuline7 code 198 = string; +option menuline8 code 199 = string; +option menuline9 code 200 = string; +option menuline10 code 201 = string; +option menuline11 code 202 = string; +option menuline12 code 203 = string; +option menuline13 code 204 = string; +option menuline14 code 205 = string; +option menuline15 code 206 = string; +option menuline16 code 207 = string; +option motdline1 code 184 = string; + +class "Etherboot" { + match if substring (option vendor-class-identifier, 0, 9) = "Etherboot"; + + option ebootmagic = E4:45:74:68:00:00; + +# We don't use this here, because different menu items require +# different cmdlines. In our ".nbi" files we specify the cmdlines + +# option cmdline = "ks initrd=initrd.img lang= devfs=nomount"; + + option motdline1 = "Welcome to Guru Labs classroom"; + + option menudflts = "timeout=30:default=192"; + + option menuline1 = "Boot from Hard Drive (Default):::/dev/hda:::"; + option menuline2 = "Boot from Floppy:::/dev/fd0:::"; + option menuline3 = "Boot from CDROM::::::"; + option menuline4 = "Kickstart install Red Hat 7.1:::rh71-ks-etherboot.nbi:::"; + option menuline5 = "Red Hat 7.1 network rescue:::rh71-rescue-etherboot.nbi:::"; + option menuline6 = "Boot Win98SE startup floppy:::win98se-startupdisk.nbi:::"; + option menuline7 = "Jumpstart install Solaris 8 (not working yet):::/dev/hda:::"; + option menuline8 = "Install Windows 98 SE (not working yet):::/dev/hda:::"; + option menuline9 = "Install Windows 2000 (not working yet):::/dev/hda:::"; + option menuline10 = "Install FreeBSD 4.3 (not working yet):::/dev/hda:::"; + option menuline11 = "Install OpenBSD 2.9 (not working yet):::/dev/hda:::"; + + # This is a hidden menu item, it should be password protected too + option menuline12 = "^[[3D^[[K^[[1A^M:::/dev/hda:::"; + +# We are using the menu, with different bootfiles. So we don't use this. +# If you weren't using a menu, you could use this override the global +# default "filename" setting. + +# filename "rh71-ks-etherboot"; + +# Use the following if etherboot compiled with -DREQUIRE_VCI_ETHERBOOT + + option vendor-encapsulated-options 3c:09:45:74:68:65:72:62:6f:6f:74:ff; + +} + +subnet 10.100.0.0 netmask 255.255.255.0 { + authoritative; + option routers 10.100.0.254; + option subnet-mask 255.255.255.0; + option domain-name "example.com"; + option domain-name-servers 10.100.0.254; + option time-offset -7; # US/Mountain + option ntp-servers 10.100.0.254; + range dynamic-bootp 10.100.0.175 10.100.0.250; + default-lease-time 21600; + max-lease-time 43200; + option netbios-name-servers 10.100.0.254; + option netbios-node-type 2; + use-host-decl-names on; + next-server server1.example.com; + +} + +host station1 { + hardware ethernet 00:01:03:de:57:e2; + fixed-address 10.100.0.1; +} +host station2 { + hardware ethernet 00:01:03:de:57:e7; + fixed-address 10.100.0.2; +} +host station3 { + hardware ethernet 00:01:03:de:57:b4; + fixed-address 10.100.0.3; +} +host station4 { + hardware ethernet 00:01:03:de:57:38; + fixed-address 10.100.0.4; +} +host station5 { + hardware ethernet 00:01:03:de:58:3d; + fixed-address 10.100.0.5; +} + +# +# Etc, etc +# + +############## End ISC DHCP v3 dhcpd.conf ############# diff --git a/contrib/dhcpid/dhcpid.txt b/contrib/dhcpid/dhcpid.txt new file mode 100644 index 0000000..e6b5d27 --- /dev/null +++ b/contrib/dhcpid/dhcpid.txt @@ -0,0 +1,884 @@ +From daniel@insu.com Thu Apr 27 14:14:55 2000 +Sender: root@iNsu.COM +Message-ID: <39075669.FAEB20F2@insu.com> +Date: Wed, 26 Apr 2000 16:49:45 -0400 +From: Daniel Shane <daniel@insu.com> +X-Mailer: Mozilla 4.72 [en] (X11; U; Linux 2.2.14-5.0 i686) +X-Accept-Language: en +MIME-Version: 1.0 +Subject: Re: New feature added to etherboot +References: <20000425170804.6677127D8A@Goffman.iNsu.COM> +Content-Type: multipart/mixed; + boundary="------------4734FDA0BF2F2FBDF8EB8DF6" + +This is a multi-part message in MIME format. +--------------4734FDA0BF2F2FBDF8EB8DF6 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit + +Ok, here is a diff for etherboot 4.6.0 that adds identifiers. + +To test this you need to use a class in the dhcpd.conf file and +also send back a string in option 208. + +These identifiers prevent a client from booting from other DHCP +servers when you have more than 1 in your network. + +In will also prevent any client, except the valid ones, to use this +DHCP server. + +Here is a subset of my dhcpd.conf : + +option iNdiskless-state code 208 = text; + +class "iNdiskless-boot" { + match if substring(option iNdiskless-state,0,4) = "BOOT"; +} +class "iNdiskless-setup" { + match if substring(option iNdiskless-state,0,5) = "SETUP"; +} + +subnet 10.4.1.0 netmask 255.255.255.0 { +pool { + allow members of "iNdiskless-boot"; + deny unknown clients; + range 10.4.1.2 10.4.1.200; + next-server 10.4.1.1; + +# Identify ourselves to the etherboot/DHCP client + option iNdiskless-state "BOOT"; + + host labo01 { + hardware ethernet 00:80:c8:ec:04:1b; + } + host labo02 { + hardware ethernet 00:4f:4c:04:45:d6; + } + host labo03 { + hardware ethernet 00:50:ba:c8:db:d6; + } +} +pool { + allow members of "iNdiskless-setup"; + range 10.4.1.201 10.4.1.254; + option iNdiskless-state "SETUP"; + +# send another kernel to setup the diskless workstation + } +} + +Daniel Shane. +--------------4734FDA0BF2F2FBDF8EB8DF6 +Content-Type: text/plain; charset=us-ascii; + name="main.c.diff" +Content-Transfer-Encoding: 7bit +Content-Disposition: inline; + filename="main.c.diff" + +--- etherboot-4.6.0/src/main.c Tue Apr 25 08:30:01 2000 ++++ etherboot-4.5.6-new/src/main.c Wed Apr 26 16:17:09 2000 +@@ -42,6 +42,23 @@ char *motd[RFC1533_VENDOR_NUMOFMOTD]; + #ifdef IMAGE_FREEBSD + int freebsd_howto = 0; + #endif ++ ++#ifdef SERVER_IDENT ++#ifdef DEFAULT_SERVER_IDENT ++char server_ident[9] = DEFAULT_SERVER_IDENT; ++#else ++char server_ident[9] = {}; ++#endif ++#endif ++ ++#ifdef CLIENT_IDENT ++#ifdef DEFAULT_CLIENT_IDENT ++char client_ident[9] = DEFAULT_CLIENT_IDENT; ++#else ++char client_ident[9] = {}; ++#endif ++#endif ++ + int vendorext_isvalid; + char config_buffer[TFTP_MAX_PACKET+1]; /* +1 for null byte */ + unsigned long netmask; +@@ -63,61 +80,85 @@ char rfc1533_cookie[5] = { RFC1533_CO + char rfc1533_cookie[] = { RFC1533_COOKIE}; + char rfc1533_end[]={RFC1533_END }; + static const char dhcpdiscover[]={ +- RFC2132_MSG_TYPE,1,DHCPDISCOVER, +- RFC2132_MAX_SIZE,2,2,64, +- RFC2132_PARAM_LIST,4,RFC1533_NETMASK,RFC1533_GATEWAY, +- RFC1533_HOSTNAME,RFC1533_EXTENSIONPATH +- }; +-static const char dhcprequest []={ +- RFC2132_MSG_TYPE,1,DHCPREQUEST, +- RFC2132_SRV_ID,4,0,0,0,0, +- RFC2132_REQ_ADDR,4,0,0,0,0, +- RFC2132_MAX_SIZE,2,2,64, +- /* request parameters */ +- RFC2132_PARAM_LIST, +-#ifdef IMAGE_FREEBSD +- /* 4 standard + 4 vendortags + 8 motd + 16 menu items */ +- 4 + 4 + 8 + 16, ++ RFC2132_MSG_TYPE,1,DHCPDISCOVER, ++ RFC2132_MAX_SIZE,2,2,64, ++#ifdef CLIENT_IDENT ++ RFC1533_VENDOR_CLIENT_IDENT,8,0,0,0,0,0,0,0,0, ++#endif ++ RFC2132_PARAM_LIST, ++#ifdef SERVER_IDENT ++ 5, + #else +- /* 4 standard + 3 vendortags + 8 motd + 16 menu items */ +- 4 + 3 + 8 + 16, ++ 4, + #endif +- /* Standard parameters */ +- RFC1533_NETMASK, RFC1533_GATEWAY, +- RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH, +- /* Etherboot vendortags */ +- RFC1533_VENDOR_MAGIC, ++#ifdef SERVER_IDENT ++ RFC1533_VENDOR_SERVER_IDENT, ++#endif ++ RFC1533_NETMASK, ++ RFC1533_GATEWAY, ++ RFC1533_HOSTNAME, ++ RFC1533_EXTENSIONPATH ++}; ++static const char dhcprequest []={ ++ RFC2132_MSG_TYPE,1,DHCPREQUEST, ++ RFC2132_SRV_ID,4,0,0,0,0, ++ RFC2132_REQ_ADDR,4,0,0,0,0, ++#ifdef CLIENT_IDENT ++ RFC1533_VENDOR_CLIENT_IDENT,8,0,0,0,0,0,0,0,0, ++#endif ++ RFC2132_MAX_SIZE,2,2,64, ++ /* request parameters */ ++ RFC2132_PARAM_LIST, ++ /* 4 standard + 3 vendortags + 8 motd + 16 menu items */ ++ 4 + ++ 3 + ++#ifdef IMAGE_FREEBSD ++ 1 + /* One more vendortags for VENDOR_HOWTO */ ++#endif ++#ifdef SERVER_IDENT ++ 1 + /* One more vendortags for VENDOR_SERVER_IDENT */ ++#endif ++ 8 + ++ 16, ++ /* Standard parameters */ ++ RFC1533_NETMASK, RFC1533_GATEWAY, ++ RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH, ++ /* Etherboot vendortags */ ++ RFC1533_VENDOR_MAGIC, + #ifdef IMAGE_FREEBSD +- RFC1533_VENDOR_HOWTO, ++ RFC1533_VENDOR_HOWTO, + #endif +- RFC1533_VENDOR_MNUOPTS, RFC1533_VENDOR_SELECTION, +- /* 8 MOTD entries */ +- RFC1533_VENDOR_MOTD, +- RFC1533_VENDOR_MOTD+1, +- RFC1533_VENDOR_MOTD+2, +- RFC1533_VENDOR_MOTD+3, +- RFC1533_VENDOR_MOTD+4, +- RFC1533_VENDOR_MOTD+5, +- RFC1533_VENDOR_MOTD+6, +- RFC1533_VENDOR_MOTD+7, +- /* 16 image entries */ +- RFC1533_VENDOR_IMG, +- RFC1533_VENDOR_IMG+1, +- RFC1533_VENDOR_IMG+2, +- RFC1533_VENDOR_IMG+3, +- RFC1533_VENDOR_IMG+4, +- RFC1533_VENDOR_IMG+5, +- RFC1533_VENDOR_IMG+6, +- RFC1533_VENDOR_IMG+7, +- RFC1533_VENDOR_IMG+8, +- RFC1533_VENDOR_IMG+9, +- RFC1533_VENDOR_IMG+10, +- RFC1533_VENDOR_IMG+11, +- RFC1533_VENDOR_IMG+12, +- RFC1533_VENDOR_IMG+13, +- RFC1533_VENDOR_IMG+14, +- RFC1533_VENDOR_IMG+15, +- }; ++#ifdef SERVER_IDENT ++ RFC1533_VENDOR_SERVER_IDENT, ++#endif ++ RFC1533_VENDOR_MNUOPTS, RFC1533_VENDOR_SELECTION, ++ /* 8 MOTD entries */ ++ RFC1533_VENDOR_MOTD, ++ RFC1533_VENDOR_MOTD+1, ++ RFC1533_VENDOR_MOTD+2, ++ RFC1533_VENDOR_MOTD+3, ++ RFC1533_VENDOR_MOTD+4, ++ RFC1533_VENDOR_MOTD+5, ++ RFC1533_VENDOR_MOTD+6, ++ RFC1533_VENDOR_MOTD+7, ++ /* 16 image entries */ ++ RFC1533_VENDOR_IMG, ++ RFC1533_VENDOR_IMG+1, ++ RFC1533_VENDOR_IMG+2, ++ RFC1533_VENDOR_IMG+3, ++ RFC1533_VENDOR_IMG+4, ++ RFC1533_VENDOR_IMG+5, ++ RFC1533_VENDOR_IMG+6, ++ RFC1533_VENDOR_IMG+7, ++ RFC1533_VENDOR_IMG+8, ++ RFC1533_VENDOR_IMG+9, ++ RFC1533_VENDOR_IMG+10, ++ RFC1533_VENDOR_IMG+11, ++ RFC1533_VENDOR_IMG+12, ++ RFC1533_VENDOR_IMG+13, ++ RFC1533_VENDOR_IMG+14, ++ RFC1533_VENDOR_IMG+15, ++}; + + #endif /* NO_DHCP_SUPPORT */ + static const char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +@@ -176,6 +217,55 @@ done: + break; + } + #endif ++ ++#ifdef SHIFTED_IDENT_INPUT ++ if (getshift() & 3) ++ { ++#endif ++ ++#ifdef CLIENT_IDENT ++# ifdef ASK_CLIENT_IDENT ++ { ++ char tmp_ident[9] = {}; ++# ifdef DEFAULT_CLIENT_IDENT ++ printf("Enter the client identifier (8 char max.) default [%s] : ",client_ident); ++# else ++ printf("Enter the client identifier (8 char max.) : "); ++# endif ++ getstr(tmp_ident,8); ++ if (strlen(tmp_ident) != 0) ++ memcpy(client_ident,tmp_ident,8); ++ else ++ printf("%s",client_ident); ++ putchar('\n'); ++ } ++# endif ++#endif ++ ++#ifdef SERVER_IDENT ++# ifdef ASK_SERVER_IDENT ++ { ++ char tmp_ident[9] = {}; ++# ifdef DEFAULT_SERVER_IDENT ++ printf("Enter the server identifier (8 char max.) default [%s] : ",server_ident); ++# else ++ printf("Enter the server identifier (8 char max.) : "); ++# endif ++ getstr(tmp_ident,8); ++ if (strlen(tmp_ident) != 0) ++ memcpy(server_ident,tmp_ident,8); ++ else ++ printf("%s",server_ident); ++ putchar('\n'); ++ } ++# endif ++#endif ++ ++#ifdef SHIFTED_IDENT_INPUT ++ } ++#endif ++ ++ print_config(); + #if (TRY_FLOPPY_FIRST > 0) && defined(FLOPPY) + disk_init(); + printf("Trying floppy"); +@@ -188,7 +278,7 @@ done: + } + printf("no floppy\n"); + #endif /* TRY_FLOPPY_FIRST && FLOPPY */ +- print_config(); ++ print_config(); + gateA20_set(); + #ifdef EMERGENCYDISKBOOT + if (!eth_probe()) { +@@ -663,6 +753,8 @@ BOOTP - Get my IP address and load infor + int bootp() + { + int retry; ++ int offset = 0; ++ + #ifndef NO_DHCP_SUPPORT + int retry1; + #endif /* NO_DHCP_SUPPORT */ +@@ -680,11 +772,18 @@ int bootp() + bp.bp_xid = xid = starttime = currticks(); + memcpy(bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE); + #ifdef NO_DHCP_SUPPORT +- memcpy(bp.bp_vend, rfc1533_cookie, 5); /* request RFC-style options */ ++ memcpy(bp.bp_vend+offset, rfc1533_cookie, 5); /* request RFC-style options */ ++ offset += sizeof rfc1533_cookie; + #else +- memcpy(bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); /* request RFC-style options */ +- memcpy(bp.bp_vend+sizeof rfc1533_cookie, dhcpdiscover, sizeof dhcpdiscover); +- memcpy(bp.bp_vend+sizeof rfc1533_cookie +sizeof dhcpdiscover, rfc1533_end, sizeof rfc1533_end); ++ memcpy(bp.bp_vend+offset, rfc1533_cookie, sizeof rfc1533_cookie); /* request RFC-style options */ ++ offset += sizeof rfc1533_cookie; ++ memcpy(bp.bp_vend+offset, dhcpdiscover, sizeof dhcpdiscover); ++ offset += sizeof dhcpdiscover; ++#ifdef CLIENT_IDENT ++ memcpy(bp.bp_vend+13, client_ident, strlen(client_ident)); ++#endif ++ memcpy(bp.bp_vend+offset, rfc1533_end, sizeof rfc1533_end); ++ offset += sizeof rfc1533_end; + #endif /* NO_DHCP_SUPPORT */ + + for (retry = 0; retry < MAX_BOOTP_RETRIES; ) { +@@ -715,19 +814,22 @@ int bootp() + #else + if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT)){ + if (dhcp_reply==DHCPOFFER){ +- dhcp_reply=0; +- memcpy(bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); +- memcpy(bp.bp_vend+sizeof rfc1533_cookie, dhcprequest, sizeof dhcprequest); +- memcpy(bp.bp_vend+sizeof rfc1533_cookie +sizeof dhcprequest, rfc1533_end, sizeof rfc1533_end); +- memcpy(bp.bp_vend+9, &dhcp_server, sizeof(in_addr)); +- memcpy(bp.bp_vend+15, &dhcp_addr, sizeof(in_addr)); +- for (retry1 = 0; retry1 < MAX_BOOTP_RETRIES;) { +- udp_transmit(IP_BROADCAST, 0, BOOTP_SERVER, +- sizeof(struct bootp_t), &bp); + dhcp_reply=0; +- if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT)) +- if (dhcp_reply==DHCPACK) +- return(1); ++ memcpy(bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); ++ memcpy(bp.bp_vend+sizeof rfc1533_cookie, dhcprequest, sizeof dhcprequest); ++ memcpy(bp.bp_vend+sizeof rfc1533_cookie +sizeof dhcprequest, rfc1533_end, sizeof rfc1533_end); ++ memcpy(bp.bp_vend+9, &dhcp_server, sizeof(in_addr)); ++ memcpy(bp.bp_vend+15, &dhcp_addr, sizeof(in_addr)); ++#ifdef CLIENT_IDENT ++ memcpy(bp.bp_vend+21, client_ident, strlen(client_ident)); ++#endif ++ for (retry1 = 0; retry1 < MAX_BOOTP_RETRIES;) { ++ udp_transmit(IP_BROADCAST, 0, BOOTP_SERVER, ++ sizeof(struct bootp_t), &bp); ++ dhcp_reply=0; ++ if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT)) ++ if (dhcp_reply==DHCPACK) ++ return(1); + rfc951_sleep(++retry1); + } + } else +@@ -750,6 +852,7 @@ AWAIT_REPLY - Wait until we get a respon + **************************************************************************/ + int await_reply(int type, int ival, void *ptr, int timeout) + { ++ int result; + unsigned long time; + struct iphdr *ip; + struct udphdr *udp; +@@ -757,6 +860,7 @@ int await_reply(int type, int ival, void + struct bootp_t *bootpreply; + struct rpc_t *rpc; + unsigned short ptype; ++ unsigned int min_packetlen; + + unsigned int protohdrlen = ETHER_HDR_SIZE + sizeof(struct iphdr) + + sizeof(struct udphdr); +@@ -766,35 +870,35 @@ int await_reply(int type, int ival, void + * needs a negligible amount of time. */ + for (;;) { + if (eth_poll()) { /* We have something! */ +- /* Check for ARP - No IP hdr */ ++ /* Check for ARP - No IP hdr */ + if (nic.packetlen >= ETHER_HDR_SIZE) { + ptype = ((unsigned short) nic.packet[12]) << 8 + | ((unsigned short) nic.packet[13]); + } else continue; /* what else could we do with it? */ + if ((nic.packetlen >= ETHER_HDR_SIZE + +- sizeof(struct arprequest)) && +- (ptype == ARP) ) { ++ sizeof(struct arprequest)) && ++ (ptype == ARP) ) { + unsigned long tmp; +- ++ + arpreply = (struct arprequest *) + &nic.packet[ETHER_HDR_SIZE]; + if ((arpreply->opcode == ntohs(ARP_REPLY)) && +- !memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) && +- (type == AWAIT_ARP)) { ++ !memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) && ++ (type == AWAIT_ARP)) { + memcpy(arptable[ival].node, arpreply->shwaddr, ETHER_ADDR_SIZE); + return(1); + } + memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr)); + if ((arpreply->opcode == ntohs(ARP_REQUEST)) && +- (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) { ++ (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) { + arpreply->opcode = htons(ARP_REPLY); + memcpy(arpreply->tipaddr, arpreply->sipaddr, sizeof(in_addr)); + memcpy(arpreply->thwaddr, arpreply->shwaddr, ETHER_ADDR_SIZE); + memcpy(arpreply->sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr)); + memcpy(arpreply->shwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE); + eth_transmit(arpreply->thwaddr, ARP, +- sizeof(struct arprequest), +- arpreply); ++ sizeof(struct arprequest), ++ arpreply); + #ifdef MDEBUG + memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr)); + printf("Sent ARP reply to: %I\n",tmp); +@@ -802,20 +906,20 @@ int await_reply(int type, int ival, void + } + continue; + } +- ++ + if (type == AWAIT_QDRAIN) { + continue; + } +- +- /* Check for RARP - No IP hdr */ ++ ++ /* Check for RARP - No IP hdr */ + if ((type == AWAIT_RARP) && +- (nic.packetlen >= ETHER_HDR_SIZE + +- sizeof(struct arprequest)) && +- (ptype == RARP)) { ++ (nic.packetlen >= ETHER_HDR_SIZE + ++ sizeof(struct arprequest)) && ++ (ptype == RARP)) { + arpreply = (struct arprequest *) + &nic.packet[ETHER_HDR_SIZE]; + if ((arpreply->opcode == ntohs(RARP_REPLY)) && +- !memcmp(arpreply->thwaddr, ptr, ETHER_ADDR_SIZE)) { ++ !memcmp(arpreply->thwaddr, ptr, ETHER_ADDR_SIZE)) { + memcpy(arptable[ARP_SERVER].node, arpreply->shwaddr, ETHER_ADDR_SIZE); + memcpy(& arptable[ARP_SERVER].ipaddr, arpreply->sipaddr, sizeof(in_addr)); + memcpy(& arptable[ARP_CLIENT].ipaddr, arpreply->tipaddr, sizeof(in_addr)); +@@ -823,64 +927,72 @@ int await_reply(int type, int ival, void + } + continue; + } +- +- /* Anything else has IP header */ ++ ++ /* Anything else has IP header */ + if ((nic.packetlen < protohdrlen) || +- (ptype != IP) ) continue; ++ (ptype != IP) ) continue; + ip = (struct iphdr *)&nic.packet[ETHER_HDR_SIZE]; + if ((ip->verhdrlen != 0x45) || +- ipchksum((unsigned short *)ip, sizeof(struct iphdr)) || +- (ip->protocol != IP_UDP)) continue; ++ ipchksum((unsigned short *)ip, sizeof(struct iphdr)) || ++ (ip->protocol != IP_UDP)) continue; + udp = (struct udphdr *)&nic.packet[ETHER_HDR_SIZE + +- sizeof(struct iphdr)]; +- +- /* BOOTP ? */ ++ sizeof(struct iphdr)]; ++ ++ /* BOOTP ? */ + bootpreply = (struct bootp_t *)&nic.packet[ETHER_HDR_SIZE]; +- if ((type == AWAIT_BOOTP) && +- (nic.packetlen >= (ETHER_HDR_SIZE + +-#ifdef NO_DHCP_SUPPORT +- sizeof(struct bootp_t))) && ++#ifdef NO_DHCP_SUPPORT ++ min_packetlen = ETHER_HDR_SIZE + sizeof(struct bootp_t); + #else +- sizeof(struct bootp_t))-DHCP_OPT_LEN) && +-#endif /* NO_DHCP_SUPPORT */ +- (ntohs(udp->dest) == BOOTP_CLIENT) && +- (bootpreply->bp_op == BOOTP_REPLY) && +- (bootpreply->bp_xid == xid)) { +- arptable[ARP_CLIENT].ipaddr.s_addr = +- bootpreply->bp_yiaddr.s_addr; ++ min_packetlen = ETHER_HDR_SIZE + sizeof(struct bootp_t) - DHCP_OPT_LEN; ++#endif ++ if ( ++ (type == AWAIT_BOOTP) && ++ (nic.packetlen >= min_packetlen) && ++ (ntohs(udp->dest) == BOOTP_CLIENT) && ++ (bootpreply->bp_op == BOOTP_REPLY) && ++ (bootpreply->bp_xid == xid) ++ ) { ++ arptable[ARP_CLIENT].ipaddr.s_addr = bootpreply->bp_yiaddr.s_addr; + #ifndef NO_DHCP_SUPPORT + dhcp_addr.s_addr = bootpreply->bp_yiaddr.s_addr; + #endif /* NO_DHCP_SUPPORT */ + netmask = default_netmask(); +- arptable[ARP_SERVER].ipaddr.s_addr = +- bootpreply->bp_siaddr.s_addr; ++ arptable[ARP_SERVER].ipaddr.s_addr = bootpreply->bp_siaddr.s_addr; + memset(arptable[ARP_SERVER].node, 0, ETHER_ADDR_SIZE); /* Kill arp */ +- arptable[ARP_GATEWAY].ipaddr.s_addr = +- bootpreply->bp_giaddr.s_addr; ++ arptable[ARP_GATEWAY].ipaddr.s_addr = bootpreply->bp_giaddr.s_addr; + memset(arptable[ARP_GATEWAY].node, 0, ETHER_ADDR_SIZE); /* Kill arp */ + if (bootpreply->bp_file[0]) { + memcpy(kernel_buf, bootpreply->bp_file, 128); + kernel = kernel_buf; + } + memcpy((char *)BOOTP_DATA_ADDR, (char *)bootpreply, sizeof(struct bootpd_t)); +- decode_rfc1533(BOOTP_DATA_ADDR->bootp_reply.bp_vend, +-#ifdef NO_DHCP_SUPPORT +- 0, BOOTP_VENDOR_LEN + +- MAX_BOOTP_EXTLEN, 1); +-#else +- 0, DHCP_OPT_LEN, 1); +-#endif /* NO_DHCP_SUPPORT */ +- return(1); ++#ifdef NO_DHCP_SUPPORT ++ if (decode_rfc1533(BOOTP_DATA_ADDR->bootp_reply.bp_vend, ++ 0, BOOTP_VENDOR_LEN + ++ MAX_BOOTP_EXTLEN, 1)) { ++ return(1); ++ } ++ else { ++ continue; ++ } ++#else ++ if (decode_rfc1533(BOOTP_DATA_ADDR->bootp_reply.bp_vend, ++ 0, DHCP_OPT_LEN, 1)) { ++ return(1); ++ } ++ else { ++ continue; ++ } + } +- ++#endif /* NO_DHCP_SUPPORT */ + #ifdef DOWNLOAD_PROTO_TFTP +- /* TFTP ? */ ++ /* TFTP ? */ + if ((type == AWAIT_TFTP) && +- (ntohs(udp->dest) == ival)) return(1); ++ (ntohs(udp->dest) == ival)) return(1); + #endif /* DOWNLOAD_PROTO_TFTP */ +- ++ + #ifdef DOWNLOAD_PROTO_NFS +- /* RPC ? */ ++ /* RPC ? */ + rpc = (struct rpc_t *)&nic.packet[ETHER_HDR_SIZE]; + if ((type == AWAIT_RPC) && + (ntohs(udp->dest) == ival) && +@@ -889,19 +1001,19 @@ int await_reply(int type, int ival, void + return (1); + } + #endif /* DOWNLOAD_PROTO_NFS */ +- ++ + } else { +- /* Check for abort key only if the Rx queue is empty - +- * as long as we have something to process, don't +- * assume that something failed. It is unlikely that +- * we have no processing time left between packets. */ ++ /* Check for abort key only if the Rx queue is empty - ++ * as long as we have something to process, don't ++ * assume that something failed. It is unlikely that ++ * we have no processing time left between packets. */ + if (iskey() && (getchar() == ESC)) + #ifdef EMERGENCYDISKBOOT + exit(0); + #else +- longjmp(jmp_bootmenu,1); ++ longjmp(jmp_bootmenu,1); + #endif +- /* Do the timeout after at least a full queue walk. */ ++ /* Do the timeout after at least a full queue walk. */ + if ((timeout == 0) || (currticks() > time)) { + break; + } +@@ -914,13 +1026,15 @@ int await_reply(int type, int ival, void + DECODE_RFC1533 - Decodes RFC1533 header + **************************************************************************/ + int decode_rfc1533(p, block, len, eof) +- register unsigned char *p; +- int block, len, eof; ++ register unsigned char *p; ++ int block, len, eof; + { + static unsigned char *extdata = NULL, *extend = NULL; + unsigned char *extpath = NULL; + unsigned char *endp; +- ++#ifdef SERVER_IDENT ++ char rcvd_server_ident[9] = {}; ++#endif + if (block == 0) { + #ifdef IMAGE_MENU + memset(imagelist, 0, sizeof(imagelist)); +@@ -1002,11 +1116,16 @@ int decode_rfc1533(p, block, len, eof) + } + #endif + #ifdef MOTD +- else if (c >= RFC1533_VENDOR_MOTD && ++ else if (c >= RFC1533_VENDOR_MOTD && + c < RFC1533_VENDOR_MOTD + + RFC1533_VENDOR_NUMOFMOTD) + motd[c - RFC1533_VENDOR_MOTD] = p; + #endif ++#ifdef SERVER_IDENT ++ else if (c == RFC1533_VENDOR_SERVER_IDENT) { ++ memcpy(rcvd_server_ident,p+2,TAG_LEN(p)); ++ } ++#endif + else { + #if 0 + unsigned char *q; +@@ -1018,6 +1137,30 @@ int decode_rfc1533(p, block, len, eof) + } + p += TAG_LEN(p) + 2; + } ++#if defined(SERVER_IDENT) && defined(DBG_IDENT) ++ if (strcasecmp(rcvd_server_ident,server_ident)) { ++ char ip[16]; ++ ++ inet_ntoa(dhcp_server,ip); ++ printf("[%s]: Option %d (%s), invalid response. Wanted (%s).\n", ++ ip, ++ RFC1533_VENDOR_SERVER_IDENT, ++ rcvd_server_ident, ++ server_ident); ++ strcpy(rcvd_server_ident,""); ++ return(0); ++ } ++ else { ++ char ip[16]; ++ ++ inet_ntoa(dhcp_server,ip); ++ printf("[%s]: Option %d (%s), valid response.\n", ++ ip, ++ RFC1533_VENDOR_SERVER_IDENT, ++ rcvd_server_ident); ++ strcpy(rcvd_server_ident,""); ++ } ++#endif + extdata = extend = endp; + if (block == 0 && extpath != NULL) { + char fname[64]; +@@ -1103,3 +1246,4 @@ void cleanup(void) + * c-basic-offset: 8 + * End: + */ ++ + +--------------4734FDA0BF2F2FBDF8EB8DF6 +Content-Type: text/plain; charset=us-ascii; + name="misc.c.diff" +Content-Transfer-Encoding: 7bit +Content-Disposition: inline; + filename="misc.c.diff" + +--- etherboot-4.6.0/src/misc.c Tue Apr 25 08:30:25 2000 ++++ etherboot-4.5.6-new/src/misc.c Wed Apr 26 16:26:38 2000 +@@ -140,9 +140,11 @@ void printf(const char *fmt, ...) + + #ifdef IMAGE_MENU + /************************************************************************** +-INET_ATON - Convert an ascii x.x.x.x to binary form ++INET_NTOA - Convert an ascii x.x.x.x to binary form + **************************************************************************/ +-int inet_aton(char *p, in_addr *i) ++int inet_aton(p, i) ++ char *p; ++ in_addr *i; + { + unsigned long ip = 0; + int val; +@@ -165,7 +167,19 @@ int inet_aton(char *p, in_addr *i) + + #endif /* IMAGE_MENU */ + +-int getdec(char **ptr) ++#if defined(CLIENT_IDENT) || defined (SERVER_IDENT) ++/************************************************************************** ++INET_NTOA - Convert a binary form to an ascii x.x.x.x form ++**************************************************************************/ ++char *inet_ntoa(in_addr i, char *p) ++{ ++ sprintf(p,"%d.%d.%d.%d",i.s_addr>>24,i.s_addr<<8>>24,i.s_addr<<16>>24,i.s_addr<<24>>24); ++ return p; ++} ++#endif ++ ++int getdec(ptr) ++ char **ptr; + { + char *p = *ptr; + int ret=0; +@@ -308,6 +322,45 @@ iskey(void) + return 0; + } + #endif /* ETHERBOOT32 */ ++ ++/************************************************************************** ++GETSTR - Read a string of size bytes from the keyboard ++(without echoing the final return) ++**************************************************************************/ ++void getstr(char *s, int size) ++{ ++ int i=0; ++ char c; ++ ++ while(1) { ++ c = getc(); ++ ++ ++ if (c == 13) ++ { ++ s[i]='\0'; ++ break; ++ } ++ else if ( ++ ((c >= 'a') && (c <='z')) || ++ ((c >= 'A') && (c <='Z')) || ++ ((c >= '0') && (c <='9')) ++ ) { ++ if (i==8) { ++ putchar(8); ++ putchar(s[i-1]=c); ++ } ++ else ++ putchar(s[i++]=c); ++ } ++ else if ( c == 8 ) { ++ if (i != 0) { ++ --i; ++ s[i]='\0'; ++ putchar(8); ++ putchar(32); ++ putchar(8); ++ } ++ } ++ } ++} + + /* + * Local variables: + +--------------4734FDA0BF2F2FBDF8EB8DF6 +Content-Type: text/plain; charset=us-ascii; + name="Config.diff" +Content-Transfer-Encoding: 7bit +Content-Disposition: inline; + filename="Config.diff" + +--- etherboot-4.6.0/src/Config Tue Apr 25 08:30:57 2000 ++++ etherboot-4.5.6-new/src/Config Wed Apr 26 15:55:57 2000 +@@ -59,6 +59,27 @@ + # may no longer be appropriate. You might need to set + # MAX_ARP_RETRIES, MAX_BOOTP_RETRIES, MAX_TFTP_RETRIES + # and MAX_RPC_RETRIES to a larger value. ++# -DDEFAULT_CLIENT_IDENT ++# The default client identifier that is sent to the ++# DHCP server to identify itself. ++# -DDEFAULT_SERVER_IDENT ++# The expected response that the client will wait ++# for when a DHCP server responds to the the initial ++# client discovery. ++# -DASK_CLIENT_IDENT ++# -DASK_SERVER_IDENT ++# If these are set, the boot process will include ++# a question period where you can manualy specify ++# the client and/or server identifiers. ++# -DSHIFTED_IDENT_INPUT ++# If this is set then the boot process will only ++# ask for the identifiers if one of the shift keys ++# is pressed. Else it will send the default identifiers ++# automatically ++# -DDBG_IDENT ++# This will give show all the DHCP responses with ++# their identifiers. ++# + # + # Etherboot/32 only options: + # -DAOUT_IMAGE - Add a.out kernel boot support (generic) +@@ -147,6 +168,14 @@ CFLAGS32+= -DASK_BOOT=3 -DANS_DEFAULT=AN + + # Change download protocol to NFS. Only available for Etherboot/32 for now. + # CFLAGS32+= -DDOWNLOAD_PROTO_NFS ++ ++# If you have more than one DHCP server you might want to ++# enable these to be able to sort out which one you want to ++# respond to. ++CFLAGS32+= -DDEFAULT_CLIENT_IDENT=\"BOOT\" -DDEFAULT_SERVER_IDENT=\"BOOT\" ++CFLAGS32+= -DASK_CLIENT_IDENT -DASK_SERVER_IDENT ++CFLAGS32+= -DSHIFTED_IDENT_INPUT ++CFLAGS32+= -DDBG_IDENT + + # These flags affect the loader that is prepended to the Etherboot image + LCONFIG+= -DMOVEROM + +--------------4734FDA0BF2F2FBDF8EB8DF6 +Content-Type: text/plain; charset=us-ascii; + name="etherboot.h.diff" +Content-Transfer-Encoding: 7bit +Content-Disposition: inline; + filename="etherboot.h.diff" + +--- etherboot-4.6.0/src/etherboot.h Tue Apr 25 08:30:55 2000 ++++ etherboot-4.5.6-new/src/etherboot.h Wed Apr 26 16:07:16 2000 +@@ -8,6 +8,14 @@ Author: Martin Renters + + #include "osdep.h" + ++#if (! defined(NO_DHCP_SUPPORT)) && (defined(ASK_CLIENT_IDENT) || defined(DEFAULT_CLIENT_IDENT)) ++# define CLIENT_IDENT ++#endif ++ ++#if (! defined(NO_DHCP_SUPPORT)) && (defined(ASK_SERVER_IDENT) || defined(DEFAULT_SERVER_IDENT)) ++# define SERVER_IDENT ++#endif ++ + /* These could be customised for different languages perhaps */ + #define ASK_PROMPT "Boot from (N)etwork or from (L)ocal? " + #define ANS_NETWORK 'N' +@@ -224,6 +232,12 @@ Author: Martin Renters + #ifdef IMAGE_FREEBSD + #define RFC1533_VENDOR_HOWTO 132 + #endif ++#ifdef CLIENT_IDENT ++#define RFC1533_VENDOR_CLIENT_IDENT 208 ++#endif ++#ifdef SERVER_IDENT ++#define RFC1533_VENDOR_SERVER_IDENT 208 ++#endif + #define RFC1533_VENDOR_MNUOPTS 160 + #define RFC1533_VENDOR_SELECTION 176 + #define RFC1533_VENDOR_MOTD 184 +@@ -477,11 +491,13 @@ extern int getdec P((char **)); + extern void printf P((const char *, ...)); + extern char *sprintf P((char *, const char *, ...)); + extern int inet_aton P((char *p, in_addr *i)); ++extern char *inet_ntoa P((in_addr i, char *p)); + extern void gateA20_set P((void)); + extern void gateA20_unset P((void)); + extern void putchar P((int)); + extern int getchar P((void)); + extern int iskey P((void)); ++extern void getstr P((char *s, int size)); + + /* start*.S */ + extern int getc P((void)); +@@ -528,8 +544,10 @@ extern int hostnamelen; + extern unsigned long netmask; + extern int jmp_bootmenu[10]; + extern struct arptable_t arptable[MAX_ARP]; +-#ifdef IMAGE_MENU ++#ifdef MOTD + extern char *motd[RFC1533_VENDOR_NUMOFMOTD]; ++#endif ++#ifdef IMAGE_MENU + extern int menutmo,menudefault; + extern unsigned char *defparams; + extern int defparams_max; + +--------------4734FDA0BF2F2FBDF8EB8DF6-- + diff --git a/contrib/eepro100notes/flash-1.txt b/contrib/eepro100notes/flash-1.txt new file mode 100644 index 0000000..61579b4 --- /dev/null +++ b/contrib/eepro100notes/flash-1.txt @@ -0,0 +1,73 @@ +Date: Tue, 18 May 1999 15:45:55 +0200 (MEST) +From: Erik Starback <erik@math.uu.se> +To: netboot@baghira.han.de +Subject: Netboot with Intel EEPRO100+ Management +Message-ID: <Pine.LNX.3.96.990518154313.3875A-100000@anarchy.math.uu.se> +MIME-Version: 1.0 +Content-Type: TEXT/PLAIN; charset=iso-8859-1 +Content-Transfer-Encoding: 8BIT +Sender: owner-netboot@baghira.han.de +Precedence: bulk +Reply-To: netboot@baghira.han.de +X-Moderator: netboot-owner@baghira.han.de +X-UIDL: 6ca8453c19c46d622813e9be8ada9517 +Status: O +X-Status: + +Hello! + +When Intel eepro100+ NIC disappeared from the market, I didn't know +what to do. I didn't find any information if anyone has used the +new eepro100+ Management Adapter to netboot linux. + +I thought that the card should netboot with the same configuration as +the old card when I read Donald Beckers comment: +> The driver should "just work" with the '559. It's not supposed to be +> substantially different than the '558. (I don't have a datasheet +> or sample card to confirm this statement.) + +The problem was now only to put the netboot-program to the built in +flash memory on the NIC. With the old card I used a flash memory (Intel +N28F020 [N28010 didn't work])) and the program FUTIL.EXE from Intel to +flash it. FUTIL did't recognize the memory on the management card +and did not work therefore. + +I found the intel program FBOOT.EXE that was made to upgrade the built +in Intel BOOT agent. I did: Boot dos from floppy, Run FBOOT (choose +adapter), choose (u)pdate, choose Create restore image, rename the +backup file (in my case 2743BE52.FLS [the eight last hex digits from +the MAC address]), rename your netboot code (in my case netboot 0.8.1) +to the backup files original name (in my case 2743BE52.FLS), run +FBOOT, choose (r)estore. + +Voila! + +A shorter way (if you don't need the backup of the old Intel BOOT +agent code) is of course: rename netboot file to [the eight last hex +digits from the MAC address].FLS, run FBOOT, choose restore. + +Caution: I think it is possible to make a NIC unusable if you have +made the netboot (or etherboot) file with "wrong" parameters. A couple +of month ago I did a etherboot boot file and put it on an old +EEPRO100+ card. It worked fine, but it was impossible to boot local +with it. So I could not boot dos and with FUTIL or FBOOT erase the +flash memory! To erase the chip I had to take out the memory chip, +boot dos and then put in the memory chip. This isn't possible when the +memory chip is build in. + +Links: +<http://support.intel.com/support/landesk/configmgr/LSA1_193.HTM> +FUTIL.EXE is a part of LSA1_193.ZIP + +<http://support.intel.com/support/etherexpress/pro100/100pboot.htm> +FBOOT.EXE is a part of 100pboot.exe + +/Erik S + +------------------------------------------------------------------------- +Erik Starbäck, System administrator E-mail address: erik@math.uu.se +Uppsala University Telephone (o): +46 18 4713277 +Department of Mathematics Cellular phone: +46 70 4250260 +P. O. Box 480 Fax (o): +46 18 4713201 +SE-751 06 UPPSALA +Sweden diff --git a/contrib/eepro100notes/flash-2.txt b/contrib/eepro100notes/flash-2.txt new file mode 100644 index 0000000..1128c30 --- /dev/null +++ b/contrib/eepro100notes/flash-2.txt @@ -0,0 +1,149 @@ +Subject: Look Mom, no PROM burner! (eepro100b flashing instructions) :-) +Date: Sun, 23 Jan 2000 01:53:08 -0500 +x-sender: mdc%thinguin.org@cdi.entity.com +x-mailer: Claris Emailer 2.0v3, January 22, 1998 +From: Marty Connor <mdc@thinguin.org> +To: "Netboot List" <netboot@baghira.han.de> +Mime-Version: 1.0 +Content-Type: text/plain; charset="US-ASCII" +Message-ID: <1263512144-341319205@entity.com> + +Continuing the Etherboot World Domination theme, I noticed that there was +a PCI ethernet card on my bookshelf that still contained the original +vendor's code in its flash memory. The card virtually cried out to be +flashed with Etherboot 4.4.1. :-) + +After having figured out how to flash the 3C905C last week, and owing to +the fact that the temperature here in Cambridge, Massachusetts (USA) has +dropped well below freezing, I decided to explore the possibility of +flashing the Intel eepro100b that was sitting on my bookcase. + +After determining that it was unlikely that one could flash the chip in +user mode under linux like the 3C509C, I turned to other options. (the +reason is that the flash is memory mapped to a place that causes a core +dump if accessed. i suppose one could to patch the kernel to flash the +card, or add a linux device driver, but... :-) + +By the way, If you are ever looking for Linux utilities for Ethernet +cards, you may want to check out: + + http://cesdis.gsfc.nasa.gov/linux/diag/ + +which is a treasure trove of tools for manipulating and testing Ethernet +cards, all with source, courtesy of Donald Becker. + +At this point, I felt it was time to make a virtual trip to the Intel +site (http://www.intel.com/), and search for utilities that might work +with the eepro100B. I found two candidates: FUTIL and FBOOT. I +downloaded, decompressed, and transferred them to a DOS formatted floppy. +Next I determined (after a few tries) that F8 will let me get to DOS +instead of booting windows. (I tend to avoid Windows when I can). + +I first tried FUTIL.EXE. No good. It told me it didn't recognize the +flash on my eepro100B. how unfortunate. and I had such hopes :-) + +Next I tested FBOOT.EXE (available at +http://support.intel.com/support/network/adapter/pro100/100PBOOT.htm) +This program did in fact recognize my eepro100b card. + +The thing about FBOOT however, is that it thinks it only can load certain +files. I of course needed to load an Etherboot image. It appeared to +have no option for doing that. Things looked grim. + +Then I noticed that FBOOT was kind enough to do the following dialog: + + Select Option (U)pdate or (R)estore: U + +I chose Update and it then offered to back up my flash rom for later +restore: + + Create Restore Image (Y)es or (N)o: Y + +I chose "Y" and it proceeded to write a file of my flash memory, which +contained the Intel code. + + Writing FLASH image to file... 100% + +It then erased the device: + + Erasing FLASH Device... 100% + +and then programmed it with fresh code (stored inside the program, no +doubt): + + Programming FLASH Device... 100% + +So now I had a backup of the Intel boot code in a file strangely called: + + 2794FC60.FLS + +Hmmmm, interesting name. The MAC address of the card is 09902794FC60. +They just name the file with the last 4 octets of the MAC address and +.FLS. The file is exactly 65536 bytes, which would make sense for a 64K +Flash Memory device. + +Then I got to thinking, I wonder how carefully the "restore" part of +FBOOT looks at what it is loading? What if I took an Etherboot .rom +file, padded it with 48K of 0xFFs and named it 2794FC60.FLS. What if I +then told FBOOT.EXE to "restore" that? + +Well, I guess by now, you know it worked :-) + +The card came up with the delightful Etherboot banner, Did DHCP, tftp, +and started a kernel. + +The only unfortunate part is that you need to do this under DOS because +you seem to need to be in real mode to program the card. Oh well, +sacrifices have to be made :-) + +So, in summary, to prepare Etherboot image for flashing into the Intel +EEPRO100B card with FBOOT, you need to first make an eepro100.rom file, +as usual. + +Then, see how large it is, with an "ls -l eepro100.rom". the answer will +probably be 16,384. You need to pad it with hex FFs to make it 64K for +FBOOT. I used the following two lines to create the flash image file. + + $ perl -e 'print "\xFF" x 49152' > 48kpad.bin + $ cat eepro100.rom 48kpad.bin > 2794FC60.FLS + +Next write it to a DOS Floppy: + + $ mount -t msdos /dev/fd0 /mnt/floppy + $ cp 2794FC60.FLS /mnt/floppy + $ umount /mnt/floppy + +Now you need to get to DOS. You could actually use a bootable DOS floppy +with FBOOT.EXE and 2794FC60.FLS on it. I started a Windows box and hit +F8 right before Windows started, and chose option 5, "Command Prompt +Only", which gives you DOS. This program can't run in a DOS window under +Windows or anything like that. You need to be in real DOS. + +Next it's time to run FBOOT. It will detect your ethernet card(s), ask +you which one you want to program, and let you choose it from a menu. + +now the fun part: + + Select Option (U)pdate or (R)estore: R + Erasing FLASH Device... 100% + Writing FLASH image from file... 100% + +Time to reboot and let Etherboot take over. + +So there you go, a way to make Intel EEPRO100Bs play nicely with +Etherboot. Maybe we should put these instructions in the Etherboot +contrib directory so people who have eepro100b cards will be able to +avoid 3C905C envy :-) + +I hope this helps a few people out. + +Regards, + +Marty + +--- + Name: Martin D. Connor +US Mail: Entity Cyber, Inc.; P.O. Box 391827; Cambridge, MA 02139; USA + Voice: (617) 491-6935, Fax: (617) 491-7046 + Email: mdc@thinguin.org + Web: http://www.thinguin.org/ diff --git a/contrib/eepro100notes/flash-3.txt b/contrib/eepro100notes/flash-3.txt new file mode 100644 index 0000000..1a865a4 --- /dev/null +++ b/contrib/eepro100notes/flash-3.txt @@ -0,0 +1,57 @@ +Date: Sun, 23 Jan 2000 09:47:15 +0100 (MET) +From: Erik Starbäck <erik@math.uu.se> +To: Netboot List <netboot@baghira.han.de> +Subject: Re: Look Mom, no PROM burner! (eepro100b flashing instructions) :-) +In-Reply-To: <1263512144-341319205@entity.com> +Message-ID: <Pine.LNX.3.96.1000123094505.28562A-100000@anarchy.math.uu.se> +MIME-Version: 1.0 +Content-Type: TEXT/PLAIN; charset=iso-8859-1 +Content-Transfer-Encoding: 8BIT +Sender: owner-netboot@baghira.han.de +Precedence: bulk +Reply-To: netboot@baghira.han.de +X-Moderator: netboot-owner@baghira.han.de + + +Hello! + +In <http://www.han.de/~gero/netboot/archive/msg01718.html> I wrote what I +did know about futil and fboot then. It is about the same as Martys +instructions, but I have a few comments now. + +> Then, see how large it is, with an "ls -l eepro100.rom". the answer will +> probably be 16,384. You need to pad it with hex FFs to make it 64K for +> FBOOT. I used the following two lines to create the flash image file. + +> $ perl -e 'print "\xFF" x 49152' > 48kpad.bin +> $ cat eepro100.rom 48kpad.bin > 2794FC60.FLS + +It worked for me without any padding. When I burned a smaller image +the program printed 50% instead of 100% and then it +stopped. Everything worked anyway. + + +I also did a brutal way of install etherboot or netboot on a +EEPRO100+Mng without creating a file of type "2794FC60.FLS" for +every card. It was necessary for me when I installed 70 clients... + +I chopped the binary file fboot.exe (my version was 99811 bytes, I +don't remember the version name) in three parts: + +fboot1 30096 bytes +fboot2 65536 bytes +fboot3 4179 bytes + +Then you cat put them together again, but with a different part 2 and +save it as fbootown.exe and execute it. It worked for me anyway. Of +course you have to use padding to get a 64k part instead of fboot2. + +/Erik S + +------------------------------------------------------------------------- +Erik Starbäck, System administrator E-mail address: erik@math.uu.se +Uppsala University Telephone (o): +46 18 4713277 +Department of Mathematics Cellular phone: +46 70 4250260 +P. O. Box 480 Fax (o): +46 18 4713201 +SE-751 06 UPPSALA +Sweden diff --git a/contrib/flashimg/Makefile b/contrib/flashimg/Makefile new file mode 100644 index 0000000..39f58e2 --- /dev/null +++ b/contrib/flashimg/Makefile @@ -0,0 +1,29 @@ +CPPFLAGS = -x assembler-with-cpp +AS86 = as86 +LD86 = ld86 +OBJDUMP = objdump + +.SUFFIXES: .s86 .asm .aout .img + +all: flashimg.img + +clean: + rm -rf *.o *.s86 *.aout *.img + +realclean: clean + rm -rf *.img + +.asm.s86: $*.asm $*.inc + $(CPP) $(CPPFLAGS) -o $@ $*.asm + +.s86.img: $*.s86 + $(AS86) -0 -b $@ $*.s86 + +# .s86.o: $*.s86 +# $(AS86) -0 -a -o $@ $*.s86 +# +# .o.aout: $*.o +# $(LD86) -0 -s -o $@ $*.o +# +# .aout.img: +# dd if=$*.aout of=$@ bs=32 skip=1 diff --git a/contrib/flashimg/flashimg.asm b/contrib/flashimg/flashimg.asm new file mode 100644 index 0000000..7a37ed5 --- /dev/null +++ b/contrib/flashimg/flashimg.asm @@ -0,0 +1,497 @@ +; Copyright (C) 1997 Markus Gutschke <gutschk@uni-muenster.de> +; +; 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; either version 2 of the License, or +; any later version. +; +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, write to the Free Software +; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +; Prepend this image file to an arbitrary ROM image. The resulting binary +; can be loaded from any BOOT-Prom that supports the "nbi" file format. +; When started, the image will reprogram the flash EPROM on the FlashCard +; ISA card. The flash EPROM has to be an AMD 29F010, and the programming +; algorithm is the same as that suggested by AMD in the appropriate data +; sheets. + + +#define SEGLOW 0xC800 /* lower range for EPROM segment */ +#define SEGHIGH 0xE800 /* upper range for EPROM segment */ +#define AMD_ID 0x2001 /* flash EPROM ID, only support AMD */ +#define ERASE1_CMD 0x80 /* first cmd for erasing full chip */ +#define ERASE2_CMD 0x10 /* second cmd for erasing full chip */ +#define READID_CMD 0x90 /* cmd to read chip ID */ +#define PROG_CMD 0xA0 /* cmd to program a byte */ +#define RESET_CMD 0xF0 /* cmd to reset chip state machine */ + +;---------------------------------------------------------------------------- + + + .text + .org 0 + +; .globl _main +_main: mov ax,#0x0FE0 + mov ds,ax + mov ax,magic ; verify that we have been loaded by + cmp ax,#0xE4E4 ; boot prom + jnz lderr + jmpi 0x200,0x0FE0 ; adjust code segment +lderr: mov si,#loaderr + cld +lderrlp:seg cs + lodsb ; loop over all characters of + or al,al ; string + jnz lderrnx + xor ah,ah + int 0x16 ; wait for keypress + jmpi 0x0000,0xFFFF ; reboot! +lderrnx:mov ah,#0x0E ; print it + mov bl,#0x07 + xor bh,bh + int 0x10 + jmp lderrlp + +loaderr:.ascii "The flash EPROM utility has to be loaded from a BOOT-Prom" + .byte 0xa,0xd + .ascii "that knows about the 'nbi' file format!" + .byte 0xa,0xd + .ascii "Reboot to proceed..." + .byte 0 + + .org 510 + .byte 0x55,0xAA + +!---------------------------------------------------------------------------- + +start: mov ax,cs + mov ds,ax + mov ax,romdata ; verify that there is an Prom image + cmp ax,#0xAA55 ; attached to the utility + jnz resmag + mov al,romdata+2 + or al,al ; non-zero size is required + jnz magicok +resmag: mov si,#badmagic ; print error message +reset: call prnstr + xor ah,ah + int 0x16 ; wait for keypress + jmpi 0x0000,0xFFFF ; reboot! +magicok:mov di,#clrline1 + mov si,#welcome ; print welcome message +inpnew: call prnstr +inprest:xor bx,bx + mov cl,#0xC ; expect 4 nibbles input data +inploop:xor ah,ah + int 0x16 + cmp al,#0x8 ; <Backspace> + jnz inpnobs + or bx,bx ; there has to be at least one input ch + jz inperr + mov si,#delchar ; wipe out char from screen + call prnstr + add cl,#4 ; compute bitmask for removing input + mov ch,cl + mov cl,#0xC + sub cl,ch + mov ax,#0xFFFF + shr ax,cl + not ax + and bx,ax + mov cl,ch +inploop1:jmp inploop +inpnobs:cmp al,#0x0D ; <Return> + jnz inpnocr + or bx,bx ; zero input -> autoprobing + jz inpdone + cmp cl,#-4 ; otherwise there have to be 4 nibbles + jz inpdone +inperr: mov al,#7 ; ring the console bell + jmp inpecho +inpnocr:cmp al,#0x15 ; <CTRL-U> + jnz inpnokl + mov si,di + call prnstr ; clear entire input and restart + jmp inprest +inpnokl:cmp cl,#-4 ; cannot input more than 4 nibbles + jz inperr + cmp al,#0x30 ; '0' + jb inperr + ja inpdig + or bx,bx ; leading '0' is not allowed + jz inperr +inpdig: cmp al,#0x39 ; '9' + ja inpnodg + mov ch,al + sub al,#0x30 +inpnum: xor ah,ah ; compute new input value + shl ax,cl + add ax,bx + test ax,#0x1FF ; test for 8kB boundary + jnz inperr + cmp ax,#SEGHIGH ; input has to be below E800 + jae inperr + cmp ax,#SEGLOW ; and above/equal C800 + jae inpok + cmp cl,#0xC ; if there is just one nibble, yet, + jnz inperr ; then the lower limit ix C000 + cmp ax,#0xC000 + jb inperr +inpok: mov bx,ax ; adjust bitmask + sub cl,#4 + mov al,ch +inpecho:call prnchr ; output new character + jmp inploop1 +inpnodg:and al,#0xDF ; lower case -> upper case + cmp al,#0x41 ; 'A' + jb inperr + cmp al,#0x46 ; 'F' + ja inperr + mov ch,al + sub al,#0x37 + jmp inpnum +inpdone:or bx,bx ; zero -> autoprobing + jnz probe + mov si,#automsg + call prnstr + mov cx,#0x10 + mov bx,#SEGHIGH ; scan from E800 to C800 +autoprb:sub bx,#0x0200 ; stepping down in 8kB increments + mov di,bx + call readid + cmp ax,#AMD_ID + jz prbfnd + loop autoprb + mov si,#failmsg +nofnd: mov di,#clrline2 + jmp near inpnew ; failure -> ask user for new input +probe: mov di,bx + test bx,#0x07FF ; EPROM might have to be aligned to + jz noalign ; 32kB boundary + call readid + cmp ax,#AMD_ID ; check for AMDs id + jz prbfnd + mov si,#alignmsg + call prnstr + and bx,#0xF800 ; enforce alignment of hardware addr +noalign:call readid ; check for AMDs id + cmp ax,#AMD_ID + jz prbfnd + mov si,#nofndmsg ; could not find any EPROM at speci- + call prnstr ; fied location --- even tried + mov si,#basemsg ; aligning to 32kB boundary + jmp nofnd ; failure -> ask user for new input +prbfnd: mov si,#fndmsg + call prnstr ; we found a flash EPROM + mov ax,bx + call prnwrd + mov si,#ersmsg + call prnstr + call erase ; erase old contents + jnc ersdone + mov si,#failresmsg ; failure -> reboot machine + jmp near reset +ersdone:mov si,#prg1msg ; tell user that we are about + call prnstr ; to program the new data into + mov ax,di ; the specified range + call prnwrd + mov si,#prg2msg + call prnstr + xor dh,dh + mov dl,romdata+2 + shl dx,#1 + mov ah,dh + mov cl,#4 + shl ah,cl + xor al,al + add ax,di + call prnwrd + mov al,#0x3A ; ':' + call prnchr + mov ah,dl + xor al,al + dec ax + call prnwrd + mov al,#0x20 + call prnchr + mov dh,romdata+2 ; number of 512 byte blocks + push ds + mov ax,ds + add ax,#romdata>>4 ; adjust segment descriptor, so that + mov ds,ax ; we can handle images which are +prgloop:mov cx,#0x200 ; larger than 64kB + xor si,si + xor bp,bp + call program ; program 512 data bytes + jc prgerr ; check error condition + mov ax,ds + add ax,#0x20 ; increment segment descriptors + mov ds,ax + add di,#0x20 + dec dh ; decrement counter + jnz prgloop + pop ds + mov si,#donemsg ; success -> reboot +prgdone:call prnstr + mov si,#resetmsg + jmp near reset +prgerr: pop ds ; failure -> reboot + mov si,#failresmsg + jmp prgdone + + +;---------------------------------------------------------------------------- + +; READID -- read EPROM id number, base address is passed in BX +; ====== +; +; changes: AX, DL, ES + +readid: mov dl,#RESET_CMD ; reset chip + call sendop + mov dl,#READID_CMD + call sendop ; send READID command + mov es,bx + seg es + mov ax,0x00 ; read manufacturer ID + mov dl,#RESET_CMD + jmp sendop ; reset chip + + +;---------------------------------------------------------------------------- + +; ERASE -- erase entire EPROM, base address is passed in BX +; ===== +; +; changes: AL, CX, DL, ES, CF + +erase: mov dl,#ERASE1_CMD + call sendop ; send ERASE1 command + mov dl,#ERASE2_CMD + call sendop ; send ERASE2 command + xor bp,bp + mov al,#0xFF + push di + mov di,bx + call waitop ; wait until operation finished + pop di + jnc erfail + mov dl,#RESET_CMD + call sendop ; reset chip + stc +erfail: ret + + +;---------------------------------------------------------------------------- + +; PROGRAM -- write data block at DS:SI of length CX into EPROM at DI:BP +; ======= +; +; changes: AX, CX, DL, BP, ES, CF + +program:mov dl,#PROG_CMD + call sendop ; send programming command + lodsb ; get next byte from buffer + mov es,di + seg es + mov byte ptr [bp],al ; write next byte into flash EPROM + call waitop ; wait until programming operation is + jc progdn ; completed + inc bp + loop program ; continue with next byte + clc ; return without error +progdn: ret + + +;---------------------------------------------------------------------------- + +; SENDOP -- send command in DL to EPROM, base address is passed in BX +; ====== +; +; changes: ES + +sendop: mov es,bx + seg es + mov byte ptr 0x5555,#0xAA ; write magic data bytes into + jcxz so1 ; magic locations. This unlocks +so1: jcxz so2 ; the flash EPROM. N.B. that the +so2: seg es ; magic locations are mirrored + mov byte ptr 0x2AAA,#0x55 ; every 32kB; the hardware address + jcxz so3 ; might have to be adjusted to a +so3: jcxz so4 ; 32kB boundary +so4: seg es + mov byte ptr 0x5555,dl + ret + + +;---------------------------------------------------------------------------- + +; WAITOP -- wait for command to complete, address is passed in DI:BP +; ====== +; +; for details on the programming algorithm, c.f. http://www.amd.com +; +; changes: AX, DL, ES, CF + +waitop: and al,#0x80 ; monitor bit 7 + mov es,di +wait1: seg es ; read contents of EPROM cell that is + mov ah,byte ptr [bp] ; being programmed + mov dl,ah + and ah,#0x80 + cmp al,ah ; bit 7 indicates sucess + je waitok + test dl,#0x20 ; bit 5 indicates timeout/error + jz wait1 ; otherwise wait for cmd to complete + seg es + mov ah,byte ptr [bp] ; check error condition once again, + and ah,#0x80 ; because bits 7 and 5 can change + cmp al,ah ; simultaneously + je waitok + stc + ret +waitok: clc + ret + +;---------------------------------------------------------------------------- + +; PRNSTR -- prints a string in DS:SI onto the console +; ====== +; +; changes: AL + +prnstr: push si + cld +prns1: lodsb ; loop over all characters of + or al,al ; string + jz prns2 + call prnchr ; print character + jmp prns1 +prns2: pop si + ret + + +;---------------------------------------------------------------------------- + +; PRNWRD, PRNBYT, PRNNIB, PRNCHR -- prints hexadezimal values, or ASCII chars +; ====== ====== ====== ====== +; +; changes: AX + +prnwrd: push ax + mov al,ah + call prnbyt ; print the upper byte + pop ax +prnbyt: push ax + shr al,1 ; prepare upper nibble + shr al,1 + shr al,1 + shr al,1 + call prnnib ; print it + pop ax +prnnib: and al,#0x0F ; prepare lower nibble + add al,#0x30 + cmp al,#0x39 ; convert it into hex + jle prnchr + add al,#7 +prnchr: push bx + mov ah,#0x0E ; print it + mov bl,#0x07 + xor bh,bh + int 0x10 + pop bx + ret + + +;---------------------------------------------------------------------------- + +magic: .byte 0xE4,0xE4 + +badmagic:.byte 0xa,0xd + .ascii "There does not appear to be a ROM image attached to the" + .ascii "flash EPROM utility;" + .byte 0xa,0xd +resetmsg:.ascii "Reboot to proceed..." + .byte 0 + +welcome:.byte 0xa,0xd + .ascii "Flash EPROM programming utility V1.0" + .byte 0xa,0xd + .ascii "Copyright (c) 1997 by M. Gutschke <gutschk@uni-muenster.de>" + .byte 0xa,0xd + .ascii "===========================================================" + .byte 0xa,0xd +prompt: .byte 0xa,0xd + .ascii "Enter base address for AMD29F010 flash EPROM on FlashCard or" + .byte 0xa,0xd + .ascii "press <RETURN> to start autoprobing; the base address has" + .byte 0xa +clrline1:.byte 0xd + .ascii "to be in the range C800..E600: " + .ascii " " + .byte 0x8,0x8,0x8,0x8 + .byte 0 + +delchar:.byte 0x8,0x20,0x8 + .byte 0 + +automsg:.ascii "autoprobing... " + .byte 0 + +failmsg:.ascii "failed!" +basemsg:.byte 0xa +clrline2:.byte 0xd + .ascii "Enter base address: " + .ascii " " + .byte 0x8,0x8,0x8,0x8 + .byte 0 + +fndmsg: .byte 0xa,0xd + .ascii "Found flash EPROM at: " + .byte 0 + +alignmsg:.byte 0xa,0xd + .ascii "FlashCard requires the hardware address to be aligned to a" + .byte 0xa,0xd + .ascii "32kB boundary; automatically adjusting..." + .byte 0 + +nofndmsg:.byte 0xa,0xd + .ascii "No AMD29F010 flash EPROM found" + .byte 0 + +ersmsg: .byte 0xa,0xd + .ascii "Erasing old contents... " + .byte 0 + +prg1msg:.ascii "done" + .byte 0xa,0xd + .ascii "Programming from " + .byte 0 + +prg2msg:.ascii ":0000 to " + .byte 0 + +donemsg:.ascii "done!" + .byte 0xa,0xd + .byte 0 + +failresmsg: + .ascii "failed!" + .byte 0xa,0xd + .byte 0 + + +;---------------------------------------------------------------------------- + + .align 16 + .org *-1 + .byte 0x00 +romdata: diff --git a/contrib/flashimg/flashimg.img b/contrib/flashimg/flashimg.img Binary files differnew file mode 100644 index 0000000..263d339 --- /dev/null +++ b/contrib/flashimg/flashimg.img diff --git a/contrib/hdload/Makefile b/contrib/hdload/Makefile new file mode 100644 index 0000000..9ed750d --- /dev/null +++ b/contrib/hdload/Makefile @@ -0,0 +1,15 @@ +# Use nasm or as86 +ASM=nasm +# ASM=as86 + +hdload.bin: hdload.S +ifeq ($(ASM),as86) + gcc $(CFLAGS) -DUSE_AS86 -E -traditional -o hdload.s hdload.S + as86 -0 -b hdload.bin hdload.s +else + gcc $(CFLAGS) -DUSE_NASM -E -traditional -o hdload.s hdload.S + nasm -f bin hdload.s -o hdload.bin +endif + +clean: + $(RM) -f hdload.s hdload.bin diff --git a/contrib/hdload/hdload.S b/contrib/hdload/hdload.S new file mode 100644 index 0000000..3bb5649 --- /dev/null +++ b/contrib/hdload/hdload.S @@ -0,0 +1,162 @@ +#if !defined(USE_NASM) && !defined(USE_AS86)
+#define USE_AS86
+#endif
+
+#ifdef USE_AS86
+#define CON(x) *x
+#define BCON(x) *x
+#define WCON(x) *x
+#define LOC(x) x
+#define BLOC(x) byte ptr x
+#define WLOC(x) word ptr x
+#define JMP(x) jmp x
+#define STRDECL(s) .ascii s
+#define SEGCS seg cs
+#define SEGES seg es
+#define ALIGN(x) .align x
+#define SPACE(x) .space x
+#endif
+
+#ifdef USE_NASM
+#define CON(x) x
+#define BCON(x) byte x
+#define WCON(x) word x
+#define LOC(x) [x]
+#define BLOC(x) byte [x]
+#define WLOC(x) word [x]
+#define JMP(x) jmp short x
+#define STRDECL(s) db s
+#define SEGCS cs
+#define SEGES es
+#define ALIGN(x) align x, db 0
+#define SPACE(x) times x db 0
+#endif
+
+ROMLOAD equ 0x5000
+
+start:
+ cli
+ xor ax, ax
+ mov ss, ax
+ mov sp, CON(0x7C00)
+ mov si, sp
+ mov es, ax
+ mov ds, ax
+ sti
+ cld
+ mov di, CON(0x600)
+ mov cx, CON(0x100)
+ rep
+ movsw
+ db 0xEA
+ dw jump
+ dw 0
+jump:
+ mov si, CON(Hlaska)
+ call print
+
+ ; rozmery prvniho HD
+ mov ah, CON(8)
+ mov dl, CON(0x80)
+ int 0x13
+ jc chyba
+ ; dh - H, cx - CS
+
+ ; prvi stopa obsahuje bootrom, tak ji natahneme do RAM
+ mov ah, CON(2)
+ mov al, cl
+ and al, CON(0x3F)
+ dec al
+ mov dx, CON(0x80)
+ mov cx, CON(2)
+ mov bx, CON(ROMLOAD)
+ mov es, bx
+ xor bx, bx
+ int 0x13
+ jc chyba
+
+ ; hromada kodu podle zdrojaku netboot
+ xor di, di
+ mov es, di
+ mov di, CON(0x380)
+ push di
+ mov cx, CON(10)
+ cld
+ rep
+ stosw
+ pop di
+#ifdef USE_AS86
+ mov word ptr [ di ], CON(0x5a5a)
+ mov byte ptr [ di + 2 ], CON(0x50)
+ mov word ptr [ di + 0x10 ], CON(0xFFFF)
+ mov word ptr [ di + 0x12 ], CON(0xFFFF)
+#endif
+#ifdef USE_NASM
+ mov word [ di ], CON(0x5a5a)
+ mov byte [ di + 2 ], CON(0x50)
+ mov word [ di + 10h ], CON(0xFFFF)
+ mov word [ di + 12h ], CON(0xFFFF)
+#endif
+
+ ; navratova adresa, kdyby nezabrala ROM
+ SEGCS
+ mov WLOC(OfsErr), CON(RomErr)
+ push cs
+ push WCON(chyba)
+ mov ax, CON(ROMLOAD)
+ mov es, ax
+ push es
+ ; kouzelny jump....
+ SEGES
+ mov si, [ 0x1a ]
+ SEGES
+#ifdef USE_AS86
+ push word ptr [ si + 0x1a ] ; ...do bootrom v RAM
+#endif
+#ifdef USE_NASM
+ push word [ si + 0x1a ] ; ...do bootrom v RAM
+#endif
+ retf
+
+chyba:
+ SEGCS
+ mov si, LOC(OfsErr)
+ call print
+ mov si, CON(CRLF)
+ call print
+ JMP(chyba)
+
+print:
+ lodsb
+ cmp al,CON(0)
+ je navrat
+ push si
+ mov bx,CON(7)
+ mov ah,CON(0x0E)
+ int 0x10
+ pop si
+ JMP(print)
+
+navrat:
+ ret
+
+Hlaska: db 13, 10
+ STRDECL('HD Net Loader v1.0 (c) poli 1999')
+ db 13, 10, 0
+CRLF: db 13, 10, 0
+OfsErr: dw Error
+Error: STRDECL('Error load from HD !')
+ db 0
+RomErr: STRDECL('ROM Error !')
+ db 0
+
+mbrend:
+ ret
+
+#ifdef USE_AS86
+ org 510
+#endif
+#ifdef USE_NASM
+ times 510-($-$$) db 0
+#endif
+ dw 0xAA55
diff --git a/contrib/hdload/petr.msg b/contrib/hdload/petr.msg new file mode 100644 index 0000000..a3134d0 --- /dev/null +++ b/contrib/hdload/petr.msg @@ -0,0 +1,175 @@ +From netboot-owner@baghira.han.de Thu Sep 16 12:08:44 1999 +Return-Path: <netboot-owner@baghira.han.de> +Received: (from factotum@localhost) + by baghira.han.de (8.9.3/8.9.3) id NAA23838 + for netboot-outgoing; Wed, 15 Sep 1999 13:12:44 +0200 +X-Authentication-Warning: baghira.han.de: factotum set sender to owner-netboot using -f +Received: from hathi.han.de (root@hathi.han.de [192.109.225.1]) + by baghira.han.de (8.9.3/8.9.3) with ESMTP id NAA23785 + for <netboot@baghira.han.de>; Wed, 15 Sep 1999 13:11:02 +0200 +Received: from vsb.cz (root@decsys.vsb.cz [158.196.149.9]) + by hathi.han.de (8.9.3/8.9.3) with ESMTP id NAA04707 + for <netboot@baghira.han.de>; Wed, 15 Sep 1999 13:11:00 +0200 +Received: from nwfei1.vsb.cz (nwfei1.vsb.cz [158.196.146.13]) + by vsb.cz (8.9.3/8.9.1) with ESMTP id NAA22363 + for <netboot@baghira.han.de>; Wed, 15 Sep 1999 13:10:52 +0200 (MET DST) +Received: from FEI1/SpoolDir by nwfei1.vsb.cz (Mercury 1.44); + 15 Sep 99 13:10:50 +0100 +Received: from SpoolDir by FEI1 (Mercury 1.44); 15 Sep 99 13:10:27 +0100 +Received: from pcd403z.vsb.cz (158.196.146.9) by nwfei1.vsb.cz (Mercury 1.44) with ESMTP; + 15 Sep 99 13:10:25 +0100 +Received: from oli10 by pcd403z.vsb.cz with local-esmtp (Exim 2.05 #1 (Debian)) + id 11RCxI-0000oT-00; Wed, 15 Sep 1999 13:10:28 +0200 +Date: Wed, 15 Sep 1999 13:10:28 +0200 (CEST) +From: Petr Olivka <Petr.Olivka@vsb.cz> +To: netboot@baghira.han.de +Subject: netboot image on hard disk - it is easy +In-Reply-To: <37DF4BD4.E8FFF8FC@gsmbox.com> +Message-ID: <Pine.LNX.4.10.9909151247430.2936-100000@pcd403z.vsb.cz> +MIME-Version: 1.0 +Content-Type: TEXT/PLAIN; charset=US-ASCII +Sender: owner-netboot@baghira.han.de +Precedence: bulk +Reply-To: netboot@baghira.han.de +X-Moderator: netboot-owner@baghira.han.de + +It is good joke, at this moment I have only simple version of MBR to load +image from HD, but only from track 0. HD have to have enough sectors per +track for rom image. +And small program in turbo-pascal to download image to HD. + +below is assembler code for MBR. Is writen for tasm and tlink. +If you have 512 bytes binary file with MBR code, then concat it with +rom-image and download to hda. BUT NOT DIRECTLY !!!! You have to copy +partition table ( and NT signature ) to MBR and then download. BUT ONLY tO +TRACK 0. + +Everything in your own risk. + +If I will have some free time, I will write some code directly to netboot. + +poli + +.model large, pascal + +.code +.386 + public mbrasm, mbrend + +ROMLOAD equ 5000h + + org 600h + +mbrasm proc + + cli + xor ax, ax + mov ss, ax + mov sp, 7C00h + mov si, sp + mov es, ax + mov ds, ax + sti + cld + mov di, 600h + mov cx, 100h + rep movsw + db 0EAh + dw offset @@jump + dw 0 +@@jump: + mov si, offset Hlaska + call @@print + + ; rozmery prvniho HD + mov ah, 8 + mov dl, 80h + int 13h + jc @@chyba + ; dh - H, cx - CS + + ; prvi stopa obsahuje bootrom, tak ji natahneme do RAM + mov ah, 2 + mov al, cl + and al, 3Fh + dec al + mov dx, 80h + mov cx, 2 + mov bx, ROMLOAD + mov es, bx + xor bx, bx + int 13h + jc @@chyba + + ; hromada kodu podle zdrojaku netboot + xor di, di + mov es, di + mov di, 380h + push di + mov cx, 10 + cld + rep stosw + pop di + mov word ptr [ di ], 5a5ah + mov byte ptr [ di + 2 ], 50h + mov word ptr [ di + 10h ], 0FFFFh + mov word ptr [ di + 12h ], 0FFFFh + + ; navratova adresa, kdyby nezabrala ROM + mov OfsErr, offset RomErr + push cs + push offset @@chyba + + mov ax, ROMLOAD + mov es, ax + push es + ; kouzelny jump.... + mov si, es:[ 1ah ] + push word ptr es:[ si + 1ah ] ; ...do bootrom v RAM + retf + +@@chyba: + mov si, OfsErr + call @@print + mov si, offset CRLF + call @@print + jmp @@chyba + +@@print: + lodsb + cmp al,0 + je @@navrat + push si + mov bx,7 + mov ah,0Eh + int 10h + pop si + jmp @@print + +@@navrat: + retn + +Hlaska db 13, 10, 'HD Net Loader v1.0 (c) poli 1999', 13, 10, 0 +CRLF db 13, 10, 0 +OfsErr dw offset Error +Error db 'Error load from HD !', 0 +RomErr db 'ROM Error !', 0 + +mbrasm endp + +mbrend proc + ret +mbrend endp + + org 800h - 2 + dw 0AA55h + +end + +=========================================================================== +This Mail was sent to netboot mailing list by: +Petr Olivka <Petr.Olivka@vsb.cz> +To get help about this list, send a mail with 'help' as the only string in +it's body to majordomo@baghira.han.de. If you have problems with this list, +send a mail to netboot-owner@baghira.han.de. + diff --git a/contrib/initrd/ChangeLog b/contrib/initrd/ChangeLog new file mode 100644 index 0000000..94f8f6a --- /dev/null +++ b/contrib/initrd/ChangeLog @@ -0,0 +1,46 @@ +mkinitrd-net ChangeLog + +Last Modified: Fri Jul 26 23:08:28 2002 + +$Log$ +Revision 1.1 2005/05/17 16:45:02 mcb30 +Initial revision + +Revision 1.1 2002/11/06 06:31:06 ken_yap +Contributed by Michael Brown. + +Revision 1.10 2002/07/26 23:09:13 mcb30 +Support for new binary etherboot.nic-dev-id structure +Added --kernel option patch from Stew Benedict at MandrakeSoft +Only try to use sudo if we are not already root + +Revision 1.9 2002/06/05 13:31:50 mcb30 +Modifications to allow DHCP, TFTP and NFS servers to be separate machines. + +Revision 1.8 2002/05/30 11:41:18 mcb30 +/tftpboot symlinked to /var/lib/tftpboot +Has ability to be quiet if "quiet" specified on kernel cmdline + +Revision 1.7 2002/05/26 11:15:04 mcb30 +PCI-ID auto-mapping via dhcpd.conf.etherboot-pcimap.include + +Revision 1.6 2002/05/24 02:05:11 mcb30 +Bugfixes, migrated /tftpboot to /var/lib/tftpboot + +Revision 1.5 2002/05/23 21:29:58 mcb30 +Now includes dhcpd.conf.etherboot.include +Automatically scans for all network modules in the pcimap file + +Revision 1.4 2002/05/08 09:04:31 mcb30 +Bugfixes: tmpdir selection, linuxrc typos, ifconfig peculiarities + +Revision 1.3 2002/05/04 21:44:13 mcb30 +During %make, LIBDIR must be set for mknbi +Added %post scriptlet since %trigger seems not to be being triggered... + +Revision 1.2 2002/05/04 21:20:32 mcb30 +Added extra sources instead of requiring "make" to download them + +Revision 1.1 2002/05/04 13:19:40 mcb30 +First attempt at an RPM package + diff --git a/contrib/initrd/Makefile b/contrib/initrd/Makefile new file mode 100644 index 0000000..f18b73f --- /dev/null +++ b/contrib/initrd/Makefile @@ -0,0 +1,187 @@ +UCLIBC_VERSION = 0.9.11 +UCLIBC = uClibc-$(UCLIBC_VERSION) +$(UCLIBC)_SOURCE = http://www.uclibc.org/downloads/$(UCLIBC).tar.bz2 +UCLIBC_INSTALL = $(CURDIR)/uClibc + +UDHCP_VERSION = 0.9.7 +UDHCP = udhcp-$(UDHCP_VERSION) +$(UDHCP)_SOURCE = http://udhcp.busybox.net/source/$(UDHCP).tar.gz + +BUSYBOX_VERSION = 0.60.3 +BUSYBOX = busybox-$(BUSYBOX_VERSION) +$(BUSYBOX)_SOURCE = http://www.busybox.net/downloads/$(BUSYBOX).tar.bz2 + +LINUX_WLAN_VERSION = 0.1.13 +LINUX_WLAN = linux-wlan-ng-$(LINUX_WLAN_VERSION) +$(LINUX_WLAN)_SOURCE = ftp://ftp.linux-wlan.org/pub/linux-wlan-ng/$(LINUX_WLAN).tar.gz + +MKNBI_VERSION = 1.2 +MKNBI = mknbi-$(MKNBI_VERSION) +$(MKNBI)_SOURCE = http://belnet.dl.sourceforge.net/sourceforge/etherboot/$(MKNBI).tar.gz + +export PATH := $(UCLIBC_INSTALL)/bin:$(PATH) + +all : utils initrd-skel mknbi mknbi-linux + # Run "make tftpboot/initrd-kernel_module.img" to generate a suitable initrd + # Run "make tftpboot/boot-kernel_module.nbi" to generate a suitable NBI + # Run "make all-nbi" to generate a complete set of NBIs + +%.tar.bz2 : + [ -d $* ] || wget $($*_SOURCE) + [ -f $*.t*gz ] && ( gunzip $*.t*gz ; bzip2 -9 $*.tar ) || true + +UTILS = udhcpc busybox wlanctl + +utils : $(UTILS) + +clean : partlyclean + rm -rf uClibc + rm -rf $(UCLIBC) + rm -rf tftpboot/* + +partlyclean : + rm -rf $(UDHCP) + rm -rf $(BUSYBOX) + rm -rf $(LINUX_WLAN) + rm -rf $(MKNBI) + rm -rf initrd-skel + rm -f *.img *.ird *.nbi insert-modules + rm -f $(UTILS) mknbi-linux + rm -f *.uClibc *.busybox *.udhcpc *.wlanctl + +.PHONY : all utils clean partlyclean + +uClibc : $(UCLIBC) + rm -rf $@ + $(MAKE) -C $(UCLIBC) install + +$(UCLIBC) : $(UCLIBC).tar.bz2 + [ -d $@ ] || tar xvjf $< + [ -f $(UCLIBC)/Config ] || perl -pe 's/^(INCLUDE_RPC).*/$$1 = true/ ;' \ + -e 's{^(DEVEL_PREFIX).*}{$$1 = $(UCLIBC_INSTALL)} ;' \ + -e 's{^(SHARED_LIB_LOADER_PATH).*}{$$1 = /lib} ;' \ + $(UCLIBC)/extra/Configs/Config.i386 > $(UCLIBC)/Config + # Stripping out spurious CVS directories (screws up local cvs update) + rm -rf `find $(UCLIBC) -name CVS` + $(MAKE) -C $(UCLIBC) + install -m 644 $(UCLIBC)/COPYING.LIB COPYING.uClibc + +udhcpc : $(UDHCP) + install -m 755 -s $(UDHCP)/$@ $@ + +$(UDHCP) : $(UDHCP).tar.bz2 uClibc + [ -d $@ ] || tar xvjf $< + if [ ! -f $@/.script.c.patch ]; then \ + patch -d $@ -b -z .orig < script.c.patch ; \ + touch $@/.script.c.patch ; \ + fi + $(MAKE) LDFLAGS+=-static -C $(UDHCP) + install -m 644 $(UDHCP)/AUTHORS AUTHORS.udhcpc + install -m 644 $(UDHCP)/COPYING COPYING.udhcpc + +busybox : $(BUSYBOX) + install -m 755 -s $(BUSYBOX)/$@ $@ + +$(BUSYBOX) : $(BUSYBOX).tar.bz2 uClibc + [ -d $@ ] || tar xvjf $< + perl -pi.orig -e \ + 's/^.*(#define BB_(FEATURE_NFSMOUNT|INSMOD|PIVOT_ROOT|IFCONFIG|ROUTE)).*/$$1/' \ + $(BUSYBOX)/Config.h + perl -pi.orig -e \ + 's/^(DOSTATIC).*$$/$$1 = true/' \ + $(BUSYBOX)/Makefile + $(MAKE) -C $(BUSYBOX) + install -m 644 $(BUSYBOX)/AUTHORS AUTHORS.busybox + install -m 644 $(BUSYBOX)/LICENSE LICENSE.busybox + +wlanctl : $(LINUX_WLAN) + install -m 755 -s $(LINUX_WLAN)/src/wlanctl/$@ $@ + +$(LINUX_WLAN) : $(LINUX_WLAN).tar.bz2 uClibc linux-wlan.cfg + [ -d $@ ] || tar xvjf $< + cd $(LINUX_WLAN) ; ./Configure -d ../linux-wlan.cfg + perl -pi.orig -e \ + 's/(-o wlanctl)/-static $$1/' \ + $(LINUX_WLAN)/src/wlanctl/Makefile + $(MAKE) -C $(LINUX_WLAN)/src/wlanctl + install -m 644 $(LINUX_WLAN)/COPYING COPYING.wlanctl + install -m 644 $(LINUX_WLAN)/LICENSE LICENSE.wlanctl + install -m 644 $(LINUX_WLAN)/THANKS THANKS.wlanctl + +mknbi-linux : $(MKNBI) + +mknbi : $(MKNBI) + +$(MKNBI) : $(MKNBI).tar.bz2 + [ -d $@ ] || tar xvjf $< + if [ ! -f $@/.mknbi-encap.patch ]; then \ + patch -d $@ -b -z .orig < mknbi-encap.patch ; \ + touch $@/.mknbi-encap.patch ; \ + fi + make -C $(MKNBI) LIBDIR=`pwd`/$(MKNBI) mknbi + install -m 755 $(MKNBI)/mknbi mknbi-linux + make -C $(MKNBI) clean + make -C $(MKNBI) + +initrd-skel : $(UTILS) linuxrc udhcpc-post include-modules + rm -rf $@ + mkdir -p $@ + mkdir -p $@/dev + mkdir -p $@/etc + mkdir -p $@/bin + mkdir -p $@/lib + mkdir -p $@/lib/modules + mkdir -p $@/proc + mkdir -p $@/sysroot + ln -s bin $@/sbin + install -m 755 busybox $@/bin/ + install -m 755 udhcpc $@/bin/ + install -m 755 wlanctl $@/bin/ + ln -s busybox $@/bin/sh + ln -s busybox $@/bin/echo + ln -s busybox $@/bin/mknod + ln -s busybox $@/bin/chmod + ln -s busybox $@/bin/insmod + ln -s busybox $@/bin/ifconfig + ln -s busybox $@/bin/route + ln -s busybox $@/bin/mount + ln -s busybox $@/bin/pivot_root + ln -s busybox $@/bin/umount + ln -s busybox $@/bin/[ + ln -s busybox $@/bin/sleep + ln -s busybox $@/bin/grep + + install -m 755 linuxrc $@/linuxrc + install -m 755 udhcpc-post $@/bin/udhcpc-post + +tftpboot/initrd-%.img : initrd-skel + ./mkinitrd-net -l `echo $* | tr . " "` + +tftpboot/boot-%.nbi : tftpboot/initrd-%.img mknbi-linux + ./mknbi-linux --format=nbi --target=linux /boot/vmlinuz $< > $@ + sudo cp $@ $(tftpbootdir) + +all-nbi : all + ./mknbi-set -l -v + ls tftpboot + +prefix = /usr +sysconfdir = /etc +bindir = $(prefix)/bin +libdir = $(prefix)/lib +mandir = $(prefix)/share/man +docdir = $(prefix)/share/doc +tftpbootdir = /var/lib/tftpboot +initrdskeldir = $(prefix)/lib/mkinitrd-net/initrd-skel + +install : + mkdir -p $(libdir)/mknbi + mkdir -p $(bindir) + mkdir -p $(sysconfdir) + mkdir -p $(tftpbootdir) + mkdir -p $(initrdskeldir) + install -m 755 mkinitrd-net include-modules mknbi-set $(bindir)/ + cp -a initrd-skel/* $(initrdskeldir)/ + install -m 644 mknbi-set.conf dhcpd.conf.etherboot.include $(sysconfdir) + make -C $(MKNBI) INSTPREFIX=$(prefix) MANDIR=$(mandir)/man1 \ + DOCDIR=$(docdir)/$(MKNBI) install diff --git a/contrib/initrd/Manifest b/contrib/initrd/Manifest new file mode 100644 index 0000000..b41e725 --- /dev/null +++ b/contrib/initrd/Manifest @@ -0,0 +1,15 @@ +initrd/ChangeLog +initrd/Makefile +initrd/Manifest +initrd/README +initrd/dhcpd.conf.etherboot.include +initrd/include-modules +initrd/linux-wlan.cfg +initrd/linuxrc +initrd/mkinitrd-net +initrd/mkinitrd-net.spec +initrd/mknbi-encap.patch +initrd/mknbi-set +initrd/mknbi-set.conf +initrd/script.c.patch +initrd/udhcpc-post diff --git a/contrib/initrd/README b/contrib/initrd/README new file mode 100644 index 0000000..5152425 --- /dev/null +++ b/contrib/initrd/README @@ -0,0 +1,37 @@ +README for mkinitrd-net + +mkinitrd-net enables you to use your distribution's stock kernel for +diskless workstations, without having to compile in support for the +relevant network card(s). It creates an initial ramdisk image containing +the required network-card kernel modules and bootstrap scripts to load the +module, obtain an IP address via DHCP and mount the root filesystem via +NFS. + +mkinitrd-net also generates a dhcpd.conf file fragment that can be used to +automate the process of mapping NBI files to clients, based on the PCI IDs +of their network cards. Etherboot will send the PCI ID of the network +card to the DHCP server in the etherboot-encapsulated-options field +(Etherboot 5.0.7 and newer) and the DHCP server can use this to identify +the correct NBI to point the client towards. + +The end result is that: + +a) You can avoid the hassle of compiling custom kernels for diskless + workstations. + +b) Diskless workstations will automatically download the correct + kernel+initrd. + +c) You have an easier life! :-) + + + +mkinitrd-net is Copyright Fen Systems Ltd. 2001. mkinitrd-net itself is +licensed under the GNU GPL. It incorporates code from the uClibc, +busybox, udhcpc and Etherboot projects, each of which has its own licence +terms. Standard disclaimers apply. + +The copy of mkinitrd-net in the Etherboot contribs is not the +authoritative copy of mkinitrd-net; please do not make modifications to +this copy. Patches should be sent to Michael Brown +<mbrown@fensystems.co.uk>. diff --git a/contrib/initrd/dhcpd.conf.etherboot.include b/contrib/initrd/dhcpd.conf.etherboot.include new file mode 100644 index 0000000..9cec1dc --- /dev/null +++ b/contrib/initrd/dhcpd.conf.etherboot.include @@ -0,0 +1,207 @@ +# dhcpd.conf include file for Etherboot +# +# Include this file from your /etc/dhcpd.conf +# $Id$ + +# Definition of Etherboot options +# (taken from vendortags.html) + +# We use an encapsulated option space to avoid polluting the site-local DHCP option space +# +option space etherboot; +option etherboot-encapsulated-options code 150 = encapsulate etherboot; + +# Definition of option codes within the etherboot-encapsulated-options space +# +option etherboot.extensions-path code 18 = string; +option etherboot.magic code 128 = string; +option etherboot.kernel-cmdline code 129 = string; +option etherboot.menu-opts code 160 = string; +option etherboot.nic-dev-id code 175 = string; +option etherboot.menu-selection code 176 = unsigned integer 8; +option etherboot.motd-1 code 184 = string; +option etherboot.motd-2 code 185 = string; +option etherboot.motd-3 code 186 = string; +option etherboot.motd-4 code 187 = string; +option etherboot.motd-5 code 188 = string; +option etherboot.motd-6 code 189 = string; +option etherboot.motd-7 code 190 = string; +option etherboot.motd-8 code 191 = string; +option etherboot.image-1 code 192 = string; +option etherboot.image-2 code 193 = string; +option etherboot.image-3 code 194 = string; +option etherboot.image-4 code 195 = string; +option etherboot.image-5 code 196 = string; +option etherboot.image-6 code 197 = string; +option etherboot.image-7 code 198 = string; +option etherboot.image-8 code 199 = string; +option etherboot.image-9 code 200 = string; +option etherboot.image-10 code 201 = string; +option etherboot.image-11 code 202 = string; +option etherboot.image-12 code 203 = string; +option etherboot.image-13 code 204 = string; +option etherboot.image-14 code 205 = string; +option etherboot.image-15 code 206 = string; +option etherboot.image-16 code 207 = string; +option etherboot.kmod code 254 = string; + +# Legacy support for Etherboot options as site-local options (i.e. non-encapsulated) +# Note: options defined after the switch to encapsulated options should not be defined here +# +option legacy-etherboot-magic code 128 = string; +option legacy-etherboot-kernel-cmdline code 129 = string; +option legacy-etherboot-menu-opts code 160 = string; +option legacy-etherboot-menu-selection code 176 = unsigned integer 8; +option legacy-etherboot-motd-1 code 184 = string; +option legacy-etherboot-motd-2 code 185 = string; +option legacy-etherboot-motd-3 code 186 = string; +option legacy-etherboot-motd-4 code 187 = string; +option legacy-etherboot-motd-5 code 188 = string; +option legacy-etherboot-motd-6 code 189 = string; +option legacy-etherboot-motd-7 code 190 = string; +option legacy-etherboot-motd-8 code 191 = string; +option legacy-etherboot-image-1 code 192 = string; +option legacy-etherboot-image-2 code 193 = string; +option legacy-etherboot-image-3 code 194 = string; +option legacy-etherboot-image-4 code 195 = string; +option legacy-etherboot-image-5 code 196 = string; +option legacy-etherboot-image-6 code 197 = string; +option legacy-etherboot-image-7 code 198 = string; +option legacy-etherboot-image-8 code 199 = string; +option legacy-etherboot-image-9 code 200 = string; +option legacy-etherboot-image-10 code 201 = string; +option legacy-etherboot-image-11 code 202 = string; +option legacy-etherboot-image-12 code 203 = string; +option legacy-etherboot-image-13 code 204 = string; +option legacy-etherboot-image-14 code 205 = string; +option legacy-etherboot-image-15 code 206 = string; +option legacy-etherboot-image-16 code 207 = string; + +# Apply Etherboot options only for Etherboot clients +# +if substring ( option vendor-class-identifier, 0, 9 ) = "Etherboot" { + + # We must specify this value for etherboot-magic, or Etherboot will + # ignore all other options. + # + option etherboot.magic E4:45:74:68:00:00; + + # Bootfile name: derive from etherboot.kmod (calculated below) + # Use boot.nbi if no NIC_DEV_ID option present + # (i.e. if etherboot.kmod doesn't get set) + # Also pass filename back in filename field + # + option bootfile-name = pick-first-value ( concat ( "boot-", + config-option etherboot.kmod, + ".nbi" ), + "boot.nbi" ) ; + filename = config-option bootfile-name; + + # "Sensible" default values for some options + + # Mount devfs (will probably be needed for a network-boot) + option etherboot.kernel-cmdline " devfs=mount"; + + # Info message (includes client IP address, MAC address, hardware ID string, + # server IP address and name of boot file) + option etherboot.motd-4 = concat ( "Using Etherboot to boot ", + binary-to-ascii ( 10, 8, ".", leased-address ), + " [", + binary-to-ascii ( 16, 8, ":", suffix ( hardware, 6 ) ), + "] [", + pick-first-value ( option etherboot.nic-dev-id, "unknown card" ), + "]", 0d:0a, " from ", + binary-to-ascii ( 10, 8, ".", option dhcp-server-identifier ), + " with file ", + config-option tftp-server-name, + ":", + config-option bootfile-name, + " [", + pick-first-value ( config-option etherboot.kmod, "unknown module" ), + "]", 0d:0a ); + + # Legacy site-local option support + # If client does not include an etherboot-encapsulated-options field in its DHCPREQUEST, then + # it will not understand etherboot-encapsulated-options in the DHCPACK and so we must send + # back the options as site-local options (i.e. not encapsulated). + # Note: we need do this only for options that existed prior to the switch to encapsulation. + # + if not exists etherboot-encapsulated-options { + option legacy-etherboot-magic = config-option etherboot.magic; + option legacy-etherboot-kernel-cmdline = config-option etherboot.kernel-cmdline; + option legacy-etherboot-menu-opts = config-option etherboot.menu-opts; + option legacy-etherboot-menu-selection = config-option etherboot.menu-selection; + option legacy-etherboot-motd-1 = config-option etherboot.motd-1; + option legacy-etherboot-motd-2 = config-option etherboot.motd-2; + option legacy-etherboot-motd-3 = config-option etherboot.motd-3; + option legacy-etherboot-motd-4 = config-option etherboot.motd-4; + option legacy-etherboot-motd-5 = config-option etherboot.motd-5; + option legacy-etherboot-motd-6 = config-option etherboot.motd-6; + option legacy-etherboot-motd-7 = config-option etherboot.motd-7; + option legacy-etherboot-motd-8 = config-option etherboot.motd-8; + option legacy-etherboot-image-1 = config-option etherboot.image-1; + option legacy-etherboot-image-2 = config-option etherboot.image-2; + option legacy-etherboot-image-3 = config-option etherboot.image-3; + option legacy-etherboot-image-4 = config-option etherboot.image-4; + option legacy-etherboot-image-5 = config-option etherboot.image-5; + option legacy-etherboot-image-6 = config-option etherboot.image-6; + option legacy-etherboot-image-7 = config-option etherboot.image-7; + option legacy-etherboot-image-8 = config-option etherboot.image-8; + option legacy-etherboot-image-9 = config-option etherboot.image-9; + option legacy-etherboot-image-10 = config-option etherboot.image-10; + option legacy-etherboot-image-11 = config-option etherboot.image-11; + option legacy-etherboot-image-12 = config-option etherboot.image-12; + option legacy-etherboot-image-13 = config-option etherboot.image-13; + option legacy-etherboot-image-14 = config-option etherboot.image-14; + option legacy-etherboot-image-15 = config-option etherboot.image-15; + option legacy-etherboot-image-16 = config-option etherboot.image-16; + } +} + +# Some options should be set for both Etherboot and the udhcpc client +# +if ( ( substring ( option vendor-class-identifier, 0, 9 ) = "Etherboot" ) + or ( substring ( option vendor-class-identifier, 0, 5 ) = "udhcp" ) ) { + + # TFTP server defaults to DHCP server and is specified in both + # next-server field and tftp-server-name option field + # + option tftp-server-name = binary-to-ascii ( 10, 8, ".", config-option dhcp-server-identifier ); + server-name = config-option tftp-server-name; + next-server = config-option dhcp-server-identifier; + + # Root path defaults to root of TFTP server + option root-path = concat ( config-option tftp-server-name, ":/" ); + + # A fallback hostname, generated from the IP address + option host-name = concat ( "client_", binary-to-ascii ( 10, 8, "_", leased-address ) ); +} + +# Force some items onto parameter request list for udhcp +# +if substring ( option vendor-class-identifier, 0, 5 ) = "udhcp" { + # Forcibly add root-path to list + option dhcp-parameter-request-list = concat ( option dhcp-parameter-request-list, 11 ); +} + +# Etherboot sends a string to identify the NIC in etherboot.nic-dev-id. +# For PCI NICs, this string is of the form "PCI:vvvv:dddd" where vvvv is the +# vendor identifier and dddd the device identifier, in lower-case ASCII hex. +# For ISA NICs, the format of the string is "ISA:..." where ... is not yet +# decided upon. +# +# We use the identifier to select the NBI image that will be specified via +# the "bootfile-name" option. +# +# PCI NICs - use PCI vendor and device IDs +# Listed in file generated by mknbi-set +# +include "/etc/dhcpd.conf.etherboot-pcimap.include"; + +# ISA NICs +# +if substring ( option vendor-class-identifier, 0, 9 ) = "Etherboot" { + if exists etherboot.nic-dev-id { + + } +} diff --git a/contrib/initrd/include-modules b/contrib/initrd/include-modules new file mode 100755 index 0000000..60e76fc --- /dev/null +++ b/contrib/initrd/include-modules @@ -0,0 +1,63 @@ +#!/usr/bin/perl -w +# +# Retrieve modules required for an initrd image +# $Id$ + +unless ( @ARGV ) { + die "Syntax: $0 [ -d target_directory ] module_1 module_2 module_3\n" +} + +# Parse command line arguments +my @requested_modules = (); +my $target_dir = ""; +my $kernel_ver; +my $quiet; +chomp ( my $current_kernel_ver = `uname -r` ); +while ( $_ = shift ) { + if ( /-d/ ) { $target_dir = shift } + elsif ( /-k/ ) { $kernel_ver = shift } + elsif ( /-q/ ) { $quiet = 1 } + else { push @requested_modules, $_ }; +} + +# Create target directory if required +if ( $target_dir ) { + print STDERR "Target directory is $target_dir\n" unless $quiet; + system ( "mkdir -p $target_dir" ); + chdir $target_dir; +} + +# Use modprobe -nav to retrieve locations of modules and their dependencies +print STDERR "Requested modules ". join (' ', @requested_modules)."\n" unless $quiet; +my @modules_dups; +foreach my $module ( @requested_modules ) { + my @module_list = map { /^\S+\s+(.*)$/ ; $1 } `/sbin/modprobe -nva $module`; + die "Cannot find any modules matching $module\n" unless @module_list; + push @modules_dups, @module_list; +} + +# Remove duplicates from list +my %module_basenames = (); +my @modules = (); +foreach my $module ( @modules_dups ) { + # Ugly hack : assume that dependencies are independent of kernel version + # This seems to be necessary because we can't run modprobe and specify + # an alternate modules.dep file; it refuses to understand lines of the + # form "depfile=XXX" as documented in modules.conf(5) + $module =~ s/$current_kernel_ver/$kernel_ver/ if $kernel_ver; + push @modules, $module unless $module_basenames{$module}; + ( my $basename ) = ( $module =~ /([^\/]+)\.o/ ); + $module_basenames{$module} = $basename; +} + +# Process module list +print "#!/bin/sh\n"; +foreach my $module ( @modules ) { + my $basename = $module_basenames{$module}; + # Report via stdout + print STDERR "Using module $basename from $module\n" unless $quiet; + # Copy uncompressed module to current directory + system ("gunzip -c $module > $basename.o"); + # Print insmod line to stdout + print "insmod $basename\n"; +} diff --git a/contrib/initrd/linux-wlan.cfg b/contrib/initrd/linux-wlan.cfg new file mode 100644 index 0000000..7df4a05 --- /dev/null +++ b/contrib/initrd/linux-wlan.cfg @@ -0,0 +1,7 @@ +# Dummy config file for building only wlanctl +# $Id$ + +PRISM2_PLX=n +PRISM2_PCMCIA=n +PRISM2_PCI=n +PRISM2_USB=n diff --git a/contrib/initrd/linuxrc b/contrib/initrd/linuxrc new file mode 100644 index 0000000..24bdb0d --- /dev/null +++ b/contrib/initrd/linuxrc @@ -0,0 +1,76 @@ +#!/bin/sh +# $Id$ + +PATH=/sbin:/bin + +echo Busybox /linuxrc starting + +echo Mounting /proc filesystem +mount -t proc none /proc + +echo=echo +if grep '\bquiet\b' /proc/cmdline > /dev/null; then + echo=true + quiet=1 +fi + +$echo Creating root device +mknod /dev/root b 1 0 2>/dev/null +chmod 700 /dev/root +echo 0x100 > /proc/sys/kernel/real-root-dev + +$echo Inserting modules +if [ -z "$quiet" ]; then + /bin/insert-modules +else + /bin/insert-modules >/dev/null +fi + +$echo Bringing up loopback interface +ifconfig lo 127.0.0.1 up +route add -net 127.0.0.0 netmask 255.0.0.0 lo + +# Hack required for prism2 cards +# It is not yet possible to use iwconfig to configure these cards, +# so we need wlanctl. +if ifconfig wlan0 down 2> /dev/null; then + $echo Setting up wireless link + wlanctl wlan0 lnxreq_ifstate ifstate=enable + wlanctl wlan0 lnxreq_autojoin ssid= authtype=opensystem +fi + +$echo Obtaining IP address via DHCP +$echo Trying to obtain IP address via wired link [eth0] +if udhcpc -i eth0 -f -n -q -s /bin/udhcpc-post; then + $echo Successfully obtained IP address via wired link [eth0] +else + $echo Failed to obtain IP address via wired link [eth0] + $echo Trying to obtain IP address via wireless link [wlan0] + udhcpc -i wlan0 -f -n -q -s /bin/udhcpc-post +fi + +if [ -d /sysroot/initrd ]; then + $echo Unmounting /proc prior to pivot_root + umount /proc + + $echo Pivoting root to /sysroot + pivot_root /sysroot /sysroot/initrd + cd / + + $echo Remounting devfs at correct place + mount -t devfs none /dev + + $echo Releasing locks on old devfs + exec 0</dev/null + exec 1>/dev/console + exec 2>/dev/console + + $echo Unmounting old devfs + umount /initrd/dev +else + # Failed to mount root: report error and hang + echo FATAL ERROR: Failed to mount root filesystem + echo Press Alt-SysRq-B or hit the reset switch to reboot + while : ; do sleep 6000 ; done +fi + diff --git a/contrib/initrd/mkinitrd-net b/contrib/initrd/mkinitrd-net new file mode 100755 index 0000000..0c95ebd --- /dev/null +++ b/contrib/initrd/mkinitrd-net @@ -0,0 +1,165 @@ +#!/bin/sh +# +# $Id$ +# initrd builder for network booting + +# Utility function to determine whether or not a filesystem is usable for +# loopback mounts. Lifted verbatim from Erik Troan's mkinitrd script. +# +is_good_fs() { + local parttype= tmpname= + local dir=$1 + [[ -d $dir ]] || return 1 + [[ -w $dir ]] || return 1 + [[ $dir == */ ]] && dir=${dir%/} + parttype=$(awk "{if (\$2 == \""$dir"\") print \$3 }" /proc/mounts) + + while tmpname=${dir%/*} && [[ -z $parttype ]];do + [[ -z $tmpname ]] && tmpname=/ + parttype=$(awk "{if (\$2 == \""$tmpname"\") print \$3 }" /proc/mounts) + dir=$tmpname + done + + case $parttype in + nfs|tmpfs) return 1;; + *) return 0; + esac +} + +# Find a suitable temporary directory (i.e. not tmpfs or nfs) +if is_good_fs $TMPDIR; then + tmpdir=$TMPDIR +elif is_good_fs /tmp; then + tmpdir=/tmp +elif is_good_fs /var/tmp; then + tmpdir=/var/tmp +elif is_good_fs /root/tmp; then + tmpdir=/root/tmp +else + echo "Cannot use a tmp directory" >&2 + exit 1 +fi + +# Default settings (some can be overridden by command-line options) +include_modules=include-modules +initrd_skel=/usr/lib/mkinitrd-net/initrd-skel +kernel_ver=`uname -r` +use_sudo=y +keep=n +output_dir=/var/lib/tftpboot +make_link=y +quiet= + +# No need to use sudo if we are root +if [ $UID -eq 0 ]; then + use_sudo=n +fi + +USAGE="Usage: $0 [-k|--kernel <kernel_ver>] [-n|--nolink] [-q|--quiet] [-l|--local] [--nosudo] [--keep] [--help] module_list ..." + +# Parse command-line options +while [ $# -gt 0 ]; do + case "$1" in + -l|--local) + shift + use_local=y ;; + -k|--kernel) + shift + kernel_ver=$1 + shift ;; + --nosudo) shift ; use_sudo=n ;; + --keep) shift ; keep=y ;; + --n|--nolink) + shift ; make_link=n ;; + -q|--quiet) shift ; quiet=-q ;; + --help) shift ; do_help=y ;; + --) shift ; break ;; + -*) echo "${0}: ${1}: invalid option" >&2 + echo $USAGE >& 2 + exit 2 ;; + *) break ;; + esac +done + +# Build list of requested modules +modules="$*" +requested_modules="$modules" +modules="$modules nfs" # Always require nfs for nfs mount +modules="$modules af_packet" # Always require af_packet for udhcpc + +# --help => Print help message +if [ "$do_help" == "y" ]; then + echo $USAGE + echo " -k, --kernel Specify kernel version" + echo " -n, --nolink Do not create a matching symbolic link" + echo " -l, --local Run locally from CVS (for developers only)" + echo " --nosudo Do not use sudo (i.e. must run as root instead)" + echo " --keep Keep temporary files instead of deleting them" + exit 0; +fi + +# --local => we are running directly from CVS, rather than +# from an installed copy, so use local files and directories +if [ "$use_local" == "y" ]; then + include_modules=./include-modules + initrd_skel=initrd-skel + output_dir=tftpboot +fi + +# If use_sudo is set, check that sudo exists +sudo=/usr/bin/sudo +if [ "$use_sudo" == "y" ]; then + if [ ! -x $sudo ]; then + use_sudo=n + echo "WARNING: --nosudo not specified but $sudo not found" + fi +fi +if [ "$use_sudo" == "n" ]; then + sudo= +fi + +# Create temporary working files +initrd=`mktemp -d ${tmpdir}/initrd.XXXXXX` +initrdimg=`mktemp ${tmpdir}/initrd.img.XXXXXX` +initrdmnt=`mktemp -d ${tmpdir}/initrd.mnt.XXXXXX` + +# Copy skeleton into temporary area +cp -a $initrd_skel/* $initrd/ +mkdir -p $initrd/lib/modules/$kernel_ver +$include_modules $quiet -k $kernel_ver -d $initrd/lib/modules/$kernel_ver $modules > $initrd/bin/insert-modules || exit 1 +chmod 755 $initrd/bin/insert-modules + +# Create empty ext2fs image file +dd if=/dev/zero bs=1k of=$initrdimg count=$((`du -sk $initrd | cut -f1` * 7 / 6)) 2> /dev/null +/sbin/mke2fs -q -F $initrdimg 2> /dev/null + +# Mount image file, copy files on, create /dev entries, display free space, umount +$sudo mount -o loop $initrdimg $initrdmnt +cp -a $initrd/* $initrdmnt/ +$sudo mknod $initrdmnt/dev/console c 5 1 +$sudo mknod $initrdmnt/dev/null c 1 3 +$sudo mknod $initrdmnt/dev/ram b 1 1 +$sudo mknod $initrdmnt/dev/systty c 4 0 +for i in 1 2 3 4; do $sudo mknod $initrdmnt/dev/tty$i c 4 $i; done +if [ "$quiet" == "n" ]; then + df -h $initrdmnt +fi +$sudo umount $initrdmnt + +# Create output file +initrd_suffix=`echo $requested_modules | tr " " .` +gzip -9 -n -c $initrdimg > $output_dir/initrd-$initrd_suffix.$kernel_ver.img + +# Create symlink +if [ "$make_link" == "y" ]; then + link=$output_dir/initrd-$initrd_suffix.img + [ -L $link ] && rm -f $link + ln -s initrd-$initrd_suffix.$kernel_ver.img $link +fi + +# Remove temporary files +if [ "$keep" == "n" ]; then + rm -rf $initrd + rm -f $initrdimg + rmdir $initrdmnt +fi diff --git a/contrib/initrd/mkinitrd-net.spec b/contrib/initrd/mkinitrd-net.spec new file mode 100644 index 0000000..94f5d9d --- /dev/null +++ b/contrib/initrd/mkinitrd-net.spec @@ -0,0 +1,112 @@ +%define name mkinitrd-net +%define version 1.10 +%define release 1fs + +Summary: Network-booting initrd builder +Name: %{name} +Version: %{version} +Release: %{release} +Source0: %{name}-%{version}.tar.bz2 +Source1: http://belnet.dl.sourceforge.net/sourceforge/etherboot/mknbi-1.2.tar.bz2 +Source2: http://www.busybox.net/downloads/busybox-0.60.3.tar.bz2 +Source3: http://www.uclibc.org/downloads/uClibc-0.9.11.tar.bz2 +Source4: ftp://ftp.linux-wlan.org/pub/linux-wlan-ng/linux-wlan-ng-0.1.13.tar.bz2 +Source5: http://udhcp.busybox.net/source/udhcp-0.9.7.tar.bz2 +Copyright: GPL/LGPL/MPL +Group: System/Kernel and hardware +BuildRoot: %{_tmppath}/%{name}-buildroot +Prefix: %{_prefix} +Requires: tftp-server + +%description +mkinitrd-net allows you to build initial ramdisk images (initrds) suitable +for use with Etherboot and other network-booting software. This package +contains two main utilities: mkinitrd-net (to build an initrd containing a +specified set of network-card modules) and mknbi (to generate +Etherboot-usable NBI images from a given kernel and initrd). It also +contains a helper script mknbi-set which will maintain sets of initrds to +match all your currently-installed kernels. + +mkinitrd-net uses code from the uClibc, busybox, udhcp and Etherboot +projects. + +%prep +%setup -n initrd -a1 -a2 -a3 -a4 -a5 + +%build +%make LIBDIR=%{_libdir}/mknbi + +%install +rm -rf $RPM_BUILD_ROOT +%makeinstall tftpbootdir=$RPM_BUILD_ROOT%{_localstatedir}/tftpboot +touch $RPM_BUILD_ROOT%{_sysconfdir}/dhcpd.conf.etherboot-pcimap.include +ln -s %{_localstatedir}/tftpboot $RPM_BUILD_ROOT/tftpboot + +%clean +rm -rf $RPM_BUILD_ROOT + +%post +%{_bindir}/mknbi-set + +%triggerin -- kernel kernel-smp kernel-secure kernel-enterprise +%{_bindir}/mknbi-set + +%files +%defattr(-,root,root) +%config(noreplace) %{_sysconfdir}/mknbi-set.conf +%config(noreplace) %{_sysconfdir}/dhcpd.conf.etherboot.include +%ghost %{_sysconfdir}/dhcpd.conf.etherboot-pcimap.include +%{_bindir}/mknbi-* +%{_bindir}/mkelf-* +%{_bindir}/dis* +%{_bindir}/mkinitrd-net +%{_bindir}/include-modules +%{_libdir}/mknbi +%{_libdir}/mkinitrd-net +%{_mandir}/man*/* +/tftpboot +%{_localstatedir}/tftpboot +%doc README +%doc AUTHORS.busybox LICENSE.busybox +%doc AUTHORS.udhcpc COPYING.udhcpc +%doc COPYING.wlanctl LICENSE.wlanctl THANKS.wlanctl +%doc COPYING.uClibc +%docdir %{_docdir}/mknbi* +%{_docdir}/mknbi* + +%changelog +* Fri Jul 26 2002 Michael Brown <mbrown@fensystems.co.uk> 1.10-1fs +- Support for new binary etherboot.nic-dev-id structure +- Added --kernel option patch from Stew Benedict at MandrakeSoft +- Only try to use sudo if we are not already root + +* Wed Jun 05 2002 Michael Brown <mbrown@fensystems.co.uk> 1.9-1fs +- Modifications to allow DHCP, TFTP and NFS servers to be separate machines. + +* Thu May 30 2002 Michael Brown <mbrown@fensystems.co.uk> 1.8-1fs +- /tftpboot symlinked to /var/lib/tftpboot +- Has ability to be quiet if "quiet" specified on kernel cmdline + +* Sun May 26 2002 Michael Brown <mbrown@fensystems.co.uk> 1.7-1fs +- PCI-ID auto-mapping via dhcpd.conf.etherboot-pcimap.include + +* Fri May 24 2002 Michael Brown <mbrown@fensystems.co.uk> 1.6-1fs +- Bugfixes, migrated /tftpboot to /var/lib/tftpboot + +* Thu May 23 2002 Michael Brown <mbrown@fensystems.co.uk> 1.5-1fs +- Now includes dhcpd.conf.etherboot.include +- Automatically scans for all network modules in the pcimap file + +* Wed May 08 2002 Michael Brown <mbrown@fensystems.co.uk> 1.4-1fs +- Bugfixes: tmpdir selection, linuxrc typos, ifconfig peculiarities + +* Sat May 04 2002 Michael Brown <mbrown@fensystems.co.uk> 1.3-1fs +- During %make, LIBDIR must be set for mknbi +- Added %post scriptlet since %trigger seems not to be being triggered... + +* Sat May 04 2002 Michael Brown <mbrown@fensystems.co.uk> 1.2-1fs +- Added extra sources instead of requiring "make" to download them + +* Sat May 04 2002 Michael Brown <mbrown@fensystems.co.uk> 1.1-1fs +- First attempt at an RPM package + diff --git a/contrib/initrd/mknbi-set b/contrib/initrd/mknbi-set new file mode 100755 index 0000000..e61acac --- /dev/null +++ b/contrib/initrd/mknbi-set @@ -0,0 +1,200 @@ +#!/usr/bin/perl -w +# +# $Id$ +# Maintains set of NBIs based on currently-installed kernels +# Network card module sets are taken from /etc/mknbi-set.conf + +use strict; +use vars qw($verbosity); + +use constant EB_PCI_DEVICE => 1; + +# Utility function: calculate output id given a kernel file name and +# space-separated list of modules +sub calc_output_id ($$) { + my $kernel = shift; + my $moduleset = shift; + my $kernel_ver = ""; + ( $kernel_ver ) = ( $kernel =~ /vmlinuz-(.*)$/ ); + ( my $output_id = "$moduleset".( $kernel_ver ? ".$kernel_ver" : "" ) ) =~ tr/,/./; + return ( $kernel_ver, $output_id ); +} + +# Utility function: read modules.pcimap-style file +# Add modules to modulesets hash, write out dhcpd.conf fragment +sub read_config_file ($$$$) { + my $configfile = shift; + my $modulesets = shift; + my $dhcpfh = shift; + my $alwaysuse = shift; + + print "Scanning through $configfile for network modules...\n" if $verbosity >= 1; + open CF, $configfile or die "Could not open $configfile: $!\n"; + chomp ( my $tempmodule = `mktemp /tmp/mknbi-set.XXXXXX` ); + chomp ( my $cwd = `pwd` ); chdir '/'; # Modprobe searches the current directory... + print $dhcpfh " \# Generated from $configfile\n"; + while (<CF>) { + chomp; + next if /^[\#;]/ or /^\s*$/; + ( my $module, undef, my $vendor, my $device ) = /^(\S+)(\s+(\S+)\s+(\S+))?/ ; + $modulesets->{$module} = 1 if $alwaysuse; + if ( ! exists $modulesets->{$module} ) { + # Check to see if module is a network module + # Only do this the first time we encounter a module + my @modulepaths = `/sbin/modprobe -l $module.o*` ; + chomp ( my $modulepath = $modulepaths[0] ); + if ( $modulepath ) { + if ( $modulepath =~ /.o.gz$/ ) { + system ( "zcat $modulepath > $tempmodule" ); + } else { + system ( "cp $modulepath $tempmodule" ); + } + $modulesets->{$module} = 0; + foreach ( `nm $tempmodule` ) { + chomp; + $modulesets->{$module} = 1 if /(ether|wlan)/ ; + } + unlink $tempmodule; + } else { + print STDERR "Cannot locate module $module specified in $configfile\n"; + } + } + if ( $modulesets->{$module} ) { + if ( $vendor ) { + print "$module ($vendor,$device) listed in $configfile\n" if $verbosity >= 2; + printf $dhcpfh ( " if option etherboot.nic-dev-id = %02x:%02x:%02x:%02x:%02x { option etherboot.kmod \"%s\"; }\n", + EB_PCI_DEVICE, + ( hex($vendor) >> 8 ) & 0xff, hex($vendor) & 0xff, + ( hex($device) >> 8 ) & 0xff, hex($device) & 0xff, + $module ); + } else { + print "$module (without PCI IDs) listed in $configfile\n" if $verbosity >= 2; + } + } + } + close CF; + print $dhcpfh "\n"; + chdir $cwd; +} + +my $conffile = '/etc/mknbi-set.conf'; +my $mkinitrd_net = 'mkinitrd-net'; +my $mknbi = 'mknbi-linux'; +my $output_dir = '/var/lib/tftpboot'; +my $dhcpfile = '/etc/dhcpd.conf.etherboot-pcimap.include'; +my $use_local; +our $verbosity = 1; +my $modulesets = {}; +my $kernel = ''; +my @kernels = (); + +my $usage="Usage: $0 [-l|--local] [-q] [-v] [-r|--refresh module[,module...]] [--help]"; + +# Parse command-line options +while ( $_ = shift ) { + if ( /-l|--local/ ) { + $conffile = 'mknbi-set.conf'; + $mkinitrd_net = './mkinitrd-net'; + $mknbi = './mknbi-linux --format=nbi --target=linux'; + $output_dir = 'tftpboot'; + $dhcpfile = 'tftpboot/dhcpd.conf.etherboot-pcimap.include'; + $use_local = 1; + } elsif ( /-r|--refresh/ ) { + my $moduleset = shift; + $modulesets->{$moduleset} = 1; + } elsif ( /-k|--kernel/ ) { + $kernel = shift; + } elsif ( /-v|--verbose/ ) { + $verbosity++; + } elsif ( /-q|--quiet/ ) { + $verbosity--; + } elsif ( /--help/ ) { + die "$usage\n". + " -k, --kernel Build NBIs for a particular kernel\n". + " -l, --local Run locally from CVS (for developers only)\n". + " -r, --refresh Refresh NBI for a particular module\n". + " -v, --verbose Be more verbose\n". + " -q, --quiet Be less verbose\n"; + } else { + die "$usage\n"; + } +} + +# Get set of current kernels +if ($kernel) { + @kernels = ( $kernel ); +} else { + @kernels = glob('/boot/vmlinuz*'); +} +die "Could not find any kernels in /boot\n" unless @kernels; + +# If modules have been specified via --refresh, do not scan for modules or rewrite the +# dhcpd.conf fragment file +unless ( %$modulesets ) { + # Write dhcpd.conf fragment file + open my $dhcpfh, ">$dhcpfile" or die "Could not open $dhcpfile for writing: $!\n"; + print $dhcpfh "# Etherboot PCI ID -> Linux kernel module mapping file\n"; + print $dhcpfh "# Generated by mknbi-set on ".(scalar localtime)."\n"; + print $dhcpfh "#\n"; + print $dhcpfh "if substring ( option vendor-class-identifier, 0, 9 ) = \"Etherboot\" {\n"; + print $dhcpfh " if exists etherboot.nic-dev-id {\n"; + print $dhcpfh " \# Legacy nic-dev-id mechanism: there are some DLink DFE538 cards in circulation that\n"; + print $dhcpfh " \# predated the change to the new nic-dev-id binary structure\n"; + print $dhcpfh " if option etherboot.nic-dev-id = \"PCI:1186:1300\" { option etherboot.kmod \"8139too\"; }\n"; + print $dhcpfh "\n"; + + # Get set of network modules to build NBIs for + # Read explicitly-specified module sets from $conffile + read_config_file($conffile, $modulesets, $dhcpfh, 1); + # Obtain list of all network modules from pcimap file + my $pcimap; + foreach ( `/sbin/modprobe -c` ) { + $pcimap = $1 if /^pcimap.*?=(.*)$/; + } + if ( $pcimap ) { + read_config_file($pcimap, $modulesets, $dhcpfh, 0); + } else { + print STDERR "Could not identify pcimap file\n"; + } + # Finish off dhcpd.conf fragment file + print $dhcpfh " }\n}\n"; + close $dhcpfh; +} + +# Build initrd and nbi for each kernel-moduleset combination +foreach my $moduleset ( sort keys %$modulesets ) { + next unless $modulesets->{$moduleset}; # Ignore if value is 0 + print "Building NBIs for module set $moduleset\n" if $verbosity >= 1; + foreach my $kernel ( @kernels ) { + ( my $kernel_ver, my $output_id ) = calc_output_id ( $kernel, $moduleset ); + if ( -l $kernel ) { + # Symbolic link; create matching symlink + my $real_kernel = readlink ( $kernel ); + ( my $real_kernel_ver, my $real_output_id ) = calc_output_id ( $real_kernel, $moduleset ); + print "Symlinking $output_id to $real_output_id\n" if $verbosity >= 2; + my $initrd_file = "$output_dir/initrd-$output_id.img"; + unlink ( $initrd_file ) if -l $initrd_file; + system ( "ln -s initrd-$real_output_id.img $initrd_file" ) == 0 or print STDERR "Could not symlink $initrd_file to initrd-$real_output_id.img: $!\n"; + my $nbi_file = "$output_dir/boot-$output_id.nbi"; + unlink ( $nbi_file ) if -l $nbi_file; + system ( "ln -s boot-$real_output_id.nbi $nbi_file" ) == 0 or print STDERR "Could not symlink $nbi_file to boot-$real_output_id.nbi: $!\n"; + } else { + # Real file: create initrd and nbi + print "Creating initrd and nbi for $output_id\n" if $verbosity >= 2; + ( my $moduleset_spaces = $moduleset ) =~ tr/,/ /; + my $initrd_cmd = "$mkinitrd_net --nolink ". + ( $use_local ? "--local " : "" ). + ( $kernel_ver ? "--kernel $kernel_ver " : "" ). + ( $verbosity >= 2 ? "" : "-q " ). + $moduleset_spaces; + print "$initrd_cmd\n" if $verbosity >= 3; + if ( system ( $initrd_cmd ) == 0 ) { + my $mknbi_cmd = "$mknbi $kernel $output_dir/initrd-$output_id.img > $output_dir/boot-$output_id.nbi"; + print "$mknbi_cmd\n" if $verbosity >= 3; + system ( $mknbi_cmd ) == 0 or print STDERR "mknbi failed: $!\n"; + } else { + print STDERR "$initrd_cmd failed: $!\n"; + } + } + } +} diff --git a/contrib/initrd/mknbi-set.conf b/contrib/initrd/mknbi-set.conf new file mode 100644 index 0000000..f24846c --- /dev/null +++ b/contrib/initrd/mknbi-set.conf @@ -0,0 +1,27 @@ +# This file specifies the network cards for which NBI images should be built +# Each line contains a list of kernel modules to be used, separated by commas +# You can optionally specify PCI vendor and device IDs that should be automatically +# mapped to this module. +# +# The format is similar to modutils' modules.pcimap file. +# +# Examples: +# RTL8139-based ethernet card +; 8139too +# RTL8139-based ethernet card with PCI IDs vendor=0x1186, device=0x1300 +; 8139too 0x1186 0x1300 +# RTL8139 and Prism2_pci in same image +; 8139too,prism2_pci + +# Some modules do not include the MODULE_DEVICE_TABLE macro, and so end up not +# being listed in the pcimap file. These modules are included here to force +# the creation of corresponding initrds. +prism2_pci 0x1260 0x3873 +prism2_plx 0x1638 0x1100 +prism2_plx 0x16ab 0x1101 +prism2_plx 0x16ab 0x1102 +prism2_plx 0x1385 0x4100 +prism2_plx 0x15e8 0x0130 +prism2_plx 0x16ec 0x3685 +prism2_plx 0x16ab 0x1102 +prism2_plx 0x15e8 0x0131 diff --git a/contrib/initrd/script.c.patch b/contrib/initrd/script.c.patch new file mode 100644 index 0000000..127b881 --- /dev/null +++ b/contrib/initrd/script.c.patch @@ -0,0 +1,11 @@ +--- script.c.orig Tue Apr 2 23:49:33 2002 ++++ script.c Wed Jun 5 14:17:22 2002 +@@ -179,7 +179,7 @@ + } + if (packet->siaddr) { + envp[j] = malloc(sizeof("siaddr=255.255.255.255")); +- sprintip(envp[j++], "siaddr=", (unsigned char *) &packet->yiaddr); ++ sprintip(envp[j++], "siaddr=", (unsigned char *) &packet->siaddr); + } + if (!(over & FILE_FIELD) && packet->file[0]) { + /* watch out for invalid packets */ diff --git a/contrib/initrd/udhcpc-post b/contrib/initrd/udhcpc-post new file mode 100644 index 0000000..395d6c5 --- /dev/null +++ b/contrib/initrd/udhcpc-post @@ -0,0 +1,25 @@ +#!/bin/sh +# $Id$ + +if [ "$1" = "deconfig" ]; then + ifconfig $interface 0.0.0.0 up +else if [ "$1" = "bound" ] ; then + echo UDHCPC: I am $ip [$hostname], booting from $serverid + [ -n "$hostname" ] && echo $hostname > /proc/sys/kernel/hostname + [ -n "$broadcast" ] && BROADCAST="broadcast $broadcast" + [ -n "$subnet" ] && NETMASK="netmask $subnet" + ifconfig $interface $ip $BROADCAST $NETMASK + route add default gw $router dev $interface + echo -n > /etc/resolv.conf + for i in $dns; do + echo nameserver $i >> /etc/resolv.conf + done + [ -n "$siaddr" ] || siaddr=$serverid + [ -n "$rootpath" ] || rootpath=$siaddr:/ + echo Mounting root filesystem $rootpath at /sysroot + echo If this appears to hang, check that the server of $rootpath is able to + echo reverse-map my IP address $ip to obtain my hostname $hostname + mount -t nfs -o nolock,rsize=8192,wsize=8192 $rootpath /sysroot + fi +fi + diff --git a/contrib/linux-2.0-transname.lsm b/contrib/linux-2.0-transname.lsm new file mode 100644 index 0000000..4a59096 --- /dev/null +++ b/contrib/linux-2.0-transname.lsm @@ -0,0 +1,93 @@ +Xref: news.nsw.CSIRO.AU comp.os.linux.announce:2827 +Path: news.nsw.CSIRO.AU!metro!metro!munnari.OZ.AU!news.ecn.uoknor.edu!news.wildstar.net!news.ececs.uc.edu!newsrelay.netins.net!newsfeed.dacom.co.kr!arclight.uoregon.edu!feed1.news.erols.com!howland.erols.net!newsfeed.internetmci.com!in3.uu.net!liw.clinet.fi!usenet +From: schoebel@informatik.uni-stuttgart.de (Thomas Schoebel-Theuer) +Newsgroups: comp.os.linux.announce +Subject: linux-2.0.21-transname - Patch for easier pool administration +Followup-To: comp.os.linux.misc +Date: 30 Oct 1996 10:53:38 GMT +Organization: Informatik, Uni Stuttgart, Germany +Lines: 76 +Approved: linux-announce@news.ornl.gov (Lars Wirzenius) +Message-ID: <pgpmoose.199610301253.4416@liw> +NNTP-Posting-Host: liw +X-Auth: PGPMoose V1.1 PGP comp.os.linux.announce + iQBVAwUBMnczrjiesvPHtqnBAQEO6gH/WRtFpTPyVtwi0cFVPZ1Xhn8cvfb6i3mk + LQY2kgpAPquP2TeXYWb5Ta3HxqK15pR1AgaEy5BmPS6+66ixZFvKRQ== + =hhea + +-----BEGIN PGP SIGNED MESSAGE----- + +linux-2.0.21-transname.patch enables diskless clients, X-terminals etc to +mount the *root filesystem* of the server. This makes administration of +large pools *a lot* easier. + +Currently different diskless clients must have their root "/" on different +directories on the server, beause each client has _some_ different +configuration files. However, most administration files (typically about 99%) +have the same contents on the clients and on the server, but have to be +(and maintained separately) just because of the 1% differences. + +This duplication causes very large efforts in practice, since at least +the /etc directory has to be duplicated for every client. Even in /etc +many files are identical, for example sendmail.cf, initrc scripts and +others. Maintaining a large pool means to ensure coherence amoung the +duplicates. Classical methods like symlinks are unconvenient +for this task because they have to be valid in the view of mounted +filesystems at the client, not at the server. + +linux-2.0-transname.patch overcomes this problem by allowing filenames +to be context-dependend. For example, if you have a file "/etc/config" +that should differ on the hosts "myserver" and "myclient", you just +create two different files named "/etc/config#host=myserver#" and +"/etc/config#host=myclient#". On host "myserver", the file +"/etc/config#host=myserver#" will appear as if it were hardlinked to +file "/etc/config" (without the #...=...# suffix). On host "myclient", +the corresponding other file will appear as "/etc/config". So you +can access the right file contents under the same name, depending +on which host you are. + +As a result, you may use different contexts for e.g. /etc/fstab, but +have one shared /etc/passwd for all pool machines. So you don't need +yp or NYS any more. + +The kernel patch was developped for and is used at our Linux pool at the +University of Stuttgart with good results. Maintainance of the pool is +at a minimum, and adding new clients is a child's play. No worry with +keeping up mail configurations, newly installed tools, changed /etc/services, +/etc/shells, /etc/resolv.conf and many, many others. In contrast to a +sophisticated symlink solution, adding a new file to the /etc directory +is seen immediately by all clients. I never had less trouble with +administration before. + +I just uploaded the patch to + ftp://ftp.lmh.ox.ac.uk + where it should appear in /pub/linux-kernel-patch-archive/ +and also to + ftp://sunsite.unc.edu/pub/Linux/Incoming/ + where it should be moved to /pub/Linux/kernel/patches/misc/ soon. + +More details can be found in the README there, and also in the +configure-help. + +Enjoy, + +- -- Thomas + + +-----BEGIN PGP SIGNATURE----- +Version: 2.6.3i +Charset: noconv + +iQCVAwUBMnczhYQRll5MupLRAQHzuwP9HGYa4I3bZpt22Y3oQIwEKZGfvnaS5AaD +fVG8wOQ/T7Nrant9JtTktsTVlxGVlYVnziRY4c0ew2qExapK9FqY/ItN0NJXy5aT +a4eSkn86rp6Un7m90RK1xVY5AyVAq49Rdw2StGxr7uj+davnmg3Np+U0MiAILq91 +52jKGaR3fvc= +=LSD6 +-----END PGP SIGNATURE----- + +-- +This article has been digitally signed by the moderator, using PGP. +http://www.iki.fi/liw/lars-public-key.asc has PGP key for validating signature. +Send submissions for comp.os.linux.announce to: linux-announce@news.ornl.gov +PLEASE remember a short description of the software and the LOCATION. +This group is archived at http://www.iki.fi/liw/linux/cola.html diff --git a/contrib/linux-3c503-patch/3c503.patch b/contrib/linux-3c503-patch/3c503.patch new file mode 100644 index 0000000..b27ff1f --- /dev/null +++ b/contrib/linux-3c503-patch/3c503.patch @@ -0,0 +1,24 @@ +diff -Naur linux.orig/drivers/net/3c503.c linux/drivers/net/3c503.c +--- linux.orig/drivers/net/3c503.c Thu Feb 19 23:14:04 1998 ++++ linux/drivers/net/3c503.c Thu Feb 19 23:16:24 1998 +@@ -179,7 +179,8 @@ + for both the old and new 3Com prefix */ + outb(ECNTRL_SAPROM|ECNTRL_THIN, ioaddr + 0x406); + vendor_id = inb(ioaddr)*0x10000 + inb(ioaddr + 1)*0x100 + inb(ioaddr + 2); +- if ((vendor_id != OLD_3COM_ID) && (vendor_id != NEW_3COM_ID)) { ++ if ((vendor_id != OLD_3COM_ID) && (vendor_id != NEW_3COM_ID) && ++ (vendor_id != BULL_3COM_ID)) { + /* Restore the register we frobbed. */ + outb(saved_406, ioaddr + 0x406); + return ENODEV; +diff -Naur linux.orig/drivers/net/3c503.h linux/drivers/net/3c503.h +--- linux.orig/drivers/net/3c503.h Thu Feb 19 23:14:05 1998 ++++ linux/drivers/net/3c503.h Mon Feb 16 11:41:56 1998 +@@ -11,6 +11,7 @@ + + #define OLD_3COM_ID 0x02608c + #define NEW_3COM_ID 0x0020af ++#define BULL_3COM_ID 0x000062 + + /* Shared memory management parameters. NB: The 8 bit cards have only + one bank (MB1) which serves both Tx and Rx packet space. The 16bit diff --git a/contrib/linux-3c503-patch/README b/contrib/linux-3c503-patch/README new file mode 100644 index 0000000..109094f --- /dev/null +++ b/contrib/linux-3c503-patch/README @@ -0,0 +1,7 @@ +As part of determining whether a 3c503 is present, the Linux driver +examines the first 3 bytes of the ethernet address (the vendor ID) +to see if it corresponds to a known 3Com vendor ID. + +The Bull discless 386 workstation I have (don't laugh) has an +unknown vendor ID 0x000062. This trivial patch adds it to those +known to the driver. diff --git a/contrib/mini-slamd/COPYING b/contrib/mini-slamd/COPYING new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/contrib/mini-slamd/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + 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; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/mini-slamd/Makefile b/contrib/mini-slamd/Makefile new file mode 100644 index 0000000..05f1a36 --- /dev/null +++ b/contrib/mini-slamd/Makefile @@ -0,0 +1,8 @@ +CC=gcc +CFLAGS=-Wall -O2 + +mini-slamd: mini-slamd.c + $(CC) $(CFLAGS) -o $@ $< + +clean: + rm -f mini-slamd
\ No newline at end of file diff --git a/contrib/mini-slamd/mini-slamd.c b/contrib/mini-slamd/mini-slamd.c new file mode 100644 index 0000000..7c33e22 --- /dev/null +++ b/contrib/mini-slamd/mini-slamd.c @@ -0,0 +1,521 @@ +/* + * mini-slamd + * (c) 2002 Eric Biederman + */ + +#include <string.h> +#include <errno.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/poll.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <netinet/ip.h> +#include <netinet/in.h> +#include <fcntl.h> +#include <unistd.h> +#include <arpa/inet.h> + +/* + * To specify the default interface for multicast packets use: + * route add -net 224.0.0.0 netmask 240.0.0.0 dev eth1 + * This server is stupid and does not override the default. + */ + +/* Sever states. + * + * Waiting for clients. + * Sending data to clients. + * Pinging clients for data. + * + */ +#define SLAM_PORT 10000 +#define SLAM_MULTICAST_IP ((239<<24)|(255<<16)|(1<<8)|(1<<0)) +#define SLAM_MULTICAST_PORT 10000 +#define SLAM_MULTICAST_TTL 1 +#define SLAM_MULTICAST_LOOPBACK 1 +#define SLAM_MAX_CLIENTS 10 + +#define SLAM_PING_TIMEOUT 100 /* ms */ + +/*** Packets Formats *** + * Data Packet: + * transaction + * total bytes + * block size + * packet # + * data + * + * Status Request Packet + * transaction + * total bytes + * block packets + * + * Status Packet + * received packets + * requested packets + * received packets + * requested packets + * ... + * received packets + * requested packtes + * 0 + */ + +#define MAX_HDR (7 + 7 + 7) /* transaction, total size, block size */ +#define MIN_HDR (1 + 1 + 1) /* transaction, total size, block size */ + +#define MAX_DATA_HDR (MAX_HDR + 7) /* header, packet # */ +#define MIN_DATA_HDR (MAX_HDR + 1) /* header, packet # */ + +/* ETH_MAX_MTU 1500 - sizeof(iphdr) 20 - sizeof(udphdr) 8 = 1472 */ +#define SLAM_MAX_NACK (1500 - (20 + 8)) +/* ETH_MAX_MTU 1500 - sizeof(iphdr) 20 - sizeof(udphdr) 8 - MAX_HDR = 1451 */ +#define SLAM_BLOCK_SIZE (1500 - (20 + 8 + MAX_HDR)) + + +/* Define how many debug messages you want + * 1 - sparse but useful + * 2 - everything + */ +#ifndef DEBUG +#define DEBUG 0 +#endif + +static int slam_encode( + unsigned char **ptr, unsigned char *end, unsigned long value) +{ + unsigned char *data = *ptr; + int bytes; + bytes = sizeof(value); + while ((bytes > 0) && ((0xff & (value >> ((bytes -1)<<3))) == 0)) { + bytes--; + } + if (bytes <= 0) { + bytes = 1; + } + if (data + bytes >= end) { + return -1; + } + if ((0xe0 & (value >> ((bytes -1)<<3))) == 0) { + /* packed together */ + *data = (bytes << 5) | (value >> ((bytes -1)<<3)); + } else { + bytes++; + *data = (bytes << 5); + } + bytes--; + data++; + while(bytes) { + *(data++) = 0xff & (value >> ((bytes -1)<<3)); + bytes--; + } + *ptr = data; + return 0; +} + +static unsigned long slam_decode(unsigned char **ptr, unsigned char *end, int *err) +{ + unsigned long value; + unsigned bytes; + if (*ptr >= end) { + *err = -1; + } + bytes = ((**ptr) >> 5) & 7; + if ((bytes == 0) || (bytes > sizeof(unsigned long))) { + *err = -1; + return 0; + } + if ((*ptr) + bytes >= end) { + *err = -1; + } + value = (**ptr) & 0x1f; + bytes--; + (*ptr)++; + while(bytes) { + value <<= 8; + value |= **ptr; + (*ptr)++; + bytes--; + } + return value; +} + + +static struct sockaddr_in client[SLAM_MAX_CLIENTS]; +static int clients; + + +void del_client(struct sockaddr_in *old) +{ + int i; + for(i = 0; i < clients; i++) { + if ((client[i].sin_family == old->sin_family) && + (client[i].sin_addr.s_addr == old->sin_addr.s_addr) && + (client[i].sin_port == old->sin_port)) { + memmove(&client[i], &client[i+1], + (clients - (i+1))*sizeof(client[0])); + clients--; + } + } +} + +void add_client(struct sockaddr_in *new) +{ + del_client(new); + if (clients >= SLAM_MAX_CLIENTS) + return; + memcpy(&client[clients], new, sizeof(*new)); + clients++; +} + +void push_client(struct sockaddr_in *new) +{ + del_client(new); + if (clients >= SLAM_MAX_CLIENTS) { + clients--; + } + memmove(&client[1], &client[0], clients*sizeof(*new)); + memcpy(&client[0], new, sizeof(*new)); + clients++; +} + + +void next_client(struct sockaddr_in *next) +{ + /* Find the next client we want to ping next */ + if (!clients) { + next->sin_family = AF_UNSPEC; + return; + } + /* Return the first client */ + memcpy(next, &client[0], sizeof(*next)); +} + +int main(int argc, char **argv) +{ + char *filename; + uint8_t nack_packet[SLAM_MAX_NACK]; + int nack_len; + uint8_t request_packet[MAX_HDR]; + int request_len; + uint8_t data_packet[MAX_DATA_HDR + SLAM_BLOCK_SIZE]; + int data_len; + uint8_t *ptr, *end; + struct sockaddr_in master_client; + struct sockaddr_in sa_src; + struct sockaddr_in sa_mcast; + uint8_t mcast_ttl; + uint8_t mcast_loop; + int sockfd, filefd; + int result; + struct pollfd fds[1]; + int state; +#define STATE_PINGING 1 +#define STATE_WAITING 2 +#define STATE_RECEIVING 3 +#define STATE_TRANSMITTING 4 + off_t size; + struct stat st; + uint64_t transaction; + unsigned long packet; + unsigned long packet_count; + unsigned slam_port, slam_multicast_port; + struct in_addr slam_multicast_ip; + + slam_port = SLAM_PORT; + slam_multicast_port = SLAM_MULTICAST_PORT; + slam_multicast_ip.s_addr = htonl(SLAM_MULTICAST_IP); + + if (argc != 2) { + fprintf(stderr, "Bad argument count\n"); + fprintf(stderr, "Usage: mini-slamd filename\n"); + exit(EXIT_FAILURE); + } + filename = argv[1]; + filefd = -1; + size = 0; + transaction = 0; + + /* Setup the udp socket */ + sockfd = socket(PF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) { + fprintf(stderr, "Cannot create socket\n"); + exit(EXIT_FAILURE); + } + memset(&sa_src, 0, sizeof(sa_src)); + sa_src.sin_family = AF_INET; + sa_src.sin_port = htons(slam_port); + sa_src.sin_addr.s_addr = INADDR_ANY; + + result = bind(sockfd, &sa_src, sizeof(sa_src)); + if (result < 0) { + fprintf(stderr, "Cannot bind socket to port %d\n", + ntohs(sa_src.sin_port)); + exit(EXIT_FAILURE); + } + + /* Setup the multicast transmission address */ + memset(&sa_mcast, 0, sizeof(sa_mcast)); + sa_mcast.sin_family = AF_INET; + sa_mcast.sin_port = htons(slam_multicast_port); + sa_mcast.sin_addr.s_addr = slam_multicast_ip.s_addr; + if (!IN_MULTICAST(ntohl(sa_mcast.sin_addr.s_addr))) { + fprintf(stderr, "Not a multicast ip\n"); + exit(EXIT_FAILURE); + } + + /* Set the multicast ttl */ + mcast_ttl = SLAM_MULTICAST_TTL; + setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, + &mcast_ttl, sizeof(mcast_ttl)); + + /* Set the multicast loopback status */ + mcast_loop = SLAM_MULTICAST_LOOPBACK; + setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &mcast_loop, sizeof(mcast_loop)); + + + state = STATE_WAITING; + packet = 0; + packet_count = 0; + fds[0].fd = sockfd; + fds[0].events = POLLIN; + fds[0].revents = 0; + for(;;) { + switch(state) { + case STATE_PINGING: + state = STATE_WAITING; + next_client(&master_client); + if (master_client.sin_family == AF_UNSPEC) { + break; + } +#if DEBUG + printf("Pinging %s:%d\n", + inet_ntoa(master_client.sin_addr), + ntohs(master_client.sin_port)); + fflush(stdout); +#endif + + /* Prepare the request packet, it is all header */ + ptr = request_packet; + end = &request_packet[sizeof(request_packet) -1]; + slam_encode(&ptr, end, transaction); + slam_encode(&ptr, end, size); + slam_encode(&ptr, end, SLAM_BLOCK_SIZE); + request_len = ptr - request_packet; + + result = sendto(sockfd, request_packet, request_len, 0, + &master_client, sizeof(master_client)); + /* Forget the client I just asked, when the reply + * comes in we will remember it again. + */ + del_client(&master_client); + break; + case STATE_WAITING: + { + int timeout; + int from_len; + timeout = -1; + if (master_client.sin_family != AF_UNSPEC) { + timeout = SLAM_PING_TIMEOUT; + } + result = poll(fds, sizeof(fds)/sizeof(fds[0]), timeout); + if (result == 0) { + /* On a timeout try the next client */ + state = STATE_PINGING; + break; + } + if (result > 0) { + from_len = sizeof(master_client); + result = recvfrom(sockfd, + nack_packet, sizeof(nack_packet), 0, + &master_client, &from_len); + if (result < 0) + break; + nack_len = result; +#if DEBUG + printf("Received Nack from %s:%d\n", + inet_ntoa(master_client.sin_addr), + ntohs(master_client.sin_port)); + fflush(stdout); +#endif +#if DEBUG + { + ptr = nack_packet; + end = ptr + result; + packet = 0; + result = 0; + while(ptr < end) { + packet += slam_decode(&ptr, end, &result); + if (result < 0) break; + packet_count = slam_decode(&ptr, end, &result); + if (result < 0) break; + printf("%d-%d ", + packet, packet + packet_count -1); + } + printf("\n"); + fflush(stdout); + } +#endif + /* Forget this client temporarily. + * If the packet appears good they will be + * readded. + */ + del_client(&master_client); + ptr = nack_packet; + end = ptr + nack_len; + result = 0; + packet = slam_decode(&ptr, end, &result); + if (result < 0) + break; + packet_count = slam_decode(&ptr, end, &result); + if (result < 0) + break; + /* We appear to have a good packet, keep + * this client. + */ + push_client(&master_client); + + /* Reopen the file to transmit */ + if (filefd != -1) { + close(filefd); + } + filefd = open(filename, O_RDONLY); + if (filefd < 0) { + fprintf(stderr, "Cannot open %s: %s\n", + filename, strerror(errno)); + break; + } + size = lseek(filefd, 0, SEEK_END); + if (size < 0) { + fprintf(stderr, "Seek failed on %s: %s\n", + filename, strerror(errno)); + break; + } + result = fstat(filefd, &st); + if (result < 0) { + fprintf(stderr, "Stat failed on %s: %s\n", + filename, strerror(errno)); + break; + } + transaction = st.st_mtime; + + state = STATE_TRANSMITTING; + break; + } + break; + } + case STATE_RECEIVING: + /* Now clear the queue of received packets */ + { + struct sockaddr_in from; + int from_len; + uint8_t dummy_packet[SLAM_MAX_NACK]; + state = STATE_TRANSMITTING; + result = poll(fds, sizeof(fds)/sizeof(fds[0]), 0); + if (result < 1) + break; + from_len = sizeof(from); + result = recvfrom(sockfd, + dummy_packet, sizeof(dummy_packet), 0, + &from, &from_len); + if (result <= 0) + break; +#if DEBUG + printf("Received Nack from %s:%d\n", + inet_ntoa(from.sin_addr), + ntohs(from.sin_port)); + fflush(stdout); +#endif + /* Receive packets until I don't get any more */ + state = STATE_RECEIVING; + /* Process a packet */ + if (dummy_packet[0] == '\0') { + /* If the first byte is null it is a disconnect + * packet. + */ + del_client(&from); + } + else { + /* Otherwise attempt to add the client. */ + add_client(&from); + } + break; + } + case STATE_TRANSMITTING: + { + off_t off; + off_t offset; + ssize_t bytes; + uint8_t *ptr2, *end2; + + /* After I transmit a packet check for packets to receive. */ + state = STATE_RECEIVING; + + /* Find the packet to transmit */ + offset = packet * SLAM_BLOCK_SIZE; + + /* Seek to the desired packet */ + off = lseek(filefd, offset, SEEK_SET); + if ((off < 0) || (off != offset)) { + fprintf(stderr, "Seek failed on %s:%s\n", + filename, strerror(errno)); + break; + } + /* Encode the packet header */ + ptr2 = data_packet; + end2 = data_packet + sizeof(data_packet); + slam_encode(&ptr2, end2, transaction); + slam_encode(&ptr2, end2, size); + slam_encode(&ptr2, end2, SLAM_BLOCK_SIZE); + slam_encode(&ptr2, end2, packet); + data_len = ptr2 - data_packet; + + /* Read in the data */ + bytes = read(filefd, &data_packet[data_len], + SLAM_BLOCK_SIZE); + if (bytes <= 0) { + fprintf(stderr, "Read failed on %s:%s\n", + filename, strerror(errno)); + break; + } + data_len += bytes; + /* Write out the data */ + result = sendto(sockfd, data_packet, data_len, 0, + &sa_mcast, sizeof(sa_mcast)); + if (result != data_len) { + fprintf(stderr, "Send failed %s\n", + strerror(errno)); + break; + } +#if DEBUG > 1 + printf("Transmitted: %d\n", packet); + fflush(stdout); +#endif + /* Compute the next packet */ + packet++; + packet_count--; + if (packet_count == 0) { + packet += slam_decode(&ptr, end, &result); + if (result >= 0) + packet_count = slam_decode(&ptr, end, &result); + if (result < 0) { + /* When a transmission is done close the file, + * so it may be updated. And then ping then start + * pinging clients to get the transmission started + * again. + */ + state = STATE_PINGING; + close(filefd); + filefd = -1; + break; + } + } + break; + } + } + } + return EXIT_SUCCESS; +} diff --git a/contrib/mkQNXnbi/Makefile b/contrib/mkQNXnbi/Makefile new file mode 100644 index 0000000..4f6c0f2 --- /dev/null +++ b/contrib/mkQNXnbi/Makefile @@ -0,0 +1,10 @@ +# Makefile for the mkQNXnbi filter + +all: mkQNXnbi + +mkQNXnbi: mkQNXnbi.o + +mkQNXnbi.o: mkQNXnbi.c + +clean: + rm -f mkQNXnbi *.o diff --git a/contrib/mkQNXnbi/README b/contrib/mkQNXnbi/README new file mode 100644 index 0000000..1522df3 --- /dev/null +++ b/contrib/mkQNXnbi/README @@ -0,0 +1,36 @@ +mkQNXnbi is a quick hack to generate tagged images from QNX boot images. + +To boot a QNX client with Etherboot you have to consider the following: +1. You MUST have another QNX box running in the network to provide the + root filesystem and the license info to the client. QNX cannot use + e.g. NFS for its root filesystem, as it needs to load a valid license + from a file on the root fs before being able to start TCP/IP. This + would lead to a chicken-and-egg problem. +2. The Net task normally determines the size of its internal tables from + the actual number of licensed nodes. Since this information is not + available at boot time when booting from the network, you will have + to set the max. number of nodes as well as a valid netmap entry for + the node providing the root filesystem as an option to Net in the + build file. + See examples/ws.etherboot and fill in the <blanks>. +3. The client does not need a TCP/IP license in order to boot. +4. You can use the boot-server OS of your choice. If you choose to use + QNX as boot server, the server of course needs a TCP/IP run-time + license. In this case you have the option of creating the boot image + on-the-fly and use the macro $(netmap) instead of a hard-coded MAC + address. + See examples/ws.etherboot.on-the-fly and fill in the <blanks>. + A template bootptab for the QNX bootp server is placed in the + examples directory. +5. mkQNXnbi expects the QNX image to be supplied on stdin and generates + the tagged image to stdout. This can be overridden on the command line + using the options -i <input-file> and -o <output-file>. + +mkQNXnbi can be compiled using e.g. Linux/gcc or on QNX using Watcom C +(or gcc, if you have it - see http://w3c.teaser.fr/~jcmichot/) + +Bug-reports to <al@alarsen.net> + +2002-01-25 +Anders Larsen +<al@alarsen.net> diff --git a/contrib/mkQNXnbi/examples/bootptab b/contrib/mkQNXnbi/examples/bootptab new file mode 100644 index 0000000..2077fa9 --- /dev/null +++ b/contrib/mkQNXnbi/examples/bootptab @@ -0,0 +1,29 @@ +# /etc/bootptab: database for QNX bootp server (/etc/bootpd) + +# First, we define a global entry which specifies the stuff every host uses. +global:\ + :hd=/boot:\ + :ht=ethernet:\ + :sm=<your netmask here>:\ + :bf=|cd /boot; buildqnx -b 0x10000 build/<your build-file here> | mkQNXnbi:\ + :hn: + +# node 2 uses the default build-file +node2:\ + :tc=global:\ + :ha=<your MAC here>:\ + :ip=<your IP address here>: + +# node 3 uses its own build-file +node3:\ + :tc=global:\ + :ha=<your MAC here>:\ + :ip=<your IP address here>:\ + :bf=|cd /boot; buildqnx -b 0x10000 build/<your build-file here> | mkQNXnbi: + +# node 4 uses a pre-built boot image +node3:\ + :tc=global:\ + :ha=<your MAC here>:\ + :ip=<your IP address here>:\ + :bf=images/<your image-file here>: diff --git a/contrib/mkQNXnbi/examples/ws.etherboot b/contrib/mkQNXnbi/examples/ws.etherboot new file mode 100644 index 0000000..d8120bc --- /dev/null +++ b/contrib/mkQNXnbi/examples/ws.etherboot @@ -0,0 +1,22 @@ +# /boot/build/ws.etherboot + +sys/boot +$ boot -v + +sys/Proc32 +$ Proc32 -l <target node number> + +sys/Slib32 +$ Slib32 + +sys/Slib16 +$ Slib16 + +/bin/Net +$ Net -n <highest QNX node number in network> -m "<node number of boot server> 1 <MAC of boot server node here>" + +/bin/Net.<network driver> +$ Net.<network driver> + +/bin/sinit +$ sinit -r //<node number of boot server>/ TERM=<your terminal emulation {QNX|qansi}> diff --git a/contrib/mkQNXnbi/examples/ws.etherboot.on-the-fly b/contrib/mkQNXnbi/examples/ws.etherboot.on-the-fly new file mode 100644 index 0000000..3058c45 --- /dev/null +++ b/contrib/mkQNXnbi/examples/ws.etherboot.on-the-fly @@ -0,0 +1,22 @@ +# /boot/build/ws.etherboot.on-the-fly + +sys/boot +$ boot -v + +sys/Proc32 +$ Proc32 -l $(lnode) + +sys/Slib32 +$ Slib32 + +sys/Slib16 +$ Slib16 + +/bin/Net +$ Net -n <highest QNX node number in network> -m $(netmap) + +/bin/Net.<network driver> +$ Net.<network driver> + +/bin/sinit +$ sinit -r //$(bnode)/ TERM=<your terminal emulation {QNX|qansi}> diff --git a/contrib/mkQNXnbi/mkQNXnbi.c b/contrib/mkQNXnbi/mkQNXnbi.c new file mode 100644 index 0000000..2ec2dc4 --- /dev/null +++ b/contrib/mkQNXnbi/mkQNXnbi.c @@ -0,0 +1,196 @@ +//***************************************************************************** +// +// Purpose: Make a boot-image for EtherBoot +// +// +// Compiler: This source can be compiled with gcc and Watcom C +// +// +// Note: The QNX boot image can be build with any reasonable +// start address, e.g. 0x1000 (default) or 0x10000 +// (widespread Boot-Rom address) +// +// +// Author: Anders Larsen +// +// +// Copyright: (C) 1999 by +// +// Anders Larsen +// systems engineer +// Gutleuthausstr. 3 +// D-69469 Weinheim +// Germany +// phone: +49-6201-961717 +// fax: +49-6201-961718 +// e-mail: al@alarsen.net +// +// 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; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +//----------------------------------------------------------------------------- +// +// Change Log: +// V0.2: Sun 1999-12-13 Anders Larsen <al@alarsen.net> +//***************************************************************************** + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> + + +// max. size of QNX OS boot image is 512K +#define MAXSIZE (512*1024) + +typedef unsigned short ushort_t; +typedef unsigned long ulong_t; + + +// global header of tagged image: +struct initial_t +{ + ulong_t magic; + ulong_t length; + ulong_t location; + ulong_t start; +}; + + +// header of each image: +struct header_t +{ + ulong_t flags; + ulong_t loadaddr; + ulong_t imgsize; + ulong_t memsize; +}; + + +// global header of the QNX EtherBoot image: +struct qnx_loader_t +{ + struct initial_t setup; + struct header_t qnx; +}; + + +// global header: +union +{ + struct qnx_loader_t h; + char filler[512]; +} header; + + +char buffer[MAXSIZE]; + + +int usage( char* const* argv ) +{ + fprintf( stderr, "%s - make a tagged boot image for EtherBoot\n", *argv ); + fprintf( stderr, "\nuse:\n" ); + fprintf( stderr, "%s [ -<option> ]*\n", *argv ); + fprintf( stderr, "\noptions:\n" ); + fprintf( stderr, " i <input file> : QNX boot file (default: stdin)\n" ); + fprintf( stderr, " o <output file> : tagged image file (default: stdout)\n" ); + fprintf( stderr, " v : be verbose\n" ); + return EXIT_FAILURE; +} + +#ifdef __USAGE +%C - make a tagged boot image for EtherBoot + +use: +%C [ -<option> ]* + +options: + i <input file> : QNX boot file (default: stdin) + o <output file> : tagged image file (default: stdout) + v : be verbose +#endif + + +int main( int argc, char* const* argv ) +{ + int ch, l; + int verbose = 0; + + while ( ( ch = getopt( argc, argv, "hi:o:v" ) ) != EOF ) + switch ( ch ) + { + case 'i': + if ( !freopen( optarg, "r", stdin ) ) + { + perror( "can't open input file" ); + return EXIT_FAILURE; + } + break; + + case 'o': + if ( !freopen( optarg, "w", stdout ) ) + { + perror( "can't create output file" ); + return EXIT_FAILURE; + } + break; + + case 'v': + verbose++; + break; + + case 'h': + default: + return usage( argv ); + } + if ( optind != argc ) + return usage( argv ); + + memset( &header, 0, sizeof header ); + header.h.setup.magic = 0x1b031336; // magic number + header.h.setup.length = 4; + header.h.setup.location = 0x93e00000; // just below the EtherBoot rom + header.h.setup.start = 0; // filled in dynamically + header.h.qnx.flags = 0x04000004; // single image only + header.h.qnx.loadaddr = 0; // filled in dynamically + header.h.qnx.imgsize = 0; // filled in dynamically + header.h.qnx.memsize = 0; // filled in dynamically + + // read the QNX image from stdin: + for ( ; ( l = fread( buffer + header.h.qnx.imgsize, 1, 1024, stdin ) ) > 0; + header.h.qnx.imgsize += l + ) + ; + header.h.qnx.memsize = header.h.qnx.imgsize; + + // fill in the real load-address of the QNX boot image: + header.h.setup.start = *(ushort_t*)&buffer[10] << 16; + header.h.qnx.loadaddr = *(ushort_t*)&buffer[10] << 4; + + // write the tagged image file to stdout: + fwrite( &header, 1, 512, stdout ); + fwrite( buffer, 1, header.h.qnx.imgsize, stdout ); + + if ( verbose ) + { + // print diagnostic information: + fprintf( stderr, "QNX image size: %d bytes (%dK), load addr: 0x%05X\n", + header.h.qnx.imgsize, + header.h.qnx.imgsize / 1024, + header.h.qnx.loadaddr + ); + } + return EXIT_SUCCESS; +} diff --git a/contrib/mkffwnb/2.0.10/linuxrc b/contrib/mkffwnb/2.0.10/linuxrc new file mode 100755 index 0000000..351679c --- /dev/null +++ b/contrib/mkffwnb/2.0.10/linuxrc @@ -0,0 +1,76 @@ +#!/bin/sh +# +# floppyfw initfile +# +# nicked from: +# hal91's initfile (/linuxrc), the bootup script of the system +# + +VERSION=2.1.6 + +load_fsmod () { + case $1 in + /dev/hd*) + insmod ide-cd + insmod cdrom + ;; + esac + case $2 in + vfat) + echo vfat support is builtin + ;; + iso9660) + insmod isofs + ;; + esac +} + +# +/bin/busybox echo "Booting floppyfw" + +PATH="/bin:/sbin:/usr/bin:/usr/sbin" +#PATH="/bin" +TERM=linux +ignoreeof=10 +no_exit_on_failed_exec=yes +export PATH TERM ignoreeof +umask 022 + +/bin/busybox echo "mounting: proc" +/bin/busybox mount -t proc /proc /proc + +/bin/busybox echo "Generating links. (Thanks to busybox.lineo.com)" +/bin/busybox --install -s + +echo "Generated" + +# Modified by Gem, based on coyote distro, changes by Ken Yap +ROOTDEV=`sed -e 's/$/ /' -e 's/.*root=\([^ ]*\) .*/\1/' -e 's/,/ /g' -e 's:/dev/nfs:/dev/fd0:' /proc/cmdline` +set -- $ROOTDEV +# Backward compatibility with a single device argument +if [ $# -eq 1 ] +then + set -- $1 vfat +fi +while [ "$1" -a "$2" ] +do + echo "attempting to mount $1 ($2)" + load_fsmod $1 $2 + if mount -t $2 $1 /mnt/tmp + then + echo "mounted $1 on /mnt/tmp" + break + fi + shift; shift +done + +[ -f /mnt/tmp/floppyfw/floppyfw.ini ] && cat /mnt/tmp/floppyfw/floppyfw.ini \ +| tr -d '\015' >/floppyfw.ini + +[ -f /floppyfw.ini ] && chmod 777 /floppyfw.ini +[ -f /floppyfw.ini ] && exec /floppyfw.ini + +echo +echo "** floppyfw.ini failed.. starting a shell" +echo +exec sh diff --git a/contrib/mkffwnb/Extendinitrd.pm b/contrib/mkffwnb/Extendinitrd.pm new file mode 100644 index 0000000..3b919ad --- /dev/null +++ b/contrib/mkffwnb/Extendinitrd.pm @@ -0,0 +1,43 @@ +#!/usr/bin/perl -w + +sub status_system ($$) { + my ($command, $message) = @_; + + $status = system($command); + $status <<= 8; + if ($status < 0) { + print STDERR "$!\n"; + } + if ($status != 0) { + print STDERR "$message\n"; + } +} + +sub extendinitrd ($$) { + my ($initrd, $nblocks) = @_; + + if ($nblocks <= 1440) { + print STDERR "nblocks must be >= 1440\n"; + return (1); + } + (undef, $type, undef, $fnlen, undef) = split(' ', `file $initrd`, 5); + print "$type $fnlen\n"; + if ($type ne 'Minix' || $fnlen != 30) { + die "Can only handle Minix initrds with 30 char filenames\n"; + return (1); + } + status_system("dd if=/dev/zero of=newinitrd bs=1k count=$nblocks", "Cannot create new initrd\n"); + status_system("mkfs.minix -n 30 newinitrd $nblocks", "Cannot mkfs.minix new initrd\n"); + mkdir("initrd.from") || print STDERR "Cannot make temp mount point initrd.from\n"; + mkdir("initrd.to") || print STDERR "Cannot make temp mount point initrd.to\n"; + status_system("mount -o ro,loop $initrd initrd.from", "Cannot mount $initrd on initrd.from"); + status_system("mount -o loop newinitrd initrd.to", "Cannot mount newinitrd on initrd.to"); + status_system("cp -a initrd.from/* initrd.to/", "Cannot copy initrd to newinitrd"); + status_system("umount initrd.from", "Cannot umount initrd.from"); + status_system("umount initrd.to", "Cannot umount initrd.to"); + rmdir("initrd.from") || print STDERR "Cannot remove temp mount point initrd.from\n"; + rmdir("initrd.to") || print STDERR "Cannot remove temp mount point initrd.to\n"; + return (0); +} + +1; diff --git a/contrib/mkffwnb/README b/contrib/mkffwnb/README new file mode 100644 index 0000000..38df476 --- /dev/null +++ b/contrib/mkffwnb/README @@ -0,0 +1,69 @@ +This is a quick and dirty script to convert a floppyfw floppy +(http://www.zelow.no/floppyfw/) to a tagged image for booting with +Etherboot (http://etherboot.sourceforge.net/). The advantages of network +booting include: it's much faster loading from the network than from a +floppy disk, you can boot from any size floppy, and you are not limited +to the maximum of 1.44 MB of the physical floppy. If you have enough RAM +and use a virtual floppy to build the initial boot image, you can put as +much on it as will fit the ramdisk. + +See further down under -nonet if you want to boot from HD or CDROM. + +This program requires mtools, tar, bzip2, loopback mount in the kernel, +and root privileges to execute. Hope you have them. + +This script works for any of the releases for which a subdirectory of +that name is provided, but it should not be too hard to make it work for +other releases, all that is done here is to substitute some scripts for +the distributed ones. + +First of all you should make the floppy work the way you want before +converting it to a tagged image. This involves editing the various +config files on the floppy. Instructions on this are distributed from +the floppyfw web page mentioned above. + +Edit the $tftpdir assignment for the directory where you put your tagged +images. Edit the $libdir assignment and the use lib directive near the +top if you decide to put this package somewhere other than +/usr/local/lib/mkffwnb/. Adjust the instructions below as necessary. + +Copy everything to $libdir. + + mkdir -p /usr/local/lib/mkffwnb/ + cp -a . /usr/local/lib/mkffwnb/ + +Make a link from /usr/local/lib/mkffwnb/mkffwnb.pl to +/usr/local/bin/mkffwnb so that it's in your path. + + ln -s /usr/local/lib/mkffwnb/mkffwnb.pl /usr/local/bin/mkffwnb + +Then run it as: + + mkffwnb + +You can also provide a floppy drive as an argument, e.g. + + mkffwnb x: + +where x: could be mapped to a disk file. This allows you to build an +image without a real floppy drive. Remember that for virtual drives root +must have the mapping for the drive in question in ~root/.mtoolsrc. + +You can use the option --localtime=/etc/localtime to specify that the +file /etc/localtime is to be copied to /etc/localtime on the initrd. +Instead of /etc/localtime, you can use any of the timezone files under +/usr/share/zoneinfo/, it's just that /etc/localtime will usually be the +correct one for your timezone. + +If you use the option -nonet, it leaves the intermediate files in +$tempdir, /tmp/mkffwnb by default. This is useful if you want the +vmlinuz and initrd.gz files for use with LILO or isolinux to boot from +HD or CDROM. Actually you can also use these with a floppy, it loads +faster if you fold all the scripts and modules into the initrd ahead +of time. + +mkffwnb has to be run as root because it uses loopback mounts and also +because the files inside the initrd are owned by root. + +Ken Yap +2003-04-20 diff --git a/contrib/mkffwnb/mkffwnb.pl b/contrib/mkffwnb/mkffwnb.pl new file mode 100755 index 0000000..555ec3c --- /dev/null +++ b/contrib/mkffwnb/mkffwnb.pl @@ -0,0 +1,226 @@ +#!/usr/bin/perl -w +# +# Perl script to make a bootable image from a floppyfw floppy +# The basic idea is to unpack and replace or convert all +# the necessary config files into the initrd +# and then make a bootable image out of it +# +# The --format= option overrides the default of nbi or elf hardcoded +# in the source. Valid arguments are nbi or elf. +# +# The --output= options specifies an output file instead of stdout +# The --nonet option specifies that a netbootable image is not to +# be built but the vmlinuz and initrd.gz files left behind in $tempdir +# The --localtime=f option specifies a timezone file that's to be +# copied to /etc/localtime in the initrd, allowing a different timezone. +# The --ffw29 option is intended for 2.9.x and above and extends +# the size of the initrd by making a bigger one and copying the original over. +# +# The first non-option argument is taken to be the letter of a floppy to +# convert, e.g. a:, b: or even x: where x: is mapped to a file using +# mtools mapping in $HOME/.mtoolsrc. See the mtools documentation. +# Thus you can work on a floppy image in a disk file and only write +# to a floppy with dd or cp when you need to test the image. + +use Getopt::Long; + +use lib '/usr/local/lib/mkffwnb/'; +use Extendinitrd; + +use strict; + +use vars qw($testing $verbose $localtime $nonet $format $ffw29 $imagefile + $floppy $libdir $tftpdir $output $tempdir $tempmount); + +sub findversion () { + my ($version) = grep(/FloppyFW/, `mtype $imagefile ${floppy}floppyfw.msg`); + return '' unless defined($version) and $version ne ''; + chomp($version); + $version =~ s/.*FloppyFW (\d+\.\d+\.\d+(\.\d+)?).*/$1/; + return ($version); +} + +sub getappendargs () { + my ($append) = join(' ', grep(/^\s*(append\s|console=)/, `mtype $imagefile ${floppy}syslinux.cfg`)); + chomp ($append); + my @args = split(/\s+/, $append); + my @result = (); + foreach $_ (@args) { + next if (/^$/ or /^append/ or /^initrd=/); + next if (!$ffw29 and /^root=/); + push (@result, $_); + } + return (join(' ', @result)); +} + +# Copy whole floppy to the current directory +# m preserves timestamps, n overwrites without warning and / means recursive +sub mcopy ($) { + my ($tempdir) = @_; + + print "mcopy $imagefile -mn/ ${floppy}* $tempdir\n"; + my $status = system("mcopy -mn/ $imagefile ${floppy}* $tempdir"); + return ($status / 256); +} + +# Gunzip file, -f forces overwriting of uncompressed file +sub gunzip ($) { + my ($file) = @_; + + print "Gunzipping $file\n" if ($verbose); + my $status = system('gunzip', '-f', $file); + return ($status / 256); +} + +# Gzip file, -f forces overwriting of compressed file +sub gzip ($) { + my ($file) = @_; + + print "Gzipping $file\n" if ($verbose); + my $status = system('gzip', '-9', '-f', $file); + return ($status / 256); +} + +sub loopbackmount ($$) { + my ($file, $point) = @_; + + print "Mounting $file on $point loopback\n" if ($verbose); + my $status = system('mount', '-o', 'loop', $file, $point); + return ($testing ? 0 : $status / 256); +} + +sub loopbackumount ($) { + my ($point) = @_; + + print "Umounting $point\n" if ($verbose); + my $status = system('umount', $point); + return ($testing ? 0 : $status / 256); +} + +# Convert DOS CR-NL to Unix NL. $dst has implied prefix of $tempmount +# Use @output for temporary storage in case we write back to the same file +sub dostounix ($$) { + my ($src, $dst) = @_; + my @output = (); + + $dst = "$tempmount/$dst"; + print "Converting $src to $dst\n" if ($verbose); + unless (open(S, $src)) { + print "$src: $!\n"; + return (0); + } + while (<S>) { + chomp; + tr /\015//d; + push(@output, $_); + } + close(S); + open(D, ">$dst") or return; + for $_ (@output) { + print D "$_\n"; + } + close(D); + chmod(0755, $dst); + return (1); +} + +sub bunzip2untar ($$) { + my ($file, $dir) = @_; + + print "Unpacking $file into $dir\n" if ($verbose); + system("bunzip2 < $file | (cd $dir; tar xf -)"); +} + +$testing = $< != 0; +$verbose = 1; +$format = ''; +$imagefile = ''; +GetOptions('output=s' => \$output, + 'nonet!' => \$nonet, + 'localtime=s' => \$localtime, + 'format=s' => \$format, + 'ffw29!' => \$ffw29, + 'ffw30!' => \$ffw29, + 'i=s' => \$imagefile); +if (defined($output) and $output !~ m(^/)) { + my $d = `pwd`; + chomp($d); + $output = "$d/$output"; +} +if ($imagefile) { + $imagefile = "-i $imagefile"; +} +$libdir = '/usr/local/lib/mkffwnb'; +$tftpdir = '/usr/local/var/tftpboot'; +# default can also be 'elf' +$format = 'nbi' if ($format ne 'elf' and $format ne 'nbi'); +$floppy = $#ARGV >= 0 ? $ARGV[0] : 'a:'; +print <<EOF; +This program requires mtools, tar, bzip2, loopback mount in the kernel, +and root privileges to execute. Hope you have them. +EOF +my $version = &findversion(); +$version ne '' or die "Cannot determine version\n"; +print "Version $version\n"; +my $append = &getappendargs(); +$append = "--append='$append'" if $append ne ''; +print "$append\n"; +$libdir .= '/' . $version; +-d $libdir or die "Cannot find files for $version\n"; +$tempdir = $nonet ? '/tmp/mkffwnb' : "/tmp/mkffwnb$$"; +$tempmount = 'tmpmount'; +mkdir($tempdir, 0755); +print "Copying files off floppy, please be patient...\n"; +&mcopy($tempdir) == 0 or die "Mcopy failed, diskette problem?\n"; +chdir($tempdir); +&gunzip('initrd.gz') == 0 or die "Gunzip of initrd.gz failed\n"; +if ($ffw29) { + extendinitrd("initrd", 5760); + system("mv newinitrd initrd"); +} +mkdir($tempmount, 0755); +&loopbackmount('initrd', $tempmount) == 0 or die "Loopback mount failed\n"; +&dostounix("$libdir/linuxrc", "linuxrc") if (-r "$libdir/linuxrc"); +unless (&dostounix("$libdir/floppyfw.ini", "floppyfw.ini")) { + &dostounix("floppyfw/floppyfw.ini", $ffw29 ? "etc/floppyfw.ini" : "floppyfw.ini"); +} +&dostounix("config", $ffw29 ? "etc/config.prelogin" : "etc/config"); +for my $i (glob('*.bz2 floppyfw/add.bz2 modules/*.bz2 packages/*.bz2')) { + &bunzip2untar($i, $tempmount); +} +for my $i (glob('packages/*.ini')) { + my $file = $i; + $file =~ s:packages/::; + &dostounix($i, "etc/$file"); +} +&dostounix("hosts", "etc/hosts"); +&dostounix("modules.lst", "etc/modules.lst"); +&dostounix("network.ini", "etc/network.init"); +&dostounix("firewall.ini", "etc/firewall.init"); +&dostounix("syslog.cfg", "etc/syslog.conf"); +&dostounix("packages/timeinfo", "etc/localtime"); +system("cp -p licenses/* $tempmount/licenses/"); +# This conditional code is for 1.1.2 and below +unless (glob('modules/*.bz2')) { + print "Copying additional modules\n" if ($verbose); + system("cp -p modules/* $tempmount/lib/modules/"); +} +# If a timezone file has been specified, copy that onto initrd +if (defined($localtime)) { + if (-r $localtime) { + print "Copying $localtime to $tempmount/etc/localtime\n"; + system("cp -p $localtime $tempmount/etc/localtime"); + } else { + print "$localtime: $!\n"; + } +} +&loopbackumount($tempmount) == 0 or die "Loopback umount failed\n"; +&gzip('initrd') == 0 or die "Gzip of initrd failed\n"; +if ($nonet) { + print "Floppyfw directory in $tempdir\n"; +} else { + print "Calling mk$format-linux to make the netbootable image\n" if ($verbose); + $output = "$tftpdir/floppyfw-$version.nb" if (!defined($output)); + system("mk$format-linux $append --output=$output vmlinuz initrd.gz"); + system("rm -fr $tempdir"); +} diff --git a/contrib/mklrpnb/README.txt b/contrib/mklrpnb/README.txt new file mode 100644 index 0000000..c99c55c --- /dev/null +++ b/contrib/mklrpnb/README.txt @@ -0,0 +1,4 @@ +This is a quick and dirty Perl program to make a netbootable +image from a Linux Router floppy. It was tested with a Coyote Linux +(http://www.coyotelinux.com) floppy which is based on LRP. You need tar, +mtools, mknbi-1.0, and of course, perl, to run this script. diff --git a/contrib/mklrpnb/extractdach.pl b/contrib/mklrpnb/extractdach.pl new file mode 100644 index 0000000..6c81da3 --- /dev/null +++ b/contrib/mklrpnb/extractdach.pl @@ -0,0 +1,191 @@ +#!/usr/bin/perl -w +# +# A program to make a netbootable image from a LRP firewall floppy +# +# Tested on a Dachstein Linux floppy image available from +# http://lrp1.steinkuehler.net/ or via http://leaf.sourceforge.net/ + +# The most recent version of this script and a companion HowTo is available at +# http://members.optushome.com.au/graybeard/linux/netboot.html +# +# Modified from the mklrpnb file found in the contrib/mklrpnb directory of the +# Etherboot source at http://etherboot.sourceforge.net/ +# +# Modifications by Glenn McK <graybeard@users.sourceforge.net> +# $Id$ +##################################### + +# this entry will need changing +$image = "/home/graybeard/etherboot/dachstein-v1.0.2-1680.bin"; + +# these can remain, but change them if desired +# +# the next argument defaults to firewall if no other name is passed via the +# command line, this will be the directory where distribution will be expanded +# under $base and also the directory in /tftpboot for lrp.nb + +my $uniqdir = shift || 'firewall'; + +$mntdir = "/mnt/floppy"; # where the above image file can be mounted +$tftpbase = "/tftpboot"; +$tftpboot = "$tftpbase/$uniqdir"; # where the netboot images will be available +$base = "/usr/src/LRP"; +$dachorg = "$base/dach-org-$uniqdir"; # a copy required to make the distribution +$dachnew = "$base/lrp-$uniqdir"; # the base files for the new distribution +$packages = "$dachnew/var/lib/lrpkg"; # list to allow lrcfg to display Packages + +# everything below should be okay +###################################### + +if ( !-e $image ) { + print +"\n\tA valid LRP file and directory are required\n\tdownload one then edit $0\n\n"; + exit 1; +} +if ( !-d $base ) { + mkdir( $base, 0700 ); +} + +if ( !-d $dachorg ) { + mkdir( $dachorg, 0700 ); +} + +if ( !-d $dachnew ) { + mkdir( $dachnew, 0700 ); + `umount $mntdir`; + `mount -o ro,loop $image $mntdir`; + + `cp -vr $mntdir/* $dachorg/`; + + @cfg = `cat $mntdir/syslinux.cfg`; + + unless ( defined(@cfg) ) { + print "Cannot find syslinux.cfg on $mntdir\n"; + exit 1; + } + print "cfg = @cfg\n"; + ($append) = grep( /append/, @cfg ); # find the append= line + print "append = \n$append\n"; + chomp($append); # remove trailing newline + $append =~ s/append=//; # remove the append= at beginning + print "strip append = \n$append\n\n"; + @args = split ( / /, $append ); # split into arguments at whitespace + ($root) = grep( /^initrd=/, @args ); # find the initrd= argument + $root =~ s/^initrd=//; # remove the initrd= at beginning + $root =~ s/\.lrp$//; # cleanup for paclages list + print "strip initrd = \n$root\n\n"; + ($lrp) = grep( /^LRP=/, @args ); # find the LRP= argument + $lrp =~ s/^LRP=//; # remove the LRP= at beginning + print "strip LRP =\n$lrp\n\n"; + @lrp = split ( /,/, $lrp ); # split into filenames at , + unshift ( @lrp, $root ); # prepend the root LRP filename + @pack = @lrp; + print "LRP =\n@lrp\n\n"; + $append = ''; + + foreach $i (@args) { # rebuild the append string + next if ( $i =~ /^initrd=/ ); # minus the unneeded parameters + next if ( $i =~ /^LRP=/ ); + next if ( $i =~ /^boot=/ ); + next if ( $i =~ /^PKGPATH=/ ); + print "$i = i\n"; + $append .= "$i "; + } + + print "final append = \n$append\n"; + + chdir($dachnew) or die "$dachnew: $!\n"; + foreach $i (@lrp) { + $i .= '.lrp' if $i !~ /\.lrp$/; + print "\n\n\nUnpacking $i\n"; + system("ln -svf $dachorg/$i ${dachorg}/${i}.tar.gz"); + chmod 0600, "$dachorg/$i"; + system("cat $mntdir/$i | tar zxvf -"); + } + + # create file for lrcfg to display packages + open( PACKAGES, ">$packages/packages" ) + || print "unable to modify $packages:$!\n"; + foreach $line (@pack) { + print PACKAGES "$line\n"; + } + close PACKAGES; + + # prevent previous file from being overwritten during installation + # and also mess with some values in /linuxrc to hide non errors + open( LINUXRC, "$packages/root.linuxrc" ); + @text = <LINUXRC>; + close LINUXRC; + open( LINUXRC, ">$packages/root.linuxrc" ); + foreach $line (@text) { + $line =~ s/PFX\/packages/PFX\/packages-old \ +\t\t\t\t# packages changed to packages-old for netboot setup/; + $line =~ +s/^rc=1/# rc=1 changed to rc=0 to suppress error messages for netboot setup \ +rc=0/; + $line =~ +s/echo -n \" \(nf\!\)\"/#echo -n \" \(nf\!\)\" changed to reflect ToDo list \ +\t\t\techo -n \" netboot setup - No backups possible from this machine - ToFix ?"/; + print LINUXRC $line; + } + close LINUXRC; + + # swap interfaces around in network config file + # eth1 is the new external eth0 is OUR internal server access + open( NETWORK, "$dachnew/etc/network.conf" ) + || print "Unable to modify NETWORK:$!\n"; + @text = <NETWORK>; + close NETWORK; + open( NETWORK, ">$dachnew/etc/network.conf" ) + || print "Unable to modify NETWORK:$!\n"; + foreach $line (@text) { + $line =~ s/eth0/eth00/; + $line =~ s/eth1/eth0/; + $line =~ s/eth00/eth1/; + print NETWORK $line; + } + close NETWORK; + + `echo $append > $dachorg/appendstr`; + + `umount /mnt/floppy`; + print "\nThe files have been extracted to $dachnew\n"; + system("ls -al $dachnew"); +} +else { + print "\n\n\t$image \n \thas already been extracted to $dachnew \ +\tNow skipping to the next step where the netboot file\ +\twill be created.\n"; + + $append = `cat $dachorg/appendstr`; + print "\nThe new append string will be...\n$append\n"; + + chdir($dachnew); + if ( !-d $tftpbase ) { + mkdir( $tftpbase, 0710 ); + system("chgrp nobody $tftpbase"); + } + + unlink($tftpboot); + + # these permissions really need changing to something secure + mkdir( $tftpboot, 0710 ); + system("chgrp nobody $tftpboot"); + print "\tRepacking to $tftpboot/lrp.lrp\n"; + system("tar zcf $tftpboot/lrp.lrp *"); + print "\tExtracting kernel image from $dachorg\n"; + system("cat $dachorg/linux > $tftpboot/lrp.ker"); + print "\tCreating netboot image $tftpboot/lrp.nb\n"; + system( +"mknbi-linux --append='$append' --output=$tftpboot/lrp.nb $tftpboot/lrp.ker $tftpboot/lrp.lrp" + ); + chmod 0604, "$tftpboot/lrp.nb", "$tftpboot/lrp.ker", "$tftpboot/lrp.lrp"; + print "\nThese netboot files are in $tftpboot\n"; + system("ls -al $tftpboot"); + print "\n The owner and permissions for $tftpboot \ + and files should be checked for security. The above\ +permissions assume that tftp is running chroot (nobody) + drwx--r--- root:nobody /tftpboot\n\n"; +} + +exit 0; diff --git a/contrib/mklrpnb/mklrpnb b/contrib/mklrpnb/mklrpnb new file mode 100755 index 0000000..47590f7 --- /dev/null +++ b/contrib/mklrpnb/mklrpnb @@ -0,0 +1,45 @@ +#!/usr/bin/perl -w +# +# A program to make a netbootable image from a LRP firewall floppy +# Tested on a Coyote Linux floppy +# +@cfg = `mtype a:syslinux.cfg`; +unless (defined(@cfg)) { + print "Cannot find syslinux.cfg on floppy\n"; + exit 1; +} +($append) = grep(/^append/, @cfg); # find the append= line +chomp($append); # remove trailing newline +$append =~ s/append=//; # remove the append= at beginning +@args = split(/ /, $append); # split into arguments at whitespace +($root) = grep(/^initrd=/, @args); # find the initrd= argument +$root =~ s/^initrd=//; # remove the initrd= at beginning +($lrp) = grep(/^LRP=/, @args); # find the LRP= argument +$lrp =~ s/^LRP=//; # remove the LRP= at beginning +@lrp = split(/,/, $lrp); # split into filenames at , +unshift(@lrp, $root); # prepend the root LRP filename +$append = ''; +foreach $i (@args) { # rebuild the append string + next if ($i =~ /^initrd=/); # minus the unneeded parameters + next if ($i =~ /^LRP=/); + next if ($i =~ /^boot=/); + $append .= "$i "; +} +# print "$append\n"; +$tempdir = "/tmp/lrp$$"; +mkdir($tempdir, 0777) or die "$tempdir: $!\n"; +chdir($tempdir) or die "$tempdir: $!\n"; +foreach $i (@lrp) { + $i .= '.lrp' if $i !~ /\.lrp$/; + print "Unpacking $i\n"; + system("mtype a:$i | tar zxvf -"); +} +print "Repacking to /tmp/lrp.lrp\n"; +system("tar zcf /tmp/lrp.lrp *"); +chdir('/tmp') or die "/tmp: $!\n"; +system("rm -fr $tempdir"); +print "Extracting kernel image from floppy\n"; +system("mtype a:linux > /tmp/lrp.ker"); +print "Creating netboot image in /tmp/lrp.nb\n"; +system("mkelf-linux --append='$append' --output=/tmp/lrp.nb /tmp/lrp.ker /tmp/lrp.lrp"); +exit 0; diff --git a/contrib/mntnbi/mntnbi.pl b/contrib/mntnbi/mntnbi.pl new file mode 100755 index 0000000..55b8148 --- /dev/null +++ b/contrib/mntnbi/mntnbi.pl @@ -0,0 +1,97 @@ +#!/usr/bin/perl -w +# +# Quick Perl program to decode and display details about +# tagged images created by mknbi, and then mount the contained +# DOS filesystem using a loop-back mount +# +# Martin Atkins, November 1998 +# by hacking disnbi by +# Ken Yap, September 1998 +# +# + +sub getvendordata { + my ($flags) = @_; + + my $vendordata = ''; + my $vendorlen = ($flags & 0xff) >> 4; + if ($vendorlen > 0) { + $vendorlen *= 4; + $vendordata = unpack("A$vendorlen", substr($imageheader, $curoffset)); + $curoffset += $vendorlen; + } + return ($vendordata); +} + +sub decodesegmentflags { + my ($flags) = @_; + + $flags >>= 24; + $flags &= 0x3; + ($flags == 0) and $type = "Absolute"; + ($flags == 1) and $type = "Follows last segment"; + ($flags == 2) and $type = "Below end of memory"; + ($flags == 3) and $type = "Below last segment loaded"; + return ($type); +} + +sub onesegment +{ + my ($segnum) = @_; + my ($type, $vendordata); + + my ($flags, $loadaddr, $imagelen, $memlength) = unpack("V4", substr($imageheader, $curoffset)); + $curoffset += 16; + print "Segment number $segnum\n"; + printf "Load address:\t\t%08x\n", $loadaddr; + printf "Image length:\t\t%d\n", $imagelen; + printf "Memory length:\t\t%d\n", $memlength; + $type = &decodesegmentflags($flags); + printf "Position:\t\t$type\n"; + printf "Vendor tag:\t\t%d\n", ($flags >> 8) & 0xff; + if (($vendordata = &getvendordata($flags)) ne '') { + print "Vendor data:\t\t", $vendordata, "\n"; + } + print "\n"; + push (@seglengths, $imagelen); + return (($flags >> 26) & 1); +} + +@seglengths = (); +$#ARGV == 1 or die "Usage: mntnbi tagged-image-file dir\n"; +$imagefile= $ARGV[0]; +open(I, $ARGV[0]) or die "$imagefile: $!\n"; +(defined($status = sysread(I, $imageheader, 512)) and $status == 512) + or die "$imagefile: Cannot read header\n"; +$headerrecord = substr($imageheader, 0, 16); +($magic, $flags, $bx, $ds, $ip, $cs) = unpack("a4Vv4", $headerrecord); +$magic eq "\x36\x13\x03\x1B" or die "$imagefile: Not a tagged image file\n"; +$curoffset = 16; + +# Now decode the header + +printf "Header location:\t%04x:%04x\n", $ds, $bx; +printf "Start address:\t\t%04x:%04x\n", $cs, $ip; +printf "Flags:\n"; + print "Return to loader after execution (extension)\n" if (($flags >> 8) & 1); +if (($vendordata = &getvendordata($flags)) ne '') { + print "Vendor data:\t\t", $vendordata, "\n"; +} +print "\n"; + +# Now decode each segment record + +$segnum = 1; +do { + $lastrecord = &onesegment($segnum); + ++$segnum; +} while (!$lastrecord); + +if ($#seglengths != 1) { + die "This is not a DOS image $#seglengths\n"; +} +$offset = 512 + $seglengths[0]; +print "mounting filesystem at offset $offset in $ARGV[0] on $ARGV[1]\n"; +$rc = system "mount $ARGV[0] $ARGV[1] -t msdos -o loop,offset=$offset"; +print "Done\n" if ($rc == 0); +exit(0); diff --git a/contrib/nfs-swap/README b/contrib/nfs-swap/README new file mode 100644 index 0000000..b95e5d7 --- /dev/null +++ b/contrib/nfs-swap/README @@ -0,0 +1,2 @@ +For more information please check +http://nfs-swap.dot-heine.de diff --git a/contrib/p910nd-0.8/Makefile b/contrib/p910nd-0.8/Makefile new file mode 100644 index 0000000..c2827d2 --- /dev/null +++ b/contrib/p910nd-0.8/Makefile @@ -0,0 +1,10 @@ +# Comment out the second command and uncomment the first command +# below if you don't want to use libwrap (hosts.{allow,deny} access control) + +# If you don't have it in /var/log/subsys, uncomment and define +#CFLAGS+=-DLOCKFILE_DIR=\"/var/log\" +LIBWRAP=-lwrap + +p910nd: p910nd.c +# $(CC) -Wall $(CFLAGS) -o $@ p910nd.c + $(CC) -Wall $(CFLAGS) -DUSE_LIBWRAP -o $@ p910nd.c $(LIBWRAP) diff --git a/contrib/p910nd-0.8/banner.pl b/contrib/p910nd-0.8/banner.pl new file mode 100755 index 0000000..5a238c8 --- /dev/null +++ b/contrib/p910nd-0.8/banner.pl @@ -0,0 +1,9 @@ +#!/usr/bin/perl +while (1) +{ + exit 0 if read(STDIN,$c,1) == 0; + last if ($cl eq "\031" && $c eq "\001"); + $cl = $c; +} +kill 'STOP',$$; +exit 0 diff --git a/contrib/p910nd-0.8/client.pl b/contrib/p910nd-0.8/client.pl new file mode 100755 index 0000000..0b0e4c3 --- /dev/null +++ b/contrib/p910nd-0.8/client.pl @@ -0,0 +1,58 @@ +#!/usr/bin/perl + +# edit this to the printer hostname +$them = 'ken'; +$port = 9101; + +open(STDIN, "$ARGV[0]") if $#ARGV >= 0; + +use Socket; +#use Sys::Hostname; + +#$hostname = hostname; + +($name, $aliases, $proto) = getprotobyname('tcp'); +($name, $aliases, $port) = getservbyname($port, 'tcp') + unless $port =~ /^\d+$/; + +#$thisaddr = inet_aton($hostname); +#defined($thisaddr) or &errexit("inet_aton: cannot resolve $hostname\n"); + +$thataddr = inet_aton($them); +defined($thataddr) or &errexit("inet_aton: cannot resolve $them\n"); + +socket(S, PF_INET, SOCK_STREAM, $proto) or &errexit("socket: $!\n"); + +#$this = sockaddr_in(0, $thisaddr); +#bind(S, $this) || &errexit("bind: $!\n"); + +$that = sockaddr_in($port, $thataddr); +connect(S, $that) || &errexit("connect: $!\n"); + +select(S); $| = 1; select(STDOUT); + +$buffer = ''; +while (1) +{ + $rin = ''; + vec($rin, fileno(S), 1) = 1; + $nfound = select($rout=$rin, $wout=$rin, undef, undef); + if (vec($rout, fileno(S), 1)) { + print STDERR "$buffer\n" if + defined($nread = sysread(S, $buffer, 8192)); + } + if (vec($wout, fileno(S), 1)) { + $nread = read(STDIN, $buffer, 8192); + last if $nread == 0; + &errexit("write: $!\n") unless + defined($written = syswrite(S,$buffer,$nread)); + } +} +close(S); +exit 0; + +sub errexit +{ + print STDERR @_; + exit 2; +} diff --git a/contrib/p910nd-0.8/p910nd.8 b/contrib/p910nd-0.8/p910nd.8 new file mode 100644 index 0000000..24572c4 --- /dev/null +++ b/contrib/p910nd-0.8/p910nd.8 @@ -0,0 +1,93 @@ +.TH P910ND 8 "1 August 2004" +.SH NAME +p910nd \- port 9100+n printer daemon +.SH SYNOPSIS +.B p910nd +[\fB-f device\fR] +[\fB-i bindaddr\fR] +[\fB-bv\fR] +[\fB0|1|2\fR] +.SH DESCRIPTION +.I p910nd +is a small daemon that copies any data received on the port +it is listening on to the corresponding printer port. +It is primarily intended for diskless Linux hosts running as printer drivers +but there is no reason why it could not be used on diskful hosts. +Port 9100 is copied to /dev/lp0, 9101 to /dev/lp1 and 9102 to /dev/lp2. +The default is port 9100 to /dev/lp0. +.LP +The \fB-f\fR option can be used to specify a different printer device, +e.g. /dev/usblp0. +.LP +The \fB-i\fR option can be used to specify binding to one address instead +of all interfaces which is the default. +.LP +The \fB-b\fR option turns on bidirectional copying. +.LP +The \fB-v\fR option shows the version number. +.SH INSTALLATION +.I p910nd +can be run as a standalone daemon or from inetd. +It will automatically detect if it is running under inetd. +.LP +A sample SysVinit script, +.IR p910nd.sh , +is provided for operation as a daemon. +.I p910nd +will change its name under ps to match the printer port, i.e. +.I p9100d, p9101d +and +.IR p9102d . +.LP +When running under inetd, the +.I /etc/inetd.conf +entry should look something like this (with tcpwrappers protection): +.sp +.nf +p9101 stream tcp nowait root /usr/sbin/tcpd /sbin/p910nd +.fi +.sp +Don't forget to add an entry in +.I /etc/services +for the corresponding port. +.LP +If operating with lprng, use the host%port syntax for the +printer device to send jobs to it. +.LP +If operating with CUPS, this is supported as the AppSocket +protocol, also known as the JetDirect (probably TM) protocol. +.LP +If operating with classic Berkeley lpd, a sample client, +.IR client.pl , +is provided. +This should be installed as the ifilter (if=) in /etc/printcap. +.I banner.pl +should be installed as the ofilter (of=) in /etc/printcap. +It may be necessary to create a dummy spool file for lpd (lp=). +This file will be opened but not written to. +The corresponding C versions are left as an exercise for the reader. +.LP +When running under inetd, more than one instance could be started. +To avoid problems with multiple instances attempting to access the +printer at the same time, make sure that only one client is active +at any one time. This can be done by designating one host as the +spooler and sending all jobs to this host. You will probably +need to set up an intermediate queue anyway to provide print job filtering. +.LP +If compiled with USE_LIBWRAP and linked with -lwrap, it uses the libwrap +library (tcpwrappers). Access control can be done with /etc/hosts.allow +and /etc/hosts.deny. The service name is p910nd. +.SH DIAGNOSTICS +.I p910nd +logs error messages to syslog. +.SH "SEE ALSO" +printcap(5), hosts_access(5) +.SH FILES +/var/run/p9100d.pid, /var/lock/subsys/p9100d, /etc/hosts.allow, /etc/hosts.deny +.SH COPYRIGHT +.I p910nd +is under the GNU Public License +.SH AUTHOR +Ken Yap (ken_yap@users.sourceforge.net) +.SH DATE +Version 0.8 October 2004 diff --git a/contrib/p910nd-0.8/p910nd.c b/contrib/p910nd-0.8/p910nd.c new file mode 100644 index 0000000..c2473d8 --- /dev/null +++ b/contrib/p910nd-0.8/p910nd.c @@ -0,0 +1,420 @@ +/* + * Port 9100+n daemon + * Accepts a connection from port 9100+n and copy stream to + * /dev/lpn, where n = 0,1,2. + * + * Run standalone as: p910nd [0|1|2] + * + * Run under inetd as: + * p910n stream tcp nowait root /usr/sbin/tcpd p910nd [0|1|2] + * where p910n is an /etc/services entry for + * port 9100, 9101 or 9102 as the case may be. + * root can be replaced by any uid with rw permission on /dev/lpn + * + * Port 9100+n will then be passively opened + * n defaults to 0 + * + * Version 0.8 + * Allow specifying address to bind to + * + * Version 0.7 + * Bidirectional data transfer + * + * Version 0.6 + * Arne Bernin fixed some cast warnings, corrected the version number + * and added a -v option to print the version. + * + * Version 0.5 + * -DUSE_LIBWRAP and -lwrap enables hosts_access (tcpwrappers) checking. + * + * Version 0.4 + * Ken Yap (ken_yap@users.sourceforge.net), April 2001 + * Placed under GPL. + * + * Added -f switch to specify device which overrides /dev/lpn. + * But number is still required get distinct ports and locks. + * + * Added locking so that two invocations of the daemon under inetd + * don't try to open the printer at the same time. This can happen + * even if there is one host running clients because the previous + * client can exit after it has sent all data but the printer has not + * finished printing and inetd starts up a new daemon when the next + * request comes in too soon. + * + * Various things could be Linux specific. I don't + * think there is much demand for this program outside of PCs, + * but if you port it to other distributions or platforms, + * I'd be happy to receive your patches. + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <getopt.h> +#include <ctype.h> +#include <string.h> +#include <fcntl.h> +#include <netdb.h> +#include <syslog.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#ifdef USE_LIBWRAP +#include "tcpd.h" +int allow_severity, deny_severity; +extern int hosts_ctl(char *daemon, char *client_name, + char *client_addr, char *client_user); +#endif + +#define BASEPORT 9100 +#define PIDFILE "/var/run/p910%cd.pid" +#ifdef LOCKFILE_DIR +#define LOCKFILE LOCKFILE_DIR "/p910%cd" +#else +#define LOCKFILE "/var/lock/subsys/p910%cd" +#endif +#define PRINTERFILE "/dev/lp%c" +#define LOGOPTS LOG_ERR + +static char *progname; +static char version[] = "p910nd Version 0.8"; +static int lockfd = -1; +static char *device = 0; +static int bidir = 0; +static char *bindaddr = 0; + +void usage(void) +{ + fprintf(stderr, "Usage: %s [-f device] [-i bindaddr] [-bv] [0|1|2]\n", progname); + exit(1); +} + +void show_version (void) +{ + fprintf(stdout, "%s \n", version); +} + +FILE *open_printer(int lpnumber) +{ + FILE *f; + char lpname[sizeof(PRINTERFILE)]; + +#ifdef TESTING + (void)snprintf(lpname, sizeof(lpname), "/dev/tty"); +#else + (void)snprintf(lpname, sizeof(lpname), PRINTERFILE, lpnumber); +#endif + if (device == 0) + device = lpname; + if ((f = fopen(device, bidir ? "w+" : "w")) == NULL) + { + syslog(LOGOPTS, "%s: %m\n", device); + exit(1); + } + return (f); +} + +int get_lock(int lpnumber) +{ + char lockname[sizeof(LOCKFILE)]; + struct flock lplock; + + (void)snprintf(lockname, sizeof(lockname), LOCKFILE, lpnumber); + if ((lockfd = open(lockname, O_CREAT|O_RDWR)) < 0) + { + syslog(LOGOPTS, "%s: %m\n", lockname); + return (0); + } + memset(&lplock, 0, sizeof(lplock)); + lplock.l_type = F_WRLCK; + lplock.l_pid = getpid(); + if (fcntl(lockfd, F_SETLKW, &lplock) < 0) + { + syslog(LOGOPTS, "%s: %m\n", lockname); + return (0); + } + return (1); +} + +void free_lock(void) +{ + if (lockfd >= 0) + (void)close(lockfd); +} + +/* Copy network socket to FILE f until EOS */ +int copy_stream(int fd, FILE *f) +{ + int nread; + char buffer[8192]; + + if (bidir) { + FILE *nf; + + if ((nf = fdopen(fd, "w")) == NULL) { + syslog(LOGOPTS, "fdopen: %m\n"); + } + for (;;) { + fd_set readfds; + int result; + int maxfd = fileno(f) > fd ? fileno(f) : fd; + FD_ZERO(&readfds); + FD_SET(fileno(f), &readfds); + FD_SET(fd, &readfds); + result = select(maxfd + 1, &readfds, 0, 0, 0); + if (result < 0) + return (result); + if (result == 0) + continue; + if (FD_ISSET(fd, &readfds)) { + nread = read(fd, buffer, sizeof(buffer)); + if (nread <= 0) + break; + (void)fwrite(buffer, sizeof(char), nread, f); + } + if (FD_ISSET(fileno(f), &readfds)) { + nread = read(fileno(f), buffer, sizeof(buffer)); + if (nread > 0 && nf != NULL) { + (void)fwrite(buffer, sizeof(char), nread, nf); + (void)fflush(nf); + } + } + } + (void)fflush(f); + (void)fclose(nf); + return (0); + } else { + while ((nread = read(fd, buffer, sizeof(buffer))) > 0) + (void)fwrite(buffer, sizeof(char), nread, f); + (void)fflush(f); + return (nread); + } +} + +void one_job(int lpnumber) +{ + FILE *f; + struct sockaddr_in client; + socklen_t clientlen = sizeof(client); + + if (getpeername(0, (struct sockaddr*) &client, &clientlen) >= 0) + syslog(LOGOPTS, "Connection from %s port %hu\n", + inet_ntoa(client.sin_addr), + ntohs(client.sin_port)); + if (get_lock(lpnumber) == 0) + return; + f = open_printer(lpnumber); + if (copy_stream(0, f) < 0) + syslog(LOGOPTS, "copy_stream: %m\n"); + fclose(f); + free_lock(); +} + +void server(int lpnumber) +{ + struct rlimit resourcelimit; +#ifdef USE_GETPROTOBYNAME + struct protoent *proto; +#endif + int netfd, fd, one = 1; + socklen_t clientlen; + struct sockaddr_in netaddr, client; + char pidfilename[sizeof(PIDFILE)]; + FILE *f; + int ipret; + +#ifndef TESTING + switch (fork()) + { + case -1: + syslog(LOGOPTS, "fork: %m\n"); + exit (1); + case 0: /* child */ + break; + default: /* parent */ + exit(0); + } + /* Now in child process */ + resourcelimit.rlim_max = 0; + if (getrlimit(RLIMIT_NOFILE, &resourcelimit) < 0) + { + syslog(LOGOPTS, "getrlimit: %m\n"); + exit(1); + } + for (fd = 0; fd < resourcelimit.rlim_max; ++fd) + (void)close(fd); + if (setsid() < 0) + { + syslog(LOGOPTS, "setsid: %m\n"); + exit(1); + } + (void)chdir("/"); + (void)umask(022); + fd = open("/dev/null", O_RDWR); /* stdin */ + (void)dup(fd); /* stdout */ + (void)dup(fd); /* stderr */ + (void)snprintf(pidfilename, sizeof(pidfilename), PIDFILE, lpnumber); + if ((f = fopen(pidfilename, "w")) == NULL) + { + syslog(LOGOPTS, "%s: %m\n", pidfilename); + exit(1); + } + (void)fprintf(f, "%d\n", getpid()); + (void)fclose(f); + if (get_lock(lpnumber) == 0) + exit(1); +#endif + f = open_printer(lpnumber); +#ifdef USE_GETPROTOBYNAME + if ((proto = getprotobyname("tcp")) == NULL) + { + syslog(LOGOPTS, "Cannot find protocol for TCP!\n"); + exit(1); + } + if ((netfd = socket(AF_INET, SOCK_STREAM, proto->p_proto)) < 0) +#else + if ((netfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0) +#endif + { + syslog(LOGOPTS, "socket: %m\n"); + exit(1); + } + if (setsockopt(netfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) + { + syslog(LOGOPTS, "setsocketopt: %m\n"); + exit(1); + } + netaddr.sin_port = htons(BASEPORT + lpnumber - '0'); + if (bindaddr == 0) { + netaddr.sin_addr.s_addr = htonl(INADDR_ANY); + } else { + ipret = inet_pton(AF_INET, bindaddr, &netaddr.sin_addr.s_addr); + if (ipret < 0) { + syslog(LOGOPTS, "inet_pton: %m\n"); + exit(1); + } else if (ipret == 0) { + syslog(LOGOPTS, "inet_pton: invalid bind IP address\n"); + exit(1); + } + } + memset(netaddr.sin_zero, 0, sizeof(netaddr.sin_zero)); + if (bind(netfd, (struct sockaddr*) &netaddr, sizeof(netaddr)) < 0) + { + syslog(LOGOPTS, "bind: %m\n"); + exit(1); + } + if (listen(netfd, 5) < 0) + { + syslog(LOGOPTS, "listen: %m\n"); + exit(1); + } + clientlen = sizeof(client); + memset(&client, 0, sizeof(client)); + while ((fd = accept(netfd, (struct sockaddr*) &client, &clientlen)) >= 0) + { +#ifdef USE_LIBWRAP + if (hosts_ctl("p910nd", STRING_UNKNOWN, + inet_ntoa(client.sin_addr), STRING_UNKNOWN) == 0) { + syslog(LOGOPTS, "Connection from %s port %hd rejected\n", + inet_ntoa(client.sin_addr), + ntohs(client.sin_port)); + close(fd); + continue; + } +#endif + syslog(LOGOPTS, "Connection from %s port %hd accepted\n", + inet_ntoa(client.sin_addr), + ntohs(client.sin_port)); + /*write(fd, "Printing", 8);*/ + if (copy_stream(fd, f) < 0) + syslog(LOGOPTS, "copy_stream: %m\n"); + (void)close(fd); + } + syslog(LOGOPTS, "accept: %m\n"); + free_lock(); + exit(1); +} + +int is_standalone(void) +{ + struct sockaddr_in bind_addr; + socklen_t ba_len; + + /* + * Check to see if a socket was passed to us from inetd. + * + * Use getsockname() to determine if descriptor 0 is indeed a socket + * (and thus we are probably a child of inetd) or if it is instead + * something else and we are running standalone. + */ + ba_len = sizeof(bind_addr); + if (getsockname(0, (struct sockaddr*) &bind_addr, &ba_len) == 0) + return (0); /* under inetd */ + if (errno != ENOTSOCK) /* strange... */ + syslog(LOGOPTS, "getsockname: %m\n"); + return (1); +} + +int main(int argc, char *argv[]) +{ + int c, lpnumber; + char *p; + + if (argc <= 0) /* in case not provided in inetd.conf */ + progname = "p910nd"; + else + { + progname = argv[0]; + if ((p = strrchr(progname, '/')) != 0) + progname = p + 1; + } + lpnumber = '0'; + while ((c = getopt(argc, argv, "bi:f:v")) != EOF) + { + switch (c) + { + case 'b': + bidir = 1; + break; + case 'f': + device = optarg; + break; + case 'i': + bindaddr = optarg; + break; + case 'v': + show_version(); + break; + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + if (argc > 0) + { + if (isdigit(argv[0][0])) + lpnumber = argv[0][0]; + } + /* change the n in argv[0] to match the port so ps will show that */ + if ((p = strstr(progname, "p910n")) != NULL) + p[4] = lpnumber; + + /* We used to pass (LOG_PERROR|LOG_PID|LOG_LPR|LOG_ERR) to syslog, but + * syslog ignored the LOG_PID and LOG_PERROR option. I.e. the intention + * was to add both options but the effect was to have neither. + * I disagree with the intention to add PERROR. --Stef */ + openlog (p, LOG_PID, LOG_LPR); + if (is_standalone()) + server(lpnumber); + else + one_job(lpnumber); + return (0); +} diff --git a/contrib/p910nd-0.8/p910nd.sh b/contrib/p910nd-0.8/p910nd.sh new file mode 100755 index 0000000..291a836 --- /dev/null +++ b/contrib/p910nd-0.8/p910nd.sh @@ -0,0 +1,39 @@ +#!/bin/sh +# +# p910nd.sh This shell script takes care of starting and stopping +# p910nd (port 9100+n printer daemon) +# This script only controls the one on port 9101. +# You can start others if you wish. +# + +# Todo: Make it fully LSB + +# See how we were called. +case "$1" in + start) + # Start daemons. + echo -n "Starting p910nd: " + # default port is 1 so it will appear as p9101d on a ps + start_daemon p910nd + echo + ;; + stop) + # Stop daemons. + echo -n "Shutting down p910nd: " + killproc p9101d + echo + rm -f /var/run/p9101.pid + ;; + status) + status p9101d + ;; + restart) + $0 stop + $0 start + ;; + *) + echo "Usage: p910nd {start|stop|restart|status}" + exit 1 +esac + +exit 0 diff --git a/contrib/ppmtoansi/Makefile b/contrib/ppmtoansi/Makefile new file mode 100644 index 0000000..bc0ca0a --- /dev/null +++ b/contrib/ppmtoansi/Makefile @@ -0,0 +1,67 @@ +CPPFLAGS = +LDLIBS = +CFLAGS = -pipe -g -O2 -Wall +LDFLAGS = -pipe +CC = gcc +LD = gcc +# Some "black" magic to determine optimal compiler flags for target +# architecture +TARGET_ARCH:= $(shell if [ \! -r .compile-options ] ; then ( \ + cpu=`grep cpu /proc/cpuinfo 2>&1 |head -1| \ + cut -d : -f 2-| sed -e 's/ //g'`; \ + if [ x"$$cpu" = x"" ] ; then \ + echo -fno-strength-reduce; \ + else if [ "$$cpu" = "386" ] ; then \ + echo -m386 -fno-strength-reduce; \ + else if [ "$$cpu" = "486" ] ; then \ + echo -m486 -fno-strength-reduce; \ + else if [ "$$cpu" = "Alpha" ] ; then \ + echo -fno-strength-reduce; \ + else echo main\(\)\{\} >.compile-options.c; \ + if gcc -mpentium -o .compile-options.o -c \ + .compile-options.c &>/dev/null; then \ + echo -mpentium -fstrength-reduce; \ + else if gcc -m486 -malign-functions=2 -malign-jumps=2 \ + -malign-loops=2 -o .compile-options.o -c \ + .compile-options.c &>/dev/null; then \ + echo -n -m486 -malign-functions=2 -malign-jumps=2; \ + echo ' '-malign-loops=2 -fno-strength-reduce; \ + else echo -m486; \ + fi;fi;fi;fi;fi;fi) > .compile-options; \ + rm -f .compile-options.c .compile-options.o; \ + fi; cat .compile-options) +ASFLAGS = $(TARGET_ARCH) + +OBJS = ppmtoansi.o + +############################################################################## + +ifeq (.depend,$(wildcard .depend)) +all: ppmtoansi +include .depend +else +all: depend + @$(MAKE) all +endif + +############################################################################## + +ppmtoansi: $(OBJS) + +############################################################################## + +clean: + $(RM) *~ *.o *.dvi *.log *.aux *yacc.tab.[ch] *yacc.output *lex.[co] \ + *.dat .depend .tmp_depend .compile-options* + strip ppmtoansi >&/dev/null || true + +distclean: clean + $(RM) -rf ppmtoansi + +############################################################################## + +depend: + for i in *.c;do $(CPP) $(CPPFLAGS) -MM $$i;done >.tmp_depend + mv .tmp_depend .depend + +############################################################################## diff --git a/contrib/ppmtoansi/demo/dos.ansi b/contrib/ppmtoansi/demo/dos.ansi new file mode 100644 index 0000000..2ce5cda --- /dev/null +++ b/contrib/ppmtoansi/demo/dos.ansi @@ -0,0 +1 @@ +[9;;1- [15;;1- [18;;5-Ûl[9;1;3-$€[13;1;3-$€[17;1;1-À[9;2;1- [12;2;1- [15;2;1- [17;2;1-À[9;3;1- [15;3;1- [18;3;5-Ûl[9;4;1- [15;4;1- [23;4;1-À[9;5;1- [15;5;1- [23;5;1-À[9;6;1- [15;6;1- [18;6;5-Ûl[8;8;4-I [14;8;4-m°[19;8;5-¶Ú[8;9;1-@[12;9;2-L[18;9;2-¬[8;10;1-@[11;10;1-`[13;10;1-@[18;10;1- [20;10;1-`[8;11;1-@[11;11;1-`[13;11;1-@[19;11;5-¶Ú[8;12;1-@[11;12;1-`[13;12;1-@[20;12;1-`[24;12;1- [8;13;1-@[12;13;2-L[18;13;2-l[24;13;1- [8;14;4-I [14;14;4-m°[19;14;5-¶Ú
\ No newline at end of file diff --git a/contrib/ppmtoansi/demo/dos.ppm b/contrib/ppmtoansi/demo/dos.ppm new file mode 100644 index 0000000..6efde7f --- /dev/null +++ b/contrib/ppmtoansi/demo/dos.ppm @@ -0,0 +1,51 @@ +P3 +17 16 +65535 +0 0 0 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 0 0 0 0 0 0 0 0 0 65535 65535 0 65535 65535 +0 65535 65535 0 65535 65535 0 65535 65535 0 0 0 0 0 0 +0 0 0 65535 0 0 65535 0 0 65535 0 0 0 0 0 65535 0 0 +65535 0 0 65535 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 0 0 0 0 0 0 0 0 65535 0 0 0 0 0 +0 0 0 65535 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 0 0 0 0 0 0 0 0 0 65535 65535 0 65535 65535 +0 65535 65535 0 65535 65535 0 65535 65535 0 0 0 0 0 0 +0 0 0 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 65535 65535 0 0 0 +0 0 0 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 65535 65535 0 0 0 +0 0 0 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 0 0 0 0 0 0 0 0 0 65535 65535 0 65535 65535 +0 65535 65535 0 65535 65535 0 65535 65535 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 0 0 0 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 0 0 0 65535 0 65535 +65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 0 0 0 +0 65535 0 0 0 0 0 0 0 0 0 0 0 65535 0 65535 65535 0 +0 0 0 0 0 0 0 0 0 0 0 0 65535 0 65535 65535 65535 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 65535 0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 65535 0 +0 0 0 0 0 0 0 0 0 0 0 0 65535 0 65535 0 0 0 +65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 65535 0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 65535 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 65535 +65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 0 0 0 +0 65535 0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 65535 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +65535 65535 0 0 0 0 0 0 0 0 0 0 65535 0 65535 +0 65535 0 0 0 0 0 0 0 0 0 0 0 65535 0 65535 65535 0 +0 0 0 0 0 0 0 0 0 0 0 0 65535 65535 0 65535 65535 0 +0 0 0 0 0 0 0 0 0 0 0 0 65535 0 65535 +0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 0 0 0 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 0 0 0 65535 0 65535 +65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/contrib/ppmtoansi/demo/dos.xpm b/contrib/ppmtoansi/demo/dos.xpm new file mode 100644 index 0000000..471c4ed --- /dev/null +++ b/contrib/ppmtoansi/demo/dos.xpm @@ -0,0 +1,29 @@ +/* XPM */ +static char *noname[] = { +/* width height ncolors chars_per_pixel */ +"17 16 6 1", +/* colors */ +"` c #000000", +"a c #00FFFF", +"b c #00FF00", +"c c #FF00FF", +"d c #FF0000", +"e c #FFFF00", +/* pixels */ +"`d`````d``aaaaa``", +"`ddd`ddd`a```````", +"`d``d``d`a```````", +"`d`````d``aaaaa``", +"`d`````d```````a`", +"`d`````d```````a`", +"`d`````d``aaaaa``", +"`````````````````", +"bbbb``eeee`ccccc`", +"b```be````ce`````", +"b``e`b````c`e````", +"b``e`b`````ccccc`", +"b``e`b``````e```c", +"b```be````ee````c", +"bbbb``eeee`ccccc`", +"`````````````````" +}; diff --git a/contrib/ppmtoansi/demo/etherboot.ansi b/contrib/ppmtoansi/demo/etherboot.ansi Binary files differnew file mode 100644 index 0000000..7975f36 --- /dev/null +++ b/contrib/ppmtoansi/demo/etherboot.ansi diff --git a/contrib/ppmtoansi/demo/etherboot.ppm b/contrib/ppmtoansi/demo/etherboot.ppm new file mode 100644 index 0000000..da5b245 --- /dev/null +++ b/contrib/ppmtoansi/demo/etherboot.ppm @@ -0,0 +1,99 @@ +P3 +32 16 +65535 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 +65535 0 0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 +0 65535 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 +0 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 0 +0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 0 +0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 0 0 0 0 +0 0 0 65535 0 0 +65535 0 0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 +0 65535 0 0 0 0 0 65535 0 0 0 0 0 0 0 0 65535 0 +0 0 0 0 65535 0 0 0 0 0 0 0 0 65535 0 0 0 0 +0 0 0 0 0 0 0 65535 0 0 0 0 0 0 0 0 0 0 +0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 0 0 0 0 +0 0 0 65535 0 0 +65535 0 0 0 0 0 0 0 0 0 65535 0 0 0 0 0 0 0 +0 65535 0 0 0 0 0 65535 0 0 0 0 0 0 0 0 65535 0 +0 0 0 0 65535 0 0 0 0 0 0 0 0 65535 0 0 0 0 +0 0 0 0 0 0 0 65535 0 0 0 0 0 0 0 0 0 0 +0 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 0 0 +0 0 0 65535 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 +0 65535 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 +0 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 0 +0 0 0 0 0 0 0 65535 0 0 0 0 0 0 0 0 0 0 +0 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 0 0 +0 0 0 0 0 0 65535 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 0 0 +0 0 0 65535 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 +0 65535 0 0 65535 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 +0 65535 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 +0 65535 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 0 0 +65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 +0 0 0 0 0 0 0 0 0 0 65535 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 0 0 +0 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 0 0 +65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 +0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 0 0 +0 0 0 0 0 0 0 65535 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 0 0 +65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 +0 0 0 0 0 0 0 0 0 0 65535 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 0 0 +0 0 0 0 0 0 0 65535 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 65535 65535 +0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 diff --git a/contrib/ppmtoansi/demo/etherboot.xpm b/contrib/ppmtoansi/demo/etherboot.xpm new file mode 100644 index 0000000..d421714 --- /dev/null +++ b/contrib/ppmtoansi/demo/etherboot.xpm @@ -0,0 +1,27 @@ +/* XPM */ +static char *noname[] = { +/* width height ncolors chars_per_pixel */ +"32 16 4 1", +/* colors */ +"` c #000000", +"a c #00FFFF", +"b c #00FF00", +"c c #FF0000", +/* pixels */ +"``a``a``a``a``a``a``a``a``a``a``", +"``a``a``a``a``a``a``a``a``a``a``", +"cccccccccccccccccccccccccccccccc", +"c``bbbb`bbbb`bbbb`bbbbb`bbbb```c", +"c``bbbb`b``b`b``b```b```bbbb```c", +"c``b``b`b``b`b``b```b```b``````c", +"`c`bbbb`bbbb`bbbb```b```b``````c", +"``c````````````````````````````c", +"`c`bbbbb`bbbb`bbbbb`bbbb```````c", +"c````b```b``````b```bbbb```````c", +"c````b```bbb````b```b``````````c", +"c````b```b``````b```b``````````c", +"cccccccccccccccccccccccccccccccc", +"``a``a``a``a``a``a``a``a``a``a``", +"``a``a``a``a``a``a``a``a``a``a``", +"````````````````````````````````" +}; diff --git a/contrib/ppmtoansi/demo/flash.ansi b/contrib/ppmtoansi/demo/flash.ansi new file mode 100644 index 0000000..43837a7 --- /dev/null +++ b/contrib/ppmtoansi/demo/flash.ansi @@ -0,0 +1 @@ +[11;;2-l[11;1;2-l[17;1;1-`[11;2;2-l[16;2;2-l[11;3;2-l[15;3;3-m€[11;4;2-l[14;4;4-m°[11;5;2-l[14;5;4-m°[11;6;4-m°[16;6;2-l[11;7;4-m°[16;7;2-l[11;8;3-m€[16;8;2-l[11;9;2-l[16;9;2-l[11;10;1-`[16;10;2-l[16;11;2-l[13;12;2-l[16;12;2-l[19;12;2-l[14;13;6-m¶À[15;14;4-m°[16;15;2-l
\ No newline at end of file diff --git a/contrib/ppmtoansi/demo/flash.ppm b/contrib/ppmtoansi/demo/flash.ppm new file mode 100644 index 0000000..1464af6 --- /dev/null +++ b/contrib/ppmtoansi/demo/flash.ppm @@ -0,0 +1,35 @@ +P3 +10 16 +65535 +65535 65535 0 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +65535 65535 0 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 +65535 65535 0 0 0 0 0 0 0 0 0 0 +65535 65535 0 65535 65535 0 0 0 0 0 0 0 0 0 0 65535 65535 0 +65535 65535 0 0 0 0 0 0 0 0 0 0 +65535 65535 0 65535 65535 0 0 0 0 0 0 0 65535 65535 0 65535 65535 0 +65535 65535 0 0 0 0 0 0 0 0 0 0 +65535 65535 0 65535 65535 0 0 0 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 0 0 0 0 0 0 0 0 0 +65535 65535 0 65535 65535 0 0 0 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 0 0 0 0 0 0 0 0 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 0 0 0 65535 65535 0 +65535 65535 0 0 0 0 0 0 0 0 0 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 0 0 0 65535 65535 0 +65535 65535 0 0 0 0 0 0 0 0 0 0 +65535 65535 0 65535 65535 0 65535 65535 0 0 0 0 0 0 0 65535 65535 0 +65535 65535 0 0 0 0 0 0 0 0 0 0 +65535 65535 0 65535 65535 0 0 0 0 0 0 0 0 0 0 65535 65535 0 +65535 65535 0 0 0 0 0 0 0 0 0 0 +65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 65535 0 +65535 65535 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 65535 0 +65535 65535 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 65535 65535 0 65535 65535 0 0 0 0 65535 65535 0 +65535 65535 0 0 0 0 65535 65535 0 65535 65535 0 +0 0 0 0 0 0 0 0 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 65535 0 +65535 65535 0 0 0 0 0 0 0 0 0 0 diff --git a/contrib/ppmtoansi/demo/flash.xpm b/contrib/ppmtoansi/demo/flash.xpm new file mode 100644 index 0000000..25419d7 --- /dev/null +++ b/contrib/ppmtoansi/demo/flash.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char *noname[] = { +/* width height ncolors chars_per_pixel */ +"10 16 2 1", +/* colors */ +" c #000000", +"x c #FFFF00", +/* pixels */ +"xx ", +"xx x ", +"xx xx ", +"xx xxx ", +"xx xxxx ", +"xx xxxx ", +"xxxx xx ", +"xxxx xx ", +"xxx xx ", +"xx xx ", +"x xx ", +" xx ", +" xx xx xx", +" xxxxxx ", +" xxxx ", +" xx ", +}; diff --git a/contrib/ppmtoansi/demo/floppy.ansi b/contrib/ppmtoansi/demo/floppy.ansi new file mode 100644 index 0000000..f4267f4 --- /dev/null +++ b/contrib/ppmtoansi/demo/floppy.ansi @@ -0,0 +1 @@ +[9;;14-%’Ûm¶@[8;1;16-$²[l’É[8;2;17-$²[l’É [8;3;17-$²[l’É [8;4;17-$¶Ûm¶É [8;5;17;1+[8;6;17;1+[8;7;17-$í¶Ûm‰ [8;8;17-$ëm¶Û‰ [8;9;17-$í¶Ûm‰ [8;10;17-$ëm¶Û‰ [8;11;17-$í¶Ûm‰ [8;12;17-$ëm¶Û‰ [8;13;17-2m¶Ûm¤ [8;14;17-2km¶Û¤ [9;15;15-'m¶ÛlH
\ No newline at end of file diff --git a/contrib/ppmtoansi/demo/floppy.ppm b/contrib/ppmtoansi/demo/floppy.ppm new file mode 100644 index 0000000..2b0b286 --- /dev/null +++ b/contrib/ppmtoansi/demo/floppy.ppm @@ -0,0 +1,51 @@ +P3 +17 16 +65535 +0 0 0 65535 0 0 65535 0 0 65535 65535 0 65535 0 0 65535 0 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 0 0 0 0 0 0 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 65535 0 65535 0 0 65535 0 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 0 0 65535 0 0 +65535 0 0 65535 65535 0 65535 0 0 65535 0 0 0 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 65535 0 65535 0 0 65535 0 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 0 0 65535 0 0 +65535 0 0 65535 65535 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 65535 0 65535 0 0 65535 0 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 0 0 65535 0 0 +65535 0 0 65535 65535 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 0 65535 65535 0 65535 65535 0 65535 65535 +0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 +0 65535 65535 0 65535 65535 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 0 65535 65535 65535 0 65535 65535 0 65535 +65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 +65535 0 65535 0 65535 65535 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 0 65535 65535 0 65535 65535 0 65535 65535 +0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 +0 65535 65535 0 65535 65535 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 0 65535 65535 65535 0 65535 65535 0 65535 +65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 +65535 0 65535 0 65535 65535 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 0 65535 65535 0 65535 65535 0 65535 65535 +0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 +0 65535 65535 0 65535 65535 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 0 65535 65535 65535 0 65535 65535 0 65535 +65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 +65535 0 65535 0 65535 65535 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 0 0 65535 0 0 65535 0 65535 65535 0 65535 65535 0 65535 65535 +0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 +0 65535 65535 0 65535 65535 0 0 65535 0 0 65535 65535 0 0 +65535 0 0 0 0 65535 0 0 65535 0 65535 65535 65535 0 65535 65535 0 65535 +65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 +65535 0 65535 0 65535 65535 0 0 65535 0 0 65535 65535 0 0 +0 0 0 65535 0 0 65535 0 0 0 65535 65535 0 65535 65535 0 65535 65535 +0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 +0 65535 65535 0 65535 65535 65535 0 0 65535 0 0 0 0 0 diff --git a/contrib/ppmtoansi/demo/floppy.xpm b/contrib/ppmtoansi/demo/floppy.xpm new file mode 100644 index 0000000..8bb60d2 --- /dev/null +++ b/contrib/ppmtoansi/demo/floppy.xpm @@ -0,0 +1,29 @@ +/* XPM */ +static char *noname[] = { +/* width height ncolors chars_per_pixel */ +"17 16 6 1", +/* colors */ +"` c #000000", +"a c #00FFFF", +"b c #FF00FF", +"c c #FF0000", +"d c #FFFF00", +"e c #0000FF", +/* pixels */ +"`ccdccddddddddc``", +"cccdccddddcccdcc`", +"cccdccddddcccdccc", +"cccdccddddcccdccc", +"cccdddddddddddccc", +"ccccccccccccccccc", +"ccccccccccccccccc", +"cccaaaaaaaaaaaccc", +"cccabbbbbbbbbaccc", +"cccaaaaaaaaaaaccc", +"cccabbbbbbbbbaccc", +"cccaaaaaaaaaaaccc", +"cccabbbbbbbbbaccc", +"ceeaaaaaaaaaaaeec", +"ceeabbbbbbbbbaeec", +"`ccaaaaaaaaaaacc`" +}; diff --git a/contrib/ppmtoansi/demo/hd.ansi b/contrib/ppmtoansi/demo/hd.ansi Binary files differnew file mode 100644 index 0000000..33bda53 --- /dev/null +++ b/contrib/ppmtoansi/demo/hd.ansi diff --git a/contrib/ppmtoansi/demo/hd.ppm b/contrib/ppmtoansi/demo/hd.ppm new file mode 100644 index 0000000..34878bf --- /dev/null +++ b/contrib/ppmtoansi/demo/hd.ppm @@ -0,0 +1,51 @@ +P3 +17 16 +65535 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +65535 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 +0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 +65535 0 0 65535 0 0 65535 0 0 0 0 0 0 0 0 +65535 0 0 0 65535 0 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 +0 65535 0 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 0 65535 0 +65535 0 0 65535 65535 0 65535 65535 0 65535 0 0 0 0 0 +65535 0 0 0 65535 0 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 +0 65535 0 65535 0 65535 0 65535 0 0 65535 0 0 65535 0 0 65535 0 +65535 0 0 65535 65535 0 65535 65535 0 65535 0 0 0 0 0 +65535 0 0 0 65535 0 65535 0 65535 0 65535 0 0 65535 0 0 65535 0 +0 65535 0 65535 0 65535 0 65535 0 0 65535 0 0 65535 0 0 65535 0 +65535 0 0 65535 65535 0 65535 65535 0 65535 0 0 0 0 0 +65535 0 0 0 65535 0 65535 0 65535 0 65535 0 0 65535 0 0 65535 0 +0 65535 0 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 0 65535 0 +65535 0 0 65535 65535 0 65535 0 0 0 0 0 0 0 0 +65535 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 +0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 +65535 0 0 65535 0 0 0 0 65535 0 0 65535 0 0 65535 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 0 65535 65535 0 65535 65535 0 0 65535 0 0 65535 +0 0 0 0 0 65535 0 65535 65535 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 65535 65535 +0 65535 65535 0 65535 65535 0 0 65535 0 65535 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 65535 65535 0 65535 65535 0 0 65535 +0 0 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 +0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 +0 65535 65535 0 0 65535 0 65535 65535 0 65535 65535 0 0 65535 +0 0 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 +0 65535 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 65535 65535 0 0 65535 0 65535 65535 0 0 65535 0 0 0 +0 0 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 +0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 +0 65535 65535 0 0 65535 0 0 65535 0 0 0 0 0 0 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/contrib/ppmtoansi/demo/hd.xpm b/contrib/ppmtoansi/demo/hd.xpm new file mode 100644 index 0000000..280c7ab --- /dev/null +++ b/contrib/ppmtoansi/demo/hd.xpm @@ -0,0 +1,30 @@ +/* XPM */ +static char *noname[] = { +/* width height ncolors chars_per_pixel */ +"17 16 7 1", +/* colors */ +"` c #000000", +"a c #00FFFF", +"b c #00FF00", +"c c #FF00FF", +"d c #FF0000", +"e c #FFFF00", +"f c #0000FF", +/* pixels */ +"`````````````````", +"ddddddddddddd````", +"dbbbbbbbbbbbddd``", +"dbccccbccccbdeed`", +"dbccccbcbbbbdeed`", +"dbcbbbbcbbbbdeed`", +"dbcbbbbccccbded``", +"dbbbbbbbbbbbddfff", +"dddddddddddddaaff", +"`faddddddddaaafaf", +"ffffffffffffffaaf", +"faaaaaaaaaaaafaaf", +"faaaaaafffffafaf`", +"faaaaaaaaaaaaff``", +"ffffffffffffff```", +"`````````````````" +}; diff --git a/contrib/ppmtoansi/demo/ibmmap.ppm b/contrib/ppmtoansi/demo/ibmmap.ppm new file mode 100644 index 0000000..648676e --- /dev/null +++ b/contrib/ppmtoansi/demo/ibmmap.ppm @@ -0,0 +1,11 @@ +P3 +8 1 +255 + 0 0 0 +255 0 0 + 0 255 0 + 0 0 255 +255 255 0 +255 0 255 + 0 255 255 +255 255 255 diff --git a/contrib/ppmtoansi/demo/ibmmap.xpm b/contrib/ppmtoansi/demo/ibmmap.xpm new file mode 100644 index 0000000..06d4d99 --- /dev/null +++ b/contrib/ppmtoansi/demo/ibmmap.xpm @@ -0,0 +1,16 @@ +/* XPM */ +static char *noname[] = { +/* width height ncolors chars_per_pixel */ +"8 1 8 1", +/* colors */ +"` c #000000", +"a c #00FFFF", +"b c #00FF00", +"c c #FF00FF", +"d c #FF0000", +"e c #FFFFFF", +"f c #FFFF00", +"g c #0000FF", +/* pixels */ +"`dbgfcae" +}; diff --git a/contrib/ppmtoansi/demo/linux-logo.ansi b/contrib/ppmtoansi/demo/linux-logo.ansi Binary files differnew file mode 100644 index 0000000..165f834 --- /dev/null +++ b/contrib/ppmtoansi/demo/linux-logo.ansi diff --git a/contrib/ppmtoansi/demo/linux-logo.ppm b/contrib/ppmtoansi/demo/linux-logo.ppm new file mode 100644 index 0000000..18604b4 --- /dev/null +++ b/contrib/ppmtoansi/demo/linux-logo.ppm @@ -0,0 +1,552 @@ +P3 +52 61 +65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 65535 65535 65535 65535 65535 65535 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 0 0 0 0 0 0 +0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +65535 65535 65535 0 0 0 0 0 0 65535 65535 65535 0 0 0 0 0 0 +0 0 0 65535 65535 65535 65535 65535 65535 0 0 0 0 0 0 65535 65535 65535 +65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 +65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 +65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 65535 65535 65535 0 0 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 0 0 0 0 0 65535 65535 65535 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 65535 0 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 0 0 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 0 0 65535 65535 0 65535 65535 0 65535 65535 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 65535 65535 65535 65535 0 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 0 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 65535 +65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 65535 65535 65535 65535 65535 65535 65535 0 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 0 0 65535 65535 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 0 0 65535 0 0 +65535 65535 0 65535 65535 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 0 0 0 +0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 0 0 0 0 0 0 0 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 0 0 0 0 0 0 0 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 0 0 0 0 0 0 0 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 0 0 0 0 0 0 0 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 0 0 0 0 0 0 0 0 0 0 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 0 0 0 0 0 0 0 0 0 0 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 0 0 0 0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 0 0 0 0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 0 0 0 +0 0 0 0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 0 0 0 +0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 0 0 0 0 0 0 0 +0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 0 0 0 0 0 0 0 +0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 0 0 0 0 0 0 0 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 0 0 0 0 0 0 0 0 0 0 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 0 0 0 0 65535 65535 0 0 0 0 0 0 0 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 0 0 0 +0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 0 +65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +0 0 0 0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 65535 65535 0 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 0 0 0 0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 0 65535 65535 0 +65535 65535 0 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 65535 65535 0 65535 65535 0 65535 0 0 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 0 0 0 0 0 0 0 0 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 0 65535 65535 0 +65535 65535 0 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 0 0 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 65535 0 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 0 0 0 0 0 0 0 0 0 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 0 0 65535 0 0 0 0 0 65535 0 0 +65535 0 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +65535 0 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 0 0 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +65535 0 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +65535 0 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 0 0 0 0 0 0 +0 0 0 0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 0 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 0 0 0 0 65535 0 0 65535 +0 0 65535 65535 0 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 0 0 0 +0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 0 0 0 0 0 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 0 0 65535 +0 0 65535 65535 0 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 0 0 0 0 0 0 65535 0 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 0 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 0 0 0 0 0 0 0 0 0 65535 0 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 0 0 65535 +65535 0 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 0 0 0 0 65535 0 0 65535 +0 0 65535 65535 0 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 0 0 0 0 0 0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 65535 0 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 0 0 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 65535 0 0 65535 0 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 0 0 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 65535 0 65535 65535 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 0 0 +0 0 65535 0 0 65535 0 0 65535 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 65535 0 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 0 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 65535 0 0 +65535 0 0 65535 0 0 65535 65535 0 65535 0 0 65535 0 0 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 65535 0 0 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 65535 diff --git a/contrib/ppmtoansi/demo/linux-logo.xpm b/contrib/ppmtoansi/demo/linux-logo.xpm new file mode 100644 index 0000000..fd2dd67 --- /dev/null +++ b/contrib/ppmtoansi/demo/linux-logo.xpm @@ -0,0 +1,73 @@ +/* XPM */ +static char *noname[] = { +/* width height ncolors chars_per_pixel */ +"52 61 5 1", +/* colors */ +"` c #000000", +"a c #FF0000", +"b c #FFFFFF", +"c c #FFFF00", +"d c #0000FF", +/* pixels */ +"dddddddddddddddddddddd```````ddddddddddddddddddddddd", +"dddddddddddddddddddd```````````ddddddddddddddddddddd", +"ddddddddddddddddddd`````````````dddddddddddddddddddd", +"dddddddddddddddddd```````````````ddddddddddddddddddd", +"ddddddddddddddddd`````````````````dddddddddddddddddd", +"ddddddddddddddddd`````````````````dddddddddddddddddd", +"ddddddddddddddddd``````````````````ddddddddddddddddd", +"ddddddddddddddddd``````````````````ddddddddddddddddd", +"ddddddddddddddddd``````````````````ddddddddddddddddd", +"ddddddddddddddddd``bb`````bbbb`````ddddddddddddddddd", +"ddddddddddddddddd``bbb```bbbbb`````ddddddddddddddddd", +"ddddddddddddddddd`b``b```bb``bb````ddddddddddddddddd", +"ddddddddddddddddd`b``````b````b````ddddddddddddddddd", +"ddddddddddddddddd`````cccc````b````ddddddddddddddddd", +"ddddddddddddddddd``b`cccccca`b``````dddddddddddddddd", +"ddddddddddddddddd``acccccccccc``````dddddddddddddddd", +"ddddddddddddddddd``cccccccccccc`````dddddddddddddddd", +"ddddddddddddddddd``ccccccccccca`````dddddddddddddddd", +"ddddddddddddddddd```ccccccaccc``````dddddddddddddddd", +"ddddddddddddddddd``bacccaccccbb``````ddddddddddddddd", +"ddddddddddddddddd``bbacccacbbbb```````dddddddddddddd", +"ddddddddddddddddd``bbbaaccbbbbbb``````dddddddddddddd", +"dddddddddddddddd```bbbbbbbbbbbbb```````ddddddddddddd", +"ddddddddddddddd```bbbbbbbbbbbbbbb``````ddddddddddddd", +"dddddddddddddd```bbbbbbbbbbbbbbbb```````dddddddddddd", +"dddddddddddddd```bbbbbbbbbbbbbbbbb```````ddddddddddd", +"ddddddddddddd```bbbbbbbbbbbbbbbbbb````````dddddddddd", +"dddddddddddd````bbbbbbbbbbbbbbbbbb````````dddddddddd", +"dddddddddddd````bbbbbbbbbbbbbbbbbbb````````ddddddddd", +"ddddddddddd````bbbbbbbbbbbbbbbbbbbb`````````dddddddd", +"ddddddddddd````bbbbbbbbbbbbbbbbbbbbb````````dddddddd", +"ddddddddddd```bbbbbbbbbbbbbbbbbbbbbb````````dddddddd", +"dddddddddd````bbbbbbbbbbbbbbbbbbbbbbb````````ddddddd", +"dddddddddd```bbbbbbbbbbbbbbbbbbbbbbbb````````ddddddd", +"ddddddddd````bbbbbbbbbbbbbbbbbbbbbbbb````````ddddddd", +"ddddddddd````bbbbbbbbbbbbbbbbbbbbbbbb`````````dddddd", +"ddddddddd```bbbbbbbbbbbbbbbbbbbbbbbbb`````````dddddd", +"dddddddd````bbbbbbbbbbbbbbbbbbbbbbbbb`````````dddddd", +"ddddddd`````bbbbbbbbbbbbbbbbbbbbbbbbb`````````dddddd", +"ddddddd`````bbbbbbbbbbbbbbbbbbbbbbbbb`````````dddddd", +"ddddddd`````bbbbbbbbbbbbbbbbbbbbbbbbb`````````dddddd", +"ddddddd``c``bbbbbbbbbbbbbbbbbbbbbbbbb`````````dddddd", +"dddddddcccc``bbbbbbbbbbbbbbbbbbbbbbcc`````````dddddd", +"dddddddccccc``bbbbbbbbbbbbbbbbbbbbcccc```````cdddddd", +"ddddddccccccc``bbbbbbbbbbbbbbbbbbbccca``````ccaddddd", +"dddddcccccccca``bbbbbbbbbbbbbbbbbbccca`````cccaddddd", +"dacccccccccccc```bbbbbbbbbbbbbbbbbccccaa`aaccccddddd", +"acccccccccccccc````bbbbbbbbbbbbbbbcccccccccccccadddd", +"acccccccccccccc````bbbbbbbbbbbbbbbccccccccccccccdddd", +"accccccccccccccc````bbbbbbbbbbbbbbaccccccccccccccadd", +"daccccccccccccccc``bbbbbbbbbbbbbb``ccccccccccccccccd", +"daccccccccccccccccbbbbbbbbbbbbbb``accccccccccccccccc", +"acccccccccccccccccbbbbbbbbbbbbb```accccccccccccccccd", +"acccccccccccccccccabbbbbbbbbb`````accccccccccccccadd", +"dacccccccccccccccca``bbbb`````````acccccccccccccdddd", +"dacccccccccccccccca```````````````acccccccccccaddddd", +"ddaacccccccccccccca```````````````acccccccccaddddddd", +"ddddddaaaacccccccaddd```````````dddaccccccaddddddddd", +"ddddddddddaaaaaaaddddddddddddddddddaaacaaddddddddddd", +"ddddddddddddddadddddddddddddddddddddaaaadddddddddddd", +"dddddddddddddddddddddddddddddddddddddddddddddddddddd" +}; diff --git a/contrib/ppmtoansi/demo/make-ansi.sh b/contrib/ppmtoansi/demo/make-ansi.sh new file mode 100755 index 0000000..16d7b98 --- /dev/null +++ b/contrib/ppmtoansi/demo/make-ansi.sh @@ -0,0 +1,17 @@ +#!/bin/sh +xpmtoppm <linux-logo.xpm >linux-logo.ppm +../ppmtoansi -b 0/0/255 -y 10 -t 0/0/0:4 linux-logo.ppm >linux-logo.ansi +xpmtoppm <etherboot.xpm >etherboot.ppm +../ppmtoansi -b 0/0/0 etherboot.ppm >etherboot.ansi +xpmtoppm <text.xpm >text.ppm +../ppmtoansi -b 0/0/0 -x 10 text.ppm >text.ansi +xpmtoppm <x.xpm >x.ppm +../ppmtoansi -b 0/0/0 -x 8 x.ppm >x.ansi +xpmtoppm <dos.xpm >dos.ppm +../ppmtoansi -b 0/0/0 -x 8 dos.ppm >dos.ansi +xpmtoppm <hd.xpm >hd.ppm +../ppmtoansi -b 0/0/0 -x 8 hd.ppm >hd.ansi +xpmtoppm <floppy.xpm >floppy.ppm +../ppmtoansi -b 0/0/0 -x 8 floppy.ppm >floppy.ansi +xpmtoppm <flash.xpm >flash.ppm +../ppmtoansi -b 0/0/0 -x 11 flash.ppm >flash.ansi diff --git a/contrib/ppmtoansi/demo/text.ansi b/contrib/ppmtoansi/demo/text.ansi Binary files differnew file mode 100644 index 0000000..bbe7998 --- /dev/null +++ b/contrib/ppmtoansi/demo/text.ansi diff --git a/contrib/ppmtoansi/demo/text.ppm b/contrib/ppmtoansi/demo/text.ppm new file mode 100644 index 0000000..c6f8761 --- /dev/null +++ b/contrib/ppmtoansi/demo/text.ppm @@ -0,0 +1,51 @@ +P3 +13 16 +65535 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 +0 0 65535 0 0 65535 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 +0 0 65535 0 0 65535 0 0 65535 0 0 0 0 0 0 0 0 0 +0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 65535 65535 65535 +0 0 65535 65535 65535 65535 0 0 65535 0 0 0 0 0 0 0 0 0 +0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 65535 65535 0 +65535 65535 0 0 0 65535 0 0 65535 0 0 0 0 0 0 0 0 0 +0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 65535 65535 0 +65535 65535 0 65535 0 0 0 0 65535 0 0 0 0 0 0 0 0 0 +0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 65535 65535 +65535 65535 65535 65535 65535 65535 0 0 65535 0 0 65535 0 0 0 0 0 0 +0 0 0 +0 0 0 0 0 0 0 0 0 0 0 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 0 0 65535 0 0 65535 0 0 0 0 0 0 +0 0 0 +0 0 0 0 0 0 0 0 0 0 0 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 +0 0 0 0 0 0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 +0 0 0 0 0 0 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 0 0 65535 0 0 65535 0 0 65535 +0 0 0 +0 0 0 0 0 0 65535 0 0 65535 65535 65535 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 0 0 65535 0 0 65535 0 0 0 +0 0 0 +0 0 0 65535 65535 0 65535 65535 0 65535 0 0 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 65535 65535 0 0 0 0 65535 65535 65535 0 +0 0 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 65535 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +65535 0 0 +65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 65535 +65535 65535 65535 65535 65535 65535 65535 65535 0 65535 65535 0 65535 65535 0 65535 65535 0 +0 0 0 +0 0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 0 0 0 +0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 diff --git a/contrib/ppmtoansi/demo/text.xpm b/contrib/ppmtoansi/demo/text.xpm new file mode 100644 index 0000000..5261b96 --- /dev/null +++ b/contrib/ppmtoansi/demo/text.xpm @@ -0,0 +1,28 @@ +/* XPM */ +static char *noname[] = { +/* width height ncolors chars_per_pixel */ +"13 16 5 1", +/* colors */ +"` c #000000", +"a c #FF0000", +"b c #FFFFFF", +"c c #FFFF00", +"d c #0000FF", +/* pixels */ +"`````ddd`````", +"````ddddd````", +"````dbdbd````", +"````dccdd````", +"````dccad````", +"`````bbbdd```", +"```dbbbbdd```", +"```dbbbbbdd``", +"``dbbbbbbdd``", +"``dbbbbbbddd`", +"``abbbbbbdd``", +"`ccabbbbbadc`", +"ccccbbbbcccca", +"cccccbbbcccc`", +"```aa````aa``", +"`````````````" +}; diff --git a/contrib/ppmtoansi/demo/x.ansi b/contrib/ppmtoansi/demo/x.ansi new file mode 100644 index 0000000..e2844b3 --- /dev/null +++ b/contrib/ppmtoansi/demo/x.ansi @@ -0,0 +1 @@ +[8;1;4-$[23;1;1- [9;2;4-$[22;2;1- [10;3;4-$[21;3;1- [11;4;4-$[20;4;1- [12;5;4-$[19;5;1- [13;6;4-$[18;6;1- [14;7;2-$[17;7;2-$[14;8;1- [16;8;4-$[13;9;1- [17;9;4-$[12;10;1- [18;10;4-$[11;11;1- [19;11;4-$[10;12;1- [20;12;4-$[9;13;1- [21;13;4-$
\ No newline at end of file diff --git a/contrib/ppmtoansi/demo/x.ppm b/contrib/ppmtoansi/demo/x.ppm new file mode 100644 index 0000000..53e5bcf --- /dev/null +++ b/contrib/ppmtoansi/demo/x.ppm @@ -0,0 +1,51 @@ +P3 +17 16 +65535 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 65535 0 0 0 0 0 +0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 65535 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 0 0 0 65535 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +65535 0 0 65535 0 0 0 0 0 65535 0 0 65535 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +65535 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 +0 0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 65535 0 0 +65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 65535 0 0 +65535 0 0 65535 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 65535 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65535 0 0 +65535 0 0 65535 0 0 65535 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 65535 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +65535 0 0 65535 0 0 65535 0 0 65535 0 0 0 0 0 +0 0 0 65535 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 65535 0 0 65535 0 0 65535 0 0 65535 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/contrib/ppmtoansi/demo/x.xpm b/contrib/ppmtoansi/demo/x.xpm new file mode 100644 index 0000000..d069527 --- /dev/null +++ b/contrib/ppmtoansi/demo/x.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char *noname[] = { +/* width height ncolors chars_per_pixel */ +"17 16 2 1", +/* colors */ +"` c #000000", +"a c #FF0000", +/* pixels */ +"`````````````````", +"aaaa```````````a`", +"`aaaa`````````a``", +"``aaaa```````a```", +"```aaaa`````a````", +"````aaaa```a`````", +"`````aaaa`a``````", +"``````aa`aa``````", +"``````a`aaaa`````", +"`````a```aaaa````", +"````a`````aaaa```", +"```a```````aaaa``", +"``a`````````aaaa`", +"`a```````````aaaa", +"`````````````````", +"`````````````````" +}; diff --git a/contrib/ppmtoansi/ppmtoansi.c b/contrib/ppmtoansi/ppmtoansi.c new file mode 100644 index 0000000..71d95cb --- /dev/null +++ b/contrib/ppmtoansi/ppmtoansi.c @@ -0,0 +1,235 @@ +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> + +static int palette[8][3] = { +/* black, red, green, yellow, */ + { 0, 0, 0},{255, 0, 0},{ 0,255, 0},{255,255, 0}, + { 0, 0,255},{255, 0,255},{ 0,255,255},{255,255,255}}; +/* blue, magenta, cyan, white */ + +static struct trans { + struct trans *next; + int idx,r,g,b; +} *trans = NULL; + +static int skipcomment(FILE *fp) +{ + int ch; + + for (;;) { + ch = getc(fp); + if (ch != '#') + return(ch); + while (ch != '\n' && ch != EOF) + ch = getc(fp); } +} + +static int readentry(FILE *fp,int format,int depth) +{ + int ch,i = 0; + + if (format == '3') { + while ((ch = getc(fp)) == ' ' || ch == '\t' || ch == '\r' || ch == '\n'); + if (ch < '0' || ch > '9') { + error: + fprintf(stderr,"Format error in input file\n"); + exit(1); } + for (; ch >= '0' && ch <= '9'; ch = getc(fp)) + i = 10*i + ch - '0'; } + else { + if ((i = getc(fp)) > depth || i < 0) + goto error; } + return((i*256)/(depth+1)); +} + +static void packpixel(char *data,int c) +{ + int i = 0, n = 0; + + while (c--) { + i = (i << 3) | (*data++ & 0x7); + if ((n += 3) >= 8) + putchar((i >> (n -= 8)) & 0xFF); } + if (n) + putchar(i << (8 - n)); + return; +} + +static int dg(int i) +{ + int d; + + for (d = 0; i; d++, i /= 10); + return(d); +} + +static char *i2s(char *buf,int i) +{ +/* if (!i) + *buf = '\000'; + else*/ + sprintf(buf,"%d",i); + return(buf); +} + +static void flushdata(int x,int y,int c,char *data) +{ + char b1[10],b2[10],b3[10],b4[10]; + int i,j,rle,v; + + for (i = j = v = 0; i < c; ) { + for (rle = 0; i+rle < c && data[i] == data[i+rle]; rle++); + if (rle > (i != j ? (v ? 4 : 6) : 0) + + ((v || (i != j)) ? 4+dg(rle)+dg(data[i]) + : 6+dg(x+i)+dg(y)+dg(rle)+dg(data[i]))) { + if (i != j) { + if (v) + printf("[%s-",i2s(b1,i-j)); + else + printf("[%s;%s;%s-",i2s(b1,x+j),i2s(b2,y),i2s(b3,i-j)); + packpixel(data+j,i-j); } + if (v++ || (i != j)) + printf("[%s;%s+",i2s(b1,rle),i2s(b2,data[i])); + else + printf("[%s;%s;%s;%s+",i2s(b1,x+i),i2s(b2,y), + i2s(b3,rle),i2s(b4,data[i])); + j = i += rle; } + else + i++; } + if (j != c) { + if (v) + printf("[%s-",i2s(b1,c-j)); + else + printf("[%s;%s;%s-",i2s(b1,x+j),i2s(b2,y),i2s(b3,c-j)); + packpixel(data+j,c-j); } + return; +} + +int main(int argc,char *argv[]) +{ + extern int optind; + extern char *optarg; + FILE *infile = NULL; + int ch,i,j,dist,idx; + int format,width,height,depth; + int bg = 0,bgred = 0,bggreen = 0,bgblue = 0; + int xoffset = 0,yoffset = 0; + int w,h,r,g,b,c; + struct trans *tp; + char *buf; + + while ((i = getopt(argc,argv,"b:t:x:y:")) >= 0) switch(i) { + case 'b': + bg++; + for (i = bgred = 0; optarg[i] >= '0' && optarg[i] <= '9'; + bgred = 10*bgred + optarg[i++] - '0'); + if (optarg[i++] != '/') + goto usage; + for (bggreen = 0; optarg[i] >= '0' && optarg[i] <= '9'; + bggreen = 10*bggreen + optarg[i++] - '0'); + if (optarg[i++] != '/') + goto usage; + for (bgblue = 0; optarg[i] >= '0' && optarg[i] <= '9'; + bgblue = 10*bgblue + optarg[i++] - '0'); + if (optarg[i]) + goto usage; + break; + case 't': + if ((tp = malloc(sizeof(struct trans))) == NULL) + goto usage; + for (i = tp->r = 0; optarg[i] >= '0' && optarg[i] <= '9'; + tp->r = 10*tp->r + optarg[i++] - '0'); + if (optarg[i++] != '/') + goto usage; + for (tp->g = 0; optarg[i] >= '0' && optarg[i] <= '9'; + tp->g = 10*tp->g + optarg[i++] - '0'); + if (optarg[i++] != '/') + goto usage; + for (tp->b = 0; optarg[i] >= '0' && optarg[i] <= '9'; + tp->b = 10*tp->b + optarg[i++] - '0'); + if (optarg[i++] != ':') + goto usage; + if (optarg[i] == '-') { + j = -1; i++; } + else j = 1; + for (tp->idx = 0; optarg[i] >= '0' && optarg[i] <= '9'; + tp->idx = 10*tp->idx + optarg[i++] - '0'); + tp->idx *= j; + if (tp->idx < -1 || tp->idx >= 8) + goto usage; + if (optarg[i]) + goto usage; + tp->next = trans; + trans = tp; + break; + case 'x': + for (i = xoffset = 0; optarg[i] >= '0' && optarg[i] <= '9'; + xoffset = 10*xoffset + optarg[i++] - '0'); + if (optarg[i]) + goto usage; + break; + case 'y': + for (i = yoffset = 0; optarg[i] >= '0' && optarg[i] <= '9'; + yoffset = 10*yoffset + optarg[i++] - '0'); + if (optarg[i]) + goto usage; + break; + default: + usage: + fprintf(stderr,"Usage: %s [-b r/g/b] [-t r/g/b:idx] " + "[-x offset] [-y offset] [ppmfile]\n",argv[0]); + exit(1); } + if (argc-optind == 0) + infile = stdin; + else if (argc-optind == 1) + infile = fopen(argv[optind],"r"); + if (!infile) + goto usage; + if ((ch = skipcomment(infile)) != 'P' || + ((format = getc(infile)) != '3' && format != '6') || + ((ch = getc(infile)) != '\n' && ch != '\r' && getc(infile) != '\n')) + goto usage; + for (width = 0; (ch = skipcomment(infile)) >= '0' && ch <= '9'; + width = 10*width + ch - '0'); + while (ch == ' ') ch = getc(infile); + for (height = 0; ch >= '0' && ch <= '9'; ch = getc(infile)) + height = 10*height + ch - '0'; + if (ch != '\n' && ch != '\r' && getc(infile) != '\n') + goto usage; + for (depth = 0; (ch = skipcomment(infile)) >= '0' && ch <= '9'; + depth = 10*depth + ch - '0'); + if (ch != '\n' && ch != '\r' && getc(infile) != '\n') + goto usage; + if (!width || !height || !depth /* || depth > 255 */) + goto usage; + if ((buf = malloc(width)) == NULL) + goto usage; + for (h = 0; h < height; h++) { + for (w = c = 0; w < width; w++) { + r = readentry(infile,format,depth); + g = readentry(infile,format,depth); + b = readentry(infile,format,depth); + idx = 255; + if (bg && bgred == r && + bggreen == g && bgblue == b) + idx = -1; + else for (tp = trans; tp; tp = tp->next) + if (tp->r == r && tp->g == g && tp->b == b) { + idx = tp->idx; + break; } + if (idx == 255) + for (idx = -1, dist = 3*255*255, i = 8; i--;) + if ((j = (r-palette[i][0])*(r-palette[i][0]) + + (g-palette[i][1])*(g-palette[i][1]) + + (b-palette[i][2])*(b-palette[i][2])) < dist) { + dist = j; idx = i; } + if (idx >= 0) + buf[c++] = idx; + else if (c) { + flushdata(w-c+xoffset,h+yoffset,c,buf); + c = 0; } } + if (c) + flushdata(w-c+xoffset,h+yoffset,c,buf); } + exit(0); +} diff --git a/contrib/ppmtoansi/ppmtoansi.man b/contrib/ppmtoansi/ppmtoansi.man new file mode 100644 index 0000000..b19f979 --- /dev/null +++ b/contrib/ppmtoansi/ppmtoansi.man @@ -0,0 +1,120 @@ +.TH PPMTOANSI 1 "January 12, 1997" +.SH NAME +ppmtoansi \- Graphics Conversion Program For Extended ANSI Escape Codes +.SH SYNOPSIS +.B ppmtoansi +[ +.SM \-b +r/g/b ] [ +.SM \-t +r/g/b:idx] [ +.SM \-x +<xoffset> ] [ +.SM \-y +<yoffset> ] [ +<filename> ] +.SH DESCRIPTION +.I ppmtoansi +converts input files in +.IR ppm (5) +format to escape sequences that are understood by +.IR etherboot . +This allows for displaying icons and logos on the BOOT-Prom's splash +screen. +.PP +If no input file is specified, data is read from +.IR standard +.IR input . +All output is send to +.IR standard +.IR output , +error messages go to +.IR standard +.IR error . +.I ppmtoansi +tries to do some compression and minimizes the output filesize. +.SH OPTIONS +.TP +.B \-b +Specifies the +.IR red , +.IR green , and +.IR blue +intensities for the background color. This information is +used for providing a shape mask. All values are in the range from 0 to +255. +.TP +.B \-t +Allows for explicitly providing a translation between color values and +color indices. The indices are in the range 0 to 7 and conform to the +standard +.IR ANSI +.IR colorcodes . +.RS +.PP +0 black 4 blue +.PP +1 red 5 magenta +.PP +2 green 6 cyan +.PP +3 yellow 7 white +.PP +If no translations apply, +.IR ppmtoansi +will automatically select the color that is closest. +.RE +.TP +.B \-x +Specify an X offset relative to the current text cursor position. +.TP +.B \-y +Specify an Y offset relative to the current text cursor position. +.SH FILE FORMAT +.IR ppmtoansi +uses these extensions to the standard +.B ANSI escape +.BR codes . +.TP +.B <esc>[a;b;c;d+<data> +Draw pixel data. Use one byte per pixel. Colors are encoded as shown +above. In text mode, graphics is approximated by outputting suitable +characters. Parameters differ depending on the number of parameters +passed: +.RS +.TP +.B cnt +.IR cnt +data bytes follow. They will be drawn to the right of the last +graphics position. +.TP +.B rle;col +The next +.IR rle +pixels have the value +.IR col . +They will be drawn to the right of the last graphics position. No data +bytes follow. +.TP +.B x;y;cnt +.IR cnt +data bytes follow. They will be drawn relative to the top left corner +of the text cursor with an offset of +.RI ( x / y ). +.TP +.B x;y;rle;col +the next +.IR rle +pixels have the value +.IR col . +They will be drawn relative to the top left corner of the text cursor +with an offset of +.RI ( x / y ). +No data bytes follow. +.RE +.TP +.B <esc>[a;b;c;d\-<data> +same as above, but pack pixels into three bits. The first pixel is +stored in the three most significant bits of the first data byte. +.SH "SEE ALSO" +ppm(5), mknbi-linux(8), mknbi-dos(8). diff --git a/contrib/rom-scan/Makefile b/contrib/rom-scan/Makefile new file mode 100644 index 0000000..637404a --- /dev/null +++ b/contrib/rom-scan/Makefile @@ -0,0 +1,64 @@ +CPPFLAGS = +LDLIBS = +CFLAGS = -pipe -g -O2 -Wall +LDFLAGS = -pipe +CC = gcc +LD = gcc +# Some "black" magic to determine optimal compiler flags for target +# architecture +TARGET_ARCH:= $(shell if [ \! -r .compile-options ] ; then ( \ + cpu=`grep cpu /proc/cpuinfo 2>&1 |head -1| \ + cut -d : -f 2-| sed -e 's/ //g'`; \ + if [ x"$$cpu" = x"" ] ; then \ + echo -fno-strength-reduce; \ + else if [ "$$cpu" = "386" ] ; then \ + echo -m386 -fno-strength-reduce; \ + else if [ "$$cpu" = "486" ] ; then \ + echo -m486 -fno-strength-reduce; \ + else if [ "$$cpu" = "Alpha" ] ; then \ + echo -fno-strength-reduce; \ + else echo main\(\)\{\} >.compile-options.c; \ + if gcc -mpentium -o .compile-options.o -c \ + .compile-options.c &>/dev/null; then \ + echo -mpentium -fstrength-reduce; \ + else if gcc -m486 -malign-functions=2 -malign-jumps=2 \ + -malign-loops=2 -o .compile-options.o -c \ + .compile-options.c &>/dev/null; then \ + echo -n -m486 -malign-functions=2 -malign-jumps=2; \ + echo ' '-malign-loops=2 -fno-strength-reduce; \ + else echo -m486; \ + fi;fi;fi;fi;fi;fi) > .compile-options; \ + rm -f .compile-options.c .compile-options.o; \ + fi; cat .compile-options) +ASFLAGS = $(TARGET_ARCH) + +OBJS = rom-scan.o + +############################################################################## + +ifeq (.depend,$(wildcard .depend)) +all: rom-scan +include .depend +else +all: depend + @$(MAKE) all +endif + +############################################################################## + +rom-scan: $(OBJS) + +############################################################################## + +clean: + $(RM) *~ *.o *.dvi *.log *.aux *yacc.tab.[ch] *yacc.output *lex.[co] \ + *.dat .depend .tmp_depend .compile-options* + strip rom-scan >&/dev/null || true + +############################################################################## + +depend: + for i in *.c;do $(CPP) $(CPPFLAGS) -MM $$i;done >.tmp_depend + mv .tmp_depend .depend + + diff --git a/contrib/rom-scan/rom-scan.c b/contrib/rom-scan/rom-scan.c new file mode 100644 index 0000000..c5e4829 --- /dev/null +++ b/contrib/rom-scan/rom-scan.c @@ -0,0 +1,115 @@ +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#ifndef __TURBOC__ +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#endif + +#ifdef __TURBOC__ +#define HUGE huge +#else +#define HUGE +#endif + +#define ROMSTART 0xC8000 +#define ROMEND 0xE8000 +#define ROMINCREMENT 0x00800 +#define ROMMASK 0x03FFF + +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)(long long)-1) +#endif + +typedef struct Images { + struct Images *next; + long start; + long size; +} Images; + +static void rom_scan(const unsigned char HUGE *rom,long offset,long len) +{ + static Images *images = NULL; + Images *ptr; +/* The assignments to dummy are to overcome a bug in TurboC */ + long dummy, size; + int chksum; + long i; + + if (rom[offset] != 0x55 || rom[dummy = offset+1] != 0xAA) + return; + size = (long)rom[dummy = offset+2]*512L; + printf("Found ROM header at %04lX:0000; " + "announces %ldk image (27C%02d EPROM)\n", + offset/16,(size+512)/1024, + size <= 1024 ? 8 : + size <= 2048 ? 16 : + size <= 4096 ? 32 : + size <= 8192 ? 64 : + size <= 16384 ? 128 : + size <= 32768 ? 256 : + size <= 65536 ? 512 : 11); + if (offset & ROMMASK) + printf(" This is a unusual position; not all BIOSs might find it.\n" + " Try to move to a 16kB boundary.\n"); + if (size > len) { + printf(" This image extends beyond %04X:0000. " + "It clashes with the system BIOS\n", + ROMEND/16); + size = len; } + for (chksum=0, i = size; i--; chksum += rom[dummy = offset+i]); + if (chksum % 256) + printf(" Checksum does not match. This image is not active\n"); + ptr = malloc(sizeof(Images)); + ptr->next = images; + ptr->start = offset; + ptr->size = size; + images = ptr; + for (ptr = ptr->next; ptr != NULL; ptr = ptr->next) { + for (i = 0; i < size && i < ptr->size; i++) + if (rom[dummy = ptr->start+i] != rom[dummy = offset+i]) + break; + if (i > 32) { + printf(" Image is identical with image at %04lX:0000 " + "for the first %ld bytes\n", + ptr->start/16,i); + if (i >= 1024) + if (i == size) + printf(" this means that you misconfigured the EPROM size!\n"); + else + printf(" this could suggest that you misconfigured the " + "EPROM size\n"); + else + printf(" this is probably harmless. Just ignore it...\n"); } } + return; +} + +int main(void) +{ + long i; + unsigned char HUGE *rom; + +#ifndef __TURBOC__ + int fh; + if ((fh = open("/dev/kmem",O_RDONLY|O_SYNC)) < 0) { + fprintf(stderr,"Could not open \"/dev/kmem\": %s\n",0 );//strerror(errno)); + return(1); } + if ((rom = mmap(NULL,ROMEND-ROMSTART,PROT_READ,MAP_SHARED,fh, + ROMSTART)) == MAP_FAILED) { + fprintf(stderr,"Could not mmap \"/dev/kmem\": %s\n",0); //strerror(errno)); + close(fh); + return(1); } + close(fh); +#endif + for (i = ROMEND; (i -= ROMINCREMENT) >= ROMSTART; ) +#ifdef __TURBOC__ + rom_scan(0,i,ROMEND-i); +#else + rom_scan(rom-ROMSTART,i,ROMEND-i); + munmap(rom,ROMEND-ROMSTART); +#endif + return(0); +} diff --git a/contrib/romid/pktdrv.bat b/contrib/romid/pktdrv.bat new file mode 100644 index 0000000..058fd4e --- /dev/null +++ b/contrib/romid/pktdrv.bat @@ -0,0 +1,84 @@ +@echo off
+if (%PKTDRV%)==(P) goto end
+A:\PKT\ROMID
+if (%ROMID%)==() goto select
+if (%ROMID%)==(NE) goto NE
+if (%ROMID%)==(WD) goto WD
+if (%ROMID%)==(3C509) goto 3C509
+if (%ROMID%)==(3C905B) goto 3C905B
+if (%ROMID%)==(EEPRO100) goto EEPRO100
+if (%PCIID%)==(10EC:8029) goto RTL8029
+if (%PCIID%)==(10EC:8139) goto RTL8139
+if (%PCIID%)==(11AD:0002) goto LITEON
+if (%PCIID%)==(1011:0009) goto DEC
+echo No Driver installed!
+goto end
+:select
+cls
+echo *** Select your network card.... ***
+echo.
+echo 1 -- Intel EtherExpress 100B PCI Adapter
+echo 2 -- 3Com 3C90X Etherlink III PCI Adapter
+echo 3 -- 3Com 3C5X9 Etherlink III ISA Adapter
+echo 4 -- NE2000 Novell ISA Adapter
+echo 5 -- Realtek 8029 PCI Adapter
+echo 6 -- Realtek 8139 PCI Adapter
+echo 7 -- SMC EliteUltra 8216 ISA Adapter
+echo 8 -- DEC21x4 Busmaster PCI Adapter
+echo 9 -- LiteOn PNIC Busmaster PCI Adapter
+echo.
+echo *** **************************** ***
+echo.
+choice /c123456789 /n Select:
+if errorlevel 9 goto LITEON
+if errorlevel 8 goto DEC
+if errorlevel 7 goto WD
+if errorlevel 6 goto RTL8139
+if errorlevel 5 goto RTL8029
+if errorlevel 4 goto NE
+if errorlevel 3 goto 3C509
+if errorlevel 2 goto 3C905B
+if errorlevel 1 goto EEPRO100
+goto end
+
+:EEPRO100
+A:\PKT\E100BPKT 0x60
+if errorlevel 0 goto ok
+goto end
+:NE
+A:\PKT\NE2000 0x60 11 0x0300
+if errorlevel 0 goto ok
+goto end
+:RTL8029
+A:\PKT\PCIPKT 0x60
+if errorlevel 0 goto ok
+goto end
+:RTL8139
+A:\PKT\RTSPKT 0x60
+if ERRORLEVEL 0 goto OK
+goto end
+:WD
+A:\PKT\SMC_WD 0x60
+if errorlevel 0 goto ok
+goto end
+:3C509
+A:\PKT\3C5X9PD 0x60
+if errorlevel 0 goto ok
+goto end
+:3C905B
+A:\PKT\3C90XPD 0x60
+if errorlevel 0 goto ok
+goto end
+:LITEON
+A:\PKT\FEPD 0x60
+if ERRORLEVEL 0 goto ok
+goto end
+:DEC
+A:\PKT\ETHPCI 0x60
+if ERRORLEVEL 0 goto ok
+goto end
+
+:ok
+SET PKTDRV=P
+:end
+
diff --git a/contrib/romid/readme b/contrib/romid/readme new file mode 100644 index 0000000..6c6c500 --- /dev/null +++ b/contrib/romid/readme @@ -0,0 +1,8 @@ +This simple utility has currently no correct error checking.
+If your environment space couldn't hold up the variables, the
+program breaks without an error message, so be sure to add a
+line similar to the following to your config.sys:
+SHELL=A:\COMMAND.COM A:\ /P/E:2048
+
+The batch is a sample which shows how it could be used for those
+one not familar with batch files and environment variables.
\ No newline at end of file diff --git a/contrib/romid/romid.c b/contrib/romid/romid.c new file mode 100644 index 0000000..f6049bf --- /dev/null +++ b/contrib/romid/romid.c @@ -0,0 +1,124 @@ +/* This little program is my try to provide information about the + EtherBoot rom via environment variables to a batch file. This + could be done better, I think, but it works... + The program compiles with Borland C 3.1; other versions not tested. + The C code for setting the environment variables I got from an + archive, it was written by Richard Marks <rmarks@KSP.unisys.COM>. + ROMID is written by Guenter Knauf <eflash@gmx.net> +*/ +#define VERSION "0.6" +#define VDATE "2003-08-24" + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define ROMSTART 0xC8000 +#define ROMEND 0xE8000 +#define ROMINCREMENT 0x00800 +#define ROMMASK 0x03FFF + +int verbose = 0; + +int settheenv(char *symbol, char *val); + +static int rom_scan(const unsigned char huge *rom,long offset,long len) { + long size,i,j; + char symbol[16]; + char val[64]; + char romid[64]; + char *rptr; + + if (rom[offset] != 0x55 || rom[offset+1] != 0xAA) + return 0; + + size = (long)rom[offset+2]*512L; + if (verbose) { + printf("Found ROM header at %04lX:0000; announces %ldk image\n", offset/16,(size+512)/1024); + if (offset & ROMMASK) + printf(" This is a unusual position; not all BIOSs might find it.\n" + " Try to move to a 16kB boundary.\n"); + if (size > len) { + printf(" This image extends beyond %04X:0000. It clashes with the system BIOS\n", ROMEND/16); + size = len; + } + } + + for (i=0; i<64; i++) { + if (rom[offset+size-3-i] == 0xff) + break; + } + if (20<i && i<63) { + i--; + for (j=0; j<i; j++) + val[j] = rom[offset+size-3-i+j]; + val[i] = 0; + } else + return 0; + + if (strstr(val, "therboot") == NULL) + return 0; + + if (verbose) + printf("ROM Signature '%s'\n", val); + if ((rptr = strstr(val, "rom")) != NULL) { + for (i=1; i<4; i++) { + rptr--; + if (rptr[0] == 0x2E) + break; + } + i = 0; + while (!(rptr[0] == 0x20 || rptr < val)) { + i++; + rptr--; + } + rptr++; + i--; + strncpy(romid, rptr, i); + romid[i] = 0; + if (verbose) + printf("ROM Driver ID '%s'\n", romid); + strcpy(symbol, "ROMID"); + if (settheenv(symbol, romid)) + printf("Error setting evironment var %s with value %s\n", symbol, romid); + } else { + if (verbose) + printf("Couldnt find driver name!\n"); + return 0; + } + if (rom[offset+0x1C] == 'P' && rom[offset+0x1D] == 'C' && rom[offset+0x1E] == 'I') { + sprintf(val, "%02X%02X:%02X%02X", rom[offset+0x21], rom[offset+0x20], + rom[offset+0x23], rom[offset+0x22]); + if (verbose) + printf("ROM Vendor ID '%s'\n", val); + strcpy(symbol, "PCIID"); + if (settheenv(symbol, val)) + printf("Error setting evironment var %s with value %s\n", symbol, val); + } + return 1; +} + +/* **************** main stuff **************** */ +int main (int argc, char *argv[]) { + long i; + + printf("\nROM-ID for Etherboot v%s (c) G. Knauf %s\n", VERSION, VDATE); + if (argc > 1) { + /* parse input parameters */ + for (argc--, argv++; *argv; argc--, argv++) { + if ((strnicmp (*argv, "-", 1) == 0) || (strnicmp (*argv, "/", 1) == 0)) { + if ((strnicmp (*argv, "-V", 2) == 0) || (strnicmp (*argv, "/V", 2) == 0)) { + verbose = 1; + } else { + printf("Usage: %s [-v]\n"); + } + } + } + } + for (i = ROMEND; (i -= ROMINCREMENT) >= ROMSTART;) + if (rom_scan(0,i,ROMEND-i)) + break; + + return 0; +} diff --git a/contrib/romid/setenvs.c b/contrib/romid/setenvs.c new file mode 100644 index 0000000..e18e399 --- /dev/null +++ b/contrib/romid/setenvs.c @@ -0,0 +1,200 @@ +/* subroutine to put a value string into an environment symbol. + Uses the controling command.com environment, not the programs. + This means that the env variable is set so other routines in + a .BAT file may use it. + + call: settheenv (char * symbol, char * val); + symbol is an asciiz string containing the env variable name, + val is an asciiz string containing the value to assign to this vbl. + + returns: 0 = OK, + 1 = failure. + failure is not unlikely. The env block may be full. Or on some + systems the env block might not be found + + SETENVS.C was written by Richard Marks <rmarks@KSP.unisys.COM>. +*/ + + +#include <stdio.h> +#include <dos.h> +#include <string.h> +#include <stdlib.h> + +typedef struct { + char fill1[0x0A]; + int *prev_term_handler; + int *prev_ctrl_c; + int *prev_crit_error; + char fill2[0x16]; + int envir_seg; +} psp; + +typedef struct { + char type; + int psp_segment; + int num_segments; + char fill[11]; + char arena_data; +} arena; + + +#define NORMAL_ATYPE 0x4D +#define LAST_ATYPE 0x5A + + +static arena * get_next_arena (arena * ap) { + return( MK_FP( FP_SEG(ap)+1+ap->num_segments, 0) ); +} + +/* returns 0 if passed pointer is to an arena, else returns 1 */ +static int is_valid_arena (arena * ap) { + arena * ap1; + if (ap->type == NORMAL_ATYPE && + (ap1=get_next_arena(ap))->type == NORMAL_ATYPE && + ( (ap1=get_next_arena(ap1))->type == NORMAL_ATYPE || + ap1->type == LAST_ATYPE) ) + return(0); + return (1); +} + + +static arena * get_first_arena () { +/* return pointer to the first arena. + * scan memory for a 0x4D on a segment start, + * see if this points to another two levels of arena + */ + arena * ap, * ap1; + int * temp; + int segment; + + for (segment=0; segment<_CS; segment++) { + ap = MK_FP(segment, 0); + if ( is_valid_arena (ap) == 0) return (ap); + } + return(NULL); +} /* end get_first_arena */ + + +static int is_valid_env (char * ad, int num_segs) { + char * base_ad; + base_ad = ad; + while ( (*ad) && (((ad-base_ad)>>4) < num_segs) ) { + if (strnicmp(ad, "COMSPEC=", 8)==0) return(0); + ad += strlen(ad) + 1; + } + return (1); +} + + +static arena * get_arena_of_environment () { +/* to get the arena of first environment block: + First get segment of COMMAND.COM from segment of previous critical err code. + Then scan all the arenas for an environment block with a matching PSP + segment */ + +arena * ap; +psp * pspp, * pspc; +unsigned int i, ccseg; + +/* set pspp to psp of this program */ +pspp = MK_FP(_psp,0); + +#ifdef DEBUG +printf("prog psp=%p\n",pspp); +#endif + +/* set pspc to psp of COMMAND.COM, back up a bit to get it if needed */ +ccseg = FP_SEG (pspp->prev_crit_error); +if ( (i=ccseg-32) < 60) i=60; + +while (ccseg>i) { + pspc = MK_FP (ccseg, 0); + if ( is_valid_arena((arena *) pspc) == 0) goto L1; + ccseg--; +} +return (NULL); + +L1: pspc = MK_FP (++ccseg, 0); +#ifdef DEBUG +printf("comm.com=%p\n",pspc); +#endif + +/* first see if env seg in command.com points to valid env block + if env seg is in a valid arena, then arena must point to this command.com + else assume env block is fabricated like for 4DOS, use 128 bytes */ + +ap = MK_FP (pspc->envir_seg-1, 0); +i = ap->num_segments; + +if (is_valid_arena (ap) == 0) { + if (ap->psp_segment != FP_SEG(pspc)) goto L2; +} else { + i = 9; +} + +if ( is_valid_env (&ap->arena_data, i) == 0 ) + return (ap); + +/* command.com did not so point, search thru all env blocks */ + +L2: +if ( (ap=get_first_arena()) != NULL ) { + while (ap->type != LAST_ATYPE) { +#ifdef DEBUG + printf("%p\n",ap); +#endif + if (ap->psp_segment == FP_SEG(pspc) && + is_valid_env (&ap->arena_data, ap->num_segments)==0 ) + return (ap); + + ap = get_next_arena(ap); + } +} return(NULL); +} /* end get_arena_of_environment */ + +/*****************************************************************************/ + +int settheenv(char * symbol, char * val) { +int total_size, + needed_size=0, + strlength; +char * sp, *op, *envir; +char symb_len=strlen(symbol); +char found=0; +arena * ap; + +strupr(symbol); + +/* first, can COMMAND.COM's envir block be found ? */ +if ( (ap=get_arena_of_environment()) == NULL) + return(1); + +/* search to end of the envir block, get sizes */ +total_size = 16 * ap->num_segments; +envir = &ap->arena_data; +op=sp=envir; +while (*sp) { + strlength = strlen(sp)+1; + if ( *(sp+symb_len)=='=' && + strnicmp(sp,symbol,symb_len)==0 ) + found=1; + else { + needed_size += strlength; + if (found) strcpy(op,sp); + op = &op[strlength]; + } + sp += strlength; +} +*op=0; +if (strlen(val) > 0) { + needed_size += 3 + strlen(symbol) + strlen(val); + if (needed_size > total_size) + return(1); /* could mess with environment expansion here */ + + strcpy(op, symbol); strcat(op, "="); strcat(op, val); + op += strlen(op)+1; + *op = 0; +} +return(0); +} /* end setheenv subroutine */ diff --git a/contrib/smc9462tx-flash/Makefile b/contrib/smc9462tx-flash/Makefile new file mode 100644 index 0000000..dc5b3ff --- /dev/null +++ b/contrib/smc9462tx-flash/Makefile @@ -0,0 +1,20 @@ +GCC = gcc +KERNELDIR = ../linux-2.4.20 +KERNELSTYLE=-D__KERNEL__ -DCPU=__i386__ -DMODULE +INCLUDE_DIR=-I$(KERNELDIR)/include -I../include -I$(ROOTDIR)/include + +all: dp83820flash.o dp83820_write + +CFLAGS+=-O2 -Wall -fomit-frame-pointer -fno-strength-reduce +CFLAGS+=$(KERNELSTYLE) $(CDEBUG) $(INCLUDE_DIR) + +install: + +dp83820flash.o: dp83820flash.c + $(GCC) dp83820flash.c -o dp83820flash.o -c $(CFLAGS) + +dp83820_write: dp83820_write.c + $(GCC) $< -o $@ -Wall -O2 + +clean: + $(RM) *.o dp83820_write diff --git a/contrib/smc9462tx-flash/README b/contrib/smc9462tx-flash/README new file mode 100644 index 0000000..53501cb --- /dev/null +++ b/contrib/smc9462tx-flash/README @@ -0,0 +1,24 @@ +This code was written by Dave Ashley for NXTV, Inc. It is released under +the terms of the GPL. The purpose is to let you write to the bootrom of +the SMC9462TX card. The assumption is that you've stuck an AT29C512 in the +socket. Note that the board has pins D5 + D6 reversed on the socket. Also +the socket only supplies 3.3V to the rom. Good luck trying to locate a +DIP programmable flash device that operates at 3.3V. What I do is to bend +pin 32 back and solder a wire directly from the 5V side of the 3.3V regulator +over to it. The dp83820's bootrom interface pins are all 5V logic tolerant. +However mod your board at your own risk, no warranty or guarantees are implied +or given!!! If you don't wire the 5V to the AT29C512, you can still read +the rom contents (it operates ok at 3.3V evidently) but you can't write to it +because the AT29C512 has a safety protection, it disables writes if the +power supply voltage drops below 3.8V. + +See the comments at the top of the 2 C files for more information. + +The Makefile needs to be hacked to build for your system. If you can't +figure it out you shouldn't be messing with this stuff anyway. + +-Dave Ashley +Email address intentionally left out to avoid spam. +http://www.xdr.com/dash + +Mon Mar 8 13:55:34 PST 2004 diff --git a/contrib/smc9462tx-flash/dp83820_write.c b/contrib/smc9462tx-flash/dp83820_write.c new file mode 100644 index 0000000..ab6e566 --- /dev/null +++ b/contrib/smc9462tx-flash/dp83820_write.c @@ -0,0 +1,310 @@ +/* + DP83820 flash utility written by Dave Ashley for NXTV, Inc. + Copyright (C) 2004 by NXTV, Inc. + Written 20040219 by Dave Ashley. + + Currently only supports the AT29C512 + + This code is released under the terms of the GPL. No warranty. + + + THEORY: + This code uses the /proc/dp83820 file which is created by the + dp83820flash.o module. That file allows single byte reads + writes + to the bootrom. + +*/ + +#include <unistd.h> +#include <sys/io.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <signal.h> + + +// SMC9462TX card has D5 + D6 on the bootrom socket reversed +int fixb(int val) +{ + return (val&~0x60) | ((val&0x20)<<1) | ((val&0x40)>>1); +} +int openit(void) +{ +int fd; + fd=open("/proc/dp83820",O_RDWR); + if(fd<0) + { + printf("Failed to open the /proc/dp83820 file to access the flashrom.\n"); + printf("Make sure you've done:\n"); + printf(" modprobe dp83820flash\n"); + exit(-1); + } + return fd; +} +void set(int addr, unsigned char val) +{ +unsigned char msg[3]; +int fd; + fd=openit(); + msg[0]=addr; + msg[1]=addr>>8; + msg[2]=val; + write(fd,msg,3); + close(fd); +} +int get(int addr) +{ +unsigned char msg[2]; +int fd; + fd=openit(); + msg[0]=addr; + msg[1]=addr>>8; + write(fd,msg,2); + read(fd,msg,1); + close(fd); + return msg[0]; +} + + +int getromsize(unsigned char *id) +{ + if(id[0]==0xbf && id[1]==0xb6) return 0x40000; + if(id[0]==0xc2 && id[1]==0xb0) return 0x40000; + if(id[0]==0x1f && id[1]==0x3d) return 0x10000; + return -1; +} + +#define MAXROMSIZE 0x200000 +unsigned char *buffer; + +int loadfile(char *name) +{ +int filefd; +int filesize; + filefd=open(name,O_RDONLY); + if(filefd<0) + { + printf("Couldn't open file %s\n",name); + return -1; + } + filesize=read(filefd,buffer,MAXROMSIZE); + close(filefd); + if(filesize<0) + { + printf("Error trying to read from file %s\n",name); + } + return filesize; +} + +void readbios(char *name,int len) +{ +int filefd; +int filesize=0; +unsigned char block[256]; +int i,j; + + filefd=open(name,O_WRONLY|O_TRUNC|O_CREAT,0644); + if(filefd<0) + { + printf("Couldn't create file %s for writing\n",name); + return; + } + for(i=j=0;i<len;++i) + { + block[j++]=get(i); + if(j<sizeof(block)) continue; + filesize+=write(filefd,block,j); + j=0; + } + close(filefd); + if(filesize!=len) + { + printf("Error during write of %s file\n",name); + return; + } + printf("BIOS contents saved to %s, $%x bytes\n",name,len); +} + +int verifybios(char *name,int len, int print) +{ +int filelen; +int i; +int same=0; + + filelen=loadfile(name); + for(i=0;i<filelen;++i) + if(get(i)!=buffer[i]) break; + if(i<filelen) + { + if(print) + printf("BIOS contents does not match file %s, from byte $%x\n", + name,i); + } else + { + if(print) + printf("BIOS contents match file %s for all of its $%x bytes\n", + name,i); + same=1; + } + return same; +} + +void writebios(char *name,int len,unsigned char *id) +{ +int i; +int p1,p2; +int sectorsize=128; + + if(len!=loadfile(name)) + { + printf("File size does not match expected ROM size\n"); + return; + } + if(0 && (id[0]!=0xbf || id[1]!=0xb6)) + { + printf("Don't know how to write this kind of flash device\n"); + return; + } + + printf("Erasing device\n"); + set(0x5555,fixb(0xaa)); + set(0x2aaa,fixb(0x55)); + set(0x5555,fixb(0x80)); + set(0x5555,fixb(0xaa)); + set(0x2aaa,fixb(0x55)); + set(0x5555,fixb(0x10)); + + for(;;) + { + printf(".");fflush(stdout); + usleep(250000); + if(get(0)==get(0) && get(0)==get(0)) + break; + } + printf("BIOS erased\n"); + + printf("Writing to BIOS\n"); + p1=-1; + for(i=0;i<len;++i) + { + p2=100*i/(len-1); + if(p2!=p1) + { + printf("\r%d%%",p1=p2); + fflush(stdout); + } + if(i%sectorsize==0) + { + set(0x5555,fixb(0xaa)); + set(0x2aaa,fixb(0x55)); + set(0x5555,fixb(0xa0)); + } + set(i,buffer[i]); + if(i%sectorsize==sectorsize-1) + while(get(0)!=get(0) || get(0)!=get(0)); + } + printf("\n"); +} + +void helptext(char *name) +{ + printf("USE: %s <options>\n",name); + printf(" -v <filename> = verify bios rom contents with file\n"); + printf(" -w <filename> = write to bios rom contents from file\n"); + printf(" -r <filename> = read from bios rom contents to file\n"); + printf(" -f = force erase/write even if contents already match\n"); + exit(0); +} + +int main(int argc,char **argv) +{ +int i; +int vals; +unsigned char id[4]; +char *filename=0; +char action=0; +int romsize; +int force=0; +int same; + + vals=0; + + if(argc<2) helptext(argv[0]); + for(i=1;i<argc;++i) + { + if(argv[i][0]!='-') + helptext(argv[0]); + switch(argv[i][1]) + { + case 'f': + force=1; + break; + case 'v': + case 'w': + case 'r': + action=argv[i][1]; + if(i+1<argc) + filename=argv[++i]; + else helptext(argv[0]); + break; + default: + helptext(argv[0]); + } + + } + + buffer=malloc(MAXROMSIZE); + if(!buffer) + { + printf("No memory available!\n"); + exit(-1); + } + + set(0x5555,fixb(0xaa)); // get into flash ID mode + set(0x2aaa,fixb(0x55)); + set(0x5555,fixb(0x90)); + + for(i=0;i<4;++i) id[i]=get(i); + + set(0x5555,fixb(0xaa)); // get out of flash ID mode + set(0x2aaa,fixb(0x55)); + set(0x5555,fixb(0xf0)); + usleep(10000); + + for(i=0;i<4;++i) + if(id[i]!=get(i)) break; + if(i==4) + { + printf("Could not read BIOS flashrom ID.\n"); + goto biosdone; + } + printf("ID %02x %02x\n",id[0],id[1]); + romsize=getromsize(id); + if(romsize<0) + { + printf("Unknown rom type\n"); + goto biosdone; + } + printf("romsize=$%x bytes\n",romsize); + if(action=='r') + readbios(filename,romsize); + if(action=='w') + { + if(!force) + same=verifybios(filename,romsize,0); + else + same=0; + if(!same) + writebios(filename,romsize,id); + } + if(action=='v' || action=='w') + verifybios(filename,romsize,1); + +biosdone: + + return 0; +} diff --git a/contrib/smc9462tx-flash/dp83820flash.c b/contrib/smc9462tx-flash/dp83820flash.c new file mode 100644 index 0000000..661c429 --- /dev/null +++ b/contrib/smc9462tx-flash/dp83820flash.c @@ -0,0 +1,152 @@ +/* + Kernel module for the dp83820 flash write utility. This code was written + by Dave Ashley for NXTV, Inc. + Copyright 2004 by NXTV, Inc. + Written 20040219 by Dave Ashley. + + This code is released under the terms of the GPL. No warranty. + + THEORY: The dp83820 bootrom interface is flawed in that you can't + read or write a single byte at a time, and this is required in order + to write to flash devices like the AT29C512. So the workaround is + to use the chips ability to map into memory the bootrom, then the cpu + can directly do byte accesses. + + The problem is that a "feature" of the dp83820 is that when you map + in the bootrom, you conveniently lose access to the PCI registers. + So we need to do this in kernel space and wrap every access to the + bootrom within interrupt_disable/restore, in case a network interrupt + were to come in. + + This kernel module is very simple, it just creates a proc file + /proc/dp83820 + If you write 3 bytes to this file you are doing a write to the flashrom: + +Byte 1 2 3 + ALOW AHIGH DATA + + If you write 2 bytes to this file you are doing a read from the flashrom: +Byte 1 2 + ALOW AHIGH + Then the next read from the file will return a single byte of what + was at that location. + + You only get one shot at accessing the proc file, you need to then + close/open if you want to do another access. This could probably be + cleaned up pretty easily so more accesses can be done without having + to close/open the file. + +*/ + + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/proc_fs.h> +#include <linux/module.h> + + +#define PROCNAME "dp83820" + +struct pci_dev *mydev=0; +unsigned long loc; +unsigned char *addr=0; + +unsigned char lastread; + + +int my_read_proc(char *buf, char **start,off_t offset,int count, int *eof,void *data) +{ +int retval=0; + + if(count>0) + { + buf[0]=lastread; + retval=1; + } + + *eof=1; + + return retval; +} + +int my_write_proc(struct file *file, const char *buffer, unsigned long count, + void *data) +{ +unsigned char *msg; + +unsigned long flags; + + msg=(void *)buffer; + save_flags(flags); + cli(); + pci_write_config_dword(mydev, 0x30, loc | 1); + + switch(count) + { + case 2: + lastread=addr[msg[0] | (msg[1]<<8)]; + break; + case 3: + addr[msg[0] | (msg[1]<<8)] = msg[2]; + break; + } + pci_write_config_dword(mydev, 0x30, loc); + restore_flags(flags); + return count; +} + + +struct proc_dir_entry *de=0; + +int __init init_module(void) +{ +int found=0; + mydev=0; + pci_for_each_dev(mydev) + { + if(mydev->vendor==0x100b && mydev->device==0x0022) + { + found=1; + break; + } + } + if(!found) + { + printk("Could not find DP83820 network device\n"); + return ENODEV; + } + + de=create_proc_entry(PROCNAME,0,0); + if(!de) + return -1; + de->data=0; + de->read_proc=my_read_proc; + de->write_proc=my_write_proc; + + loc=mydev->resource[PCI_ROM_RESOURCE].start; + addr=ioremap_nocache(loc,0x10000); + + + return 0; +} + +void cleanup_module(void) +{ + if(de) + { + remove_proc_entry(PROCNAME,0); + de=0; + } + if(addr) + { + iounmap(addr); + addr=0; + } +} + diff --git a/contrib/t2hproxy/README b/contrib/t2hproxy/README new file mode 100644 index 0000000..ce5e1e9 --- /dev/null +++ b/contrib/t2hproxy/README @@ -0,0 +1,95 @@ +T2hproxy + +This is a TFTP to HTTP proxy. To the TFTP client it looks like a TFTP +server. To the HTTP server it looks like a HTTP client. So you can store +your boot files on the HTTP server. Or even create them with a CGI +program. E.g. if you can get dhcpd to send a filename which has strings +representing attributes of the client, as determined from the DHCP +request, then you can get the CGI program to parse this and send the +appropriate image, which might even be synthesised. + +There are two versions of the proxy, in Perl and in Java. + +1. The Perl version. + +This is the original quick Perl hack conceived in a moment of madness. +:-) Perl is great for prototyping. + +To run it, you need Perl 5.8.0 or later and all the Perl modules listed +at the top of the program installed. Edit and install the xinetd config +file as /etc/xinetd.d/t2hproxy and restart xinetd. The prefix is the +string that is prepended to all filenames to form the URL requested from +the HTTP server. Remember you need the trailing / if the filenames don't +start with /. + +This is only a proof-of concept. It has these drawbacks at the moment: + ++ (I don't consider this a draback, but some may.) It's started from +xinetd because xinetd handles all the socket listening, IP address +checking, rate limiting, etc. + ++ It has no cache. Use a proxy to do the caching (there's a --proxy +option). This also takes care of fetching from outside a firewall. + ++ It reads the entire HTTP content into memory before serving. Ideally +it should stream it from the HTTP server to minimise memory usage. This +is a serious drawback for booting lots of clients. Each instance of the +server will consume an amount of memory equal to the size of image +loaded. + ++ If the HTTP server is at the end of a slow link there is a delay +before the first data block is sent. The client may timeout before +then. Another reason for streaming, as this allows the first block to +be sent sooner. A local cache primed with the images in advance may +help. Using the blocksize option helps here because this causes the +server to send the OACK to the client immediately before the data is +fetched and this prevents it from starting up another connection. + ++ The transfer size may not be obtainable from the HTTP headers in all +cases, e.g. a CGI constructed image. This matters for clients that need +the tsize extension, which is not supported at the moment. + +If I'm feeling masochistic I may write a Java version, which should take +care of the multi-threading and streaming. + +2. The Java version + +The main problem with the Perl version is that it does not stream the +HTTP input but sucks it all in at once. As mentioned, this causes a +delay as well as requiring memory to hold the image. I could fix this by +doing the polling on the HTTP socket myself instead of letting LWP do +it, but that's for later. Java has streaming facilities as well as +threading and is also somewhat portable. So I decided to be masochistic +and give it a go. But boy is Java bureaucratic. + +You will need a Java 1.4 JRE, because I use the java.nio classes; and +the commons-httpclient and commons-logging jars from the +jakarta.apache.org project. As I understand it, there are several ways +to get those jars on your classpath. One is to put it in the directory +where your java extensions jars are kept, normally +$JAVA_HOME/jre/lib/ext. But it may not be writable to you. Another is to +set your $CLASSPATH variable to have those jars in the path. A third is +to use the -cp option of the java interpreter, see the shell script +runT2hproxy for details. + +All the source is in one Java file. build.xml is a "Makefile" for ant to +compile and jar it. You should then edit runT2proxy.sh as required, then +start it. As with the Perl version, the prefix is what's prepended to +the filenames requested by the TFTP client, and the proxy is the +host:port string for the proxy if you are using one. On *ix you will +need root permission to listen on ports below 1024 (TFTP is at 69 UDP by +default). + +Currently it logs to stderr, but you can change this by downloading and +installing the log4j jar from jakarta.apache.org and instructing +commons-logging to use that, with a command line property setting and a +property file. Destinations could be syslog, or a file, or an event +logger, or...; it's supposedly very flexible. + +3. Licensing + +All this code is GPLed. For details read the file COPYING found in the +Etherboot top directory since it currently bundled with Etherboot. I +don't see the point of including COPYING in every directory. + +Ken Yap, October 2003 diff --git a/contrib/t2hproxy/T2hproxy.java b/contrib/t2hproxy/T2hproxy.java new file mode 100644 index 0000000..cfe1d1a --- /dev/null +++ b/contrib/t2hproxy/T2hproxy.java @@ -0,0 +1,508 @@ +/* + * TFTP to HTTP proxy in Java + * + * Copyright Ken Yap 2003 + * Released under GPL2 + */ +import java.io.IOException; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.BufferedInputStream; +import java.io.UnsupportedEncodingException; +import java.lang.String; +import java.lang.StringBuffer; +import java.lang.Thread; +import java.lang.NumberFormatException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.BufferUnderflowException; +import java.util.HashMap; +import java.util.Properties; + +import org.apache.commons.httpclient.Credentials; +import org.apache.commons.httpclient.Header; +import org.apache.commons.httpclient.HostConfiguration; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.HttpMethod; +import org.apache.commons.httpclient.UsernamePasswordCredentials; +import org.apache.commons.httpclient.methods.GetMethod; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Description of the Class + * + *@author ken + *@created 24 September 2003 + */ +public class T2hproxy implements Runnable { + /** + * Description of the Field + */ + public final static String NAME = T2hproxy.class.getName(); + /** + * Description of the Field + */ + public final static String VERSION = "0.1"; + /** + * Description of the Field + */ + public final static int MTU = 1500; + /** + * Description of the Field + */ + public final static short TFTP_RRQ = 1; + /** + * Description of the Field + */ + public final static short TFTP_DATA = 3; + /** + * Description of the Field + */ + public final static short TFTP_ACK = 4; + /** + * Description of the Field + */ + public final static short TFTP_ERROR = 5; + /** + * Description of the Field + */ + public final static short TFTP_OACK = 6; + /** + * Description of the Field + */ + public final static short ERR_NOFILE = 1; + /** + * Description of the Field + */ + public final static short ERR_ILLOP = 4; + /** + * Description of the Field + */ + public final static int MAX_RETRIES = 5; + /** + * TFTP timeout in milliseconds + */ + public final static int TFTP_ACK_TIMEOUT = 2000; + /** + * Description of the Field + */ + public final static int DEFAULT_PROXY_PORT = 3128; + + private static Log log = LogFactory.getLog(T2hproxy.class); + /** + * The members below must be per thread and must not share any storage with + * the main thread + */ + private DatagramSocket responsesocket; + private DatagramPacket response; + private InetAddress iaddr; + private int port; + private byte[] req; + private String prefix; + private String proxy = null; + private int timeout; + private HashMap options = new HashMap(); + private int blocksize = 512; + private HttpClient client = new HttpClient(); + private HttpMethod method; + private BufferedInputStream bstream = null; + private String message; + + + /** + * Constructor for the T2hproxy object + * + *@param i Description of the Parameter + *@param p Description of the Parameter + *@param b Description of the Parameter + *@param pf Description of the Parameter + *@param pr Description of the Parameter + *@param t Timeout for HTTP GET + */ + public T2hproxy(InetAddress i, int p, byte[] b, String pf, String pr, int t) { + iaddr = i; + port = p; + // make a copy of the request buffer + req = new byte[b.length]; + System.arraycopy(b, 0, req, 0, b.length); + prefix = pf; + // proxy can be null + proxy = pr; + timeout = t; + } + + + /** + * Extract an asciz string from bufer + * + *@param buffer Description of the Parameter + *@return The asciz value + */ + private String getAsciz(ByteBuffer buffer) { + StringBuffer s = new StringBuffer(); + try { + byte b; + while ((b = buffer.get()) != 0) { + s.append((char) b); + } + } catch (BufferUnderflowException e) { + } finally { + return (s.toString()); + } + } + + + /** + * Convert a string of digits to a number, invalid => 0 + * + *@param s Description of the Parameter + *@return Description of the Return Value + */ + private int atoi(String s) { + if (s == null) { + return (0); + } + int value = 0; + try { + value = (new Integer(s)).intValue(); + } catch (NumberFormatException e) { + } + return (value); + } + + + /** + * Wait for ack packet with timeout + * + *@return Return block number acked + */ + private int waitForAck() { + DatagramPacket ack = new DatagramPacket(new byte[MTU], MTU); + try { + do { + responsesocket.setSoTimeout(TFTP_ACK_TIMEOUT); + responsesocket.receive(ack); + } while (!ack.getAddress().equals(iaddr) || ack.getPort() != port); + } catch (SocketTimeoutException e) { + return (-1); + } catch (Exception e) { + log.info(e.toString(), e); + } + ByteBuffer buffer = ByteBuffer.wrap(ack.getData(), ack.getOffset(), ack.getLength() - ack.getOffset()); + short op; + if ((op = buffer.getShort()) == TFTP_ACK) { + return ((int) buffer.getShort()); + } else if (op == TFTP_ERROR) { + return (-2); + } + return (-3); + } + + + /** + * Description of the Method + * + *@param error Description of the Parameter + *@param message Description of the Parameter + */ + private void sendError(short error, String message) { + ByteBuffer buffer = ByteBuffer.wrap(response.getData()); + buffer.putShort(TFTP_ERROR).putShort(error).put(message.getBytes()); + response.setLength(buffer.position()); + try { + responsesocket.send(response); + } catch (Exception e) { + log.info(e.toString(), e); + } + } + + + /** + * Description of the Method + * + *@return Description of the Return Value + */ + private boolean sendOackRecvAck() { + ByteBuffer buffer = ByteBuffer.wrap(response.getData()); + buffer.putShort(TFTP_OACK).put("blksize".getBytes()).put((byte) 0).put(String.valueOf(blocksize).getBytes()).put((byte) 0); + response.setLength(buffer.position()); + int retry; + for (retry = 0; retry < MAX_RETRIES; retry++) { + try { + responsesocket.send(response); + } catch (Exception e) { + log.info(e.toString(), e); + } + if (waitForAck() == 0) { + log.debug("Ack received"); + break; + } + } + return (retry < MAX_RETRIES); + } + + + /** + * Description of the Method + * + *@param block Description of the Parameter + *@return Description of the Return Value + */ + private boolean sendDataBlock(int block) { + int retry; + for (retry = 0; retry < MAX_RETRIES; retry++) { + try { + responsesocket.send(response); + } catch (Exception e) { + log.info(e.toString(), e); + } + int ablock; + if ((ablock = waitForAck()) == block) { + log.debug("Ack received for " + ablock); + break; + } else if (ablock == -1) { + log.info("Timeout waiting for ack"); + } else if (ablock == -2) { + return (false); + } else { + log.info("Unknown opcode from ack"); + } + } + return (retry < MAX_RETRIES); + } + + + /** + * Description of the Method + * + *@param buffer Description of the Parameter + *@return Description of the Return Value + */ + private boolean handleOptions(ByteBuffer buffer) { + for (; ; ) { + String option = getAsciz(buffer); + String value = getAsciz(buffer); + if (option.equals("") || value.equals("")) { + break; + } + log.info(option + " " + value); + options.put(option, value); + } + blocksize = atoi((String) options.get("blksize")); + if (blocksize < 512) { + blocksize = 512; + } + if (blocksize > 1432) { + blocksize = 1432; + } + return (sendOackRecvAck()); + } + + + /** + * Description of the Method + * + *@param url Description of the Parameter + */ + private void makeStream(String url) { + // establish a connection within timeout milliseconds + client.setConnectionTimeout(timeout); + if (proxy != null) { + String[] hostport = proxy.split(":"); + int port = DEFAULT_PROXY_PORT; + if (hostport.length > 1) { + port = atoi(hostport[1]); + if (port == 0) { + port = DEFAULT_PROXY_PORT; + } + } + log.info("Proxy is " + hostport[0] + ":" + port); + client.getHostConfiguration().setProxy(hostport[0], port); + } + // create a method object + method = new GetMethod(url); + method.setFollowRedirects(true); + method.setStrictMode(false); + try { + int status; + if ((status = client.executeMethod(method)) != 200) { + log.info(message = method.getStatusText()); + return; + } + bstream = new BufferedInputStream(method.getResponseBodyAsStream()); + } catch (HttpException he) { + message = he.getMessage(); + } catch (IOException ioe) { + message = "Unable to get " + url; + } + } + + + /** + * Reads a block of data from URL stream + * + *@param stream Description of the Parameter + *@param data Description of the Parameter + *@param blocksize Description of the Parameter + *@param offset Description of the Parameter + *@return Number of bytes read + */ + private int readBlock(BufferedInputStream stream, byte[] data, int offset, int blocksize) { + int status; + int nread = 0; + while (nread < blocksize) { + try { + status = stream.read(data, offset + nread, blocksize - nread); + } catch (Exception e) { + return (-1); + } + if (status < 0) { + return (nread); + } + nread += status; + } + return (nread); + } + + + /** + * Description of the Method + * + *@param filename Description of the Parameter + */ + private void doRrq(String filename) { + String url = prefix + filename; + log.info("GET " + url); + makeStream(url); + if (bstream == null) { + log.info(message); + sendError(ERR_NOFILE, message); + return; + } + // read directly into send buffer to avoid buffer copying + byte[] data; + ByteBuffer buffer = ByteBuffer.wrap(data = response.getData()); + // dummy puts to get start position of data + buffer.putShort(TFTP_DATA).putShort((short) 0); + int start = buffer.position(); + int length; + int block = 1; + do { + length = readBlock(bstream, data, start, blocksize); + block &= 0xffff; + log.debug("Block " + block + " " + length); + // fill in the block number + buffer.position(0); + buffer.putShort(TFTP_DATA).putShort((short) block); + response.setLength(start + length); + if (!sendDataBlock(block)) { + break; + } + buffer.position(start); + block++; + } while (length >= blocksize); + log.info("Closing TFTP session"); + // clean up the connection resources + method.releaseConnection(); + method.recycle(); + } + + + /** + * Main processing method for the T2hproxy object + */ + public void run() { + ByteBuffer buffer = ByteBuffer.wrap(req); + buffer.getShort(); + String filename = getAsciz(buffer); + String mode = getAsciz(buffer); + log.info(filename + " " + mode); + response = new DatagramPacket(new byte[MTU], MTU, iaddr, port); + try { + responsesocket = new DatagramSocket(); + } catch (SocketException e) { + log.info(e.toString(), e); + return; + } + if (!handleOptions(buffer)) { + return; + } + doRrq(filename); + } + + + /** + * Description of the Method + * + *@param s Description of the Parameter + *@param r Description of the Parameter + *@param prefix Description of the Parameter + *@param proxy Description of the Parameter + *@param timeout Description of the Parameter + */ + public static void handleRequest(DatagramSocket s, DatagramPacket r, String prefix, String proxy, int timeout) { + log.info("Connection from " + r.getAddress().getCanonicalHostName() + ":" + r.getPort()); + ByteBuffer buffer = ByteBuffer.wrap(r.getData(), r.getOffset(), r.getLength() - r.getOffset()); + if (buffer.getShort() != TFTP_RRQ) { + DatagramPacket error = new DatagramPacket(new byte[MTU], MTU); + ByteBuffer rbuf = ByteBuffer.wrap(error.getData()); + rbuf.putShort(TFTP_ERROR).putShort(ERR_ILLOP).put("Illegal operation".getBytes()); + error.setLength(rbuf.position()); + try { + s.send(error); + } catch (Exception e) { + log.info(e.toString(), e); + } + return; + } + // fork thread + new Thread(new T2hproxy(r.getAddress(), r.getPort(), r.getData(), prefix, proxy, timeout)).start(); + } + + + /** + * The main program for the T2hproxy class + * + *@param argv The command line arguments + *@exception IOException Description of the Exception + */ + public static void main(String[] argv) throws IOException { + log.info(T2hproxy.NAME + "." + T2hproxy.VERSION); + int port = Integer.getInteger(T2hproxy.NAME + ".port", 69).intValue(); + String prefix = System.getProperty(T2hproxy.NAME + ".prefix", "http://localhost/"); + String proxy = System.getProperty(T2hproxy.NAME + ".proxy"); + int timeout = Integer.getInteger(T2hproxy.NAME + ".timeout", 5000).intValue(); + String propfile = System.getProperty(T2hproxy.NAME + ".properties"); + if (propfile != null) { + FileInputStream pf = new FileInputStream(propfile); + Properties p = new Properties(System.getProperties()); + p.load(pf); + // set the system properties + System.setProperties(p); + } + DatagramSocket requestsocket; + try { + requestsocket = new DatagramSocket(port); + } catch (SocketException e) { + log.info(e.toString(), e); + return; + } + DatagramPacket request = new DatagramPacket(new byte[MTU], MTU); + for (; ; ) { + try { + requestsocket.receive(request); + handleRequest(requestsocket, request, prefix, proxy, timeout); + } catch (Exception e) { + log.info(e.toString(), e); + } + } + } +} diff --git a/contrib/t2hproxy/build.xml b/contrib/t2hproxy/build.xml new file mode 100644 index 0000000..5494ab9 --- /dev/null +++ b/contrib/t2hproxy/build.xml @@ -0,0 +1,19 @@ +<?xml version="1.0"?> +<!-- + Build file for T2hproxy +--> +<project name="T2hproxy" default="jar" basedir="."> + <target name="compile"> + <javac fork="true" srcdir="." destdir="." /> + </target> + + <target name="jar" depends="compile"> + <jar jarfile="T2hproxy.jar" basedir="." + includes="T2hproxy.class"> + <manifest> + <attribute name="Main-Class" value="T2hproxy" /> + </manifest> + </jar> + </target> +</project> + diff --git a/contrib/t2hproxy/runT2proxy.sh b/contrib/t2hproxy/runT2proxy.sh new file mode 100755 index 0000000..d7fc0d2 --- /dev/null +++ b/contrib/t2hproxy/runT2proxy.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +# If the httpclient and logging jars are not in the standard directories +# edit and uncomment +# CP='-cp /usr/local/lib/commons-httpclient-2.0-rc1.jar:/usr/local/lib/commons-logging-api.jar:/usr/local/lib/commons-logging.jar' + +# Edit and uncomment to use an alternate port +# PORT='-DT2hproxy.port=1069' +PREFIX='-DT2hproxy.prefix=http://localhost/' +# Edit and uncomment to use a proxy +# PROXY='-DT2hproxy.proxy=localhost:3128' +# These T2hproxy properties can be put in a file and read in all at once +# PROPERTIES='-DT2hproxy.properties=t2hproxy.prop + +exec java -jar $CP $PORT $PREFIX $PROXY $PROPERTIES T2hproxy.jar diff --git a/contrib/t2hproxy/t2hproxy.pl b/contrib/t2hproxy/t2hproxy.pl new file mode 100755 index 0000000..4fc0178 --- /dev/null +++ b/contrib/t2hproxy/t2hproxy.pl @@ -0,0 +1,174 @@ +#!/usr/bin/perl -w +# +# tftp to http proxy +# Copyright 2003 Ken Yap +# Released under GPL2 +# + +require 5.8.0; # needs constant and the pack Z format behaviour + +use bytes; # to forestall Unicode interpretation of strings +use strict; + +use Getopt::Long; +use Socket; +use Sys::Hostname; +use Sys::Syslog; +use LWP; +use POSIX 'setsid'; + +use constant PROGNAME => 't2hproxy'; +use constant VERSION => '0.1'; + +use constant ETH_DATA_LEN => 1500; +use constant { + TFTP_RRQ => 1, TFTP_WRQ => 2, TFTP_DATA => 3, TFTP_ACK => 4, + TFTP_ERROR => 5, TFTP_OACK => 6 +}; +use constant { + E_UNDEF => 0, E_FNF => 1, E_ACC => 2, E_DISK => 3, E_ILLOP => 4, + E_UTID => 5, E_FEXIST => 6, E_NOUSER => 7 +}; + +use vars qw($prefix $proxy $sockh $timeout %options $tsize $bsize); + +# We can't use die because xinetd will think something's wrong +sub log_and_exit ($) { + syslog('info', $_[0]); + exit; +} + +sub what_source ($) { + my ($port, $saddr) = sockaddr_in($_[0]); + my $host = gethostbyaddr($saddr, AF_INET); + return ($host, $port); +} + +sub send_error ($$$) { + my ($iaddr, $error, $message) = @_; + # error packets don't get acked + send(STDOUT, pack('nna*', TFTP_ERROR, $error, $message), 0, $iaddr); +} + +sub send_ack_retry ($$$$$) { + my ($iaddr, $udptimeout, $maxretries, $blockno, $sendfunc) = @_; +RETRY: + while ($maxretries-- > 0) { + &$sendfunc; + my $rin = ''; + my $rout = ''; + vec($rin, fileno($sockh), 1) = 1; + do { + my ($fds, $timeleft) = select($rout = $rin, undef, undef, $udptimeout); + last if ($fds <= 0); + my $ack; + my $theiripaddr = recv($sockh, $ack, 256, 0); + # check it's for us + if ($theiripaddr eq $iaddr) { + my ($opcode, $ackblock) = unpack('nn', $ack); + return (0) if ($opcode == TFTP_ERROR); + # check that the right block was acked + if ($ackblock == $blockno) { + return (1); + } else { + syslog('info', "Resending block $blockno"); + next RETRY; + } + } + # stray packet for some other server instance + send_error($theiripaddr, E_UTID, 'Wrong TID'); + } while (1); + } + return (0); +} + +sub handle_options ($$) { + my ($iaddr, $operand) = @_; + while ($operand ne '') { + my ($key, $value) = unpack('Z*Z*', $operand); + $options{$key} = $value; + syslog('info', "$key=$value"); + $operand = substr($operand, length($key) + length($value) + 2); + } + my $optstr = ''; + if (exists($options{blksize})) { + $bsize = $options{blksize}; + $bsize = 512 if ($bsize < 512); + $bsize = 1432 if ($bsize > 1432); + $optstr .= pack('Z*Z*', 'blksize', $bsize . ''); + } + # OACK expects an ack for block 0 + log_and_exit('Abort received or retransmit limit reached, exiting') + unless send_ack_retry($iaddr, 2, 5, 0, + sub { send($sockh, pack('na*', TFTP_OACK, $optstr), 0, $iaddr); }); +} + +sub http_get ($) { + my ($url) = @_; + syslog('info', "GET $url"); + my $ua = LWP::UserAgent->new; + $ua->timeout($timeout); + $ua->proxy(['http', 'ftp'], $proxy) if (defined($proxy) and $proxy); + my $req = HTTP::Request->new(GET => $url); + my $res = $ua->request($req); + return ($res->is_success, $res->status_line, $res->content_ref); +} + +sub send_file ($$) { + my ($iaddr, $contentref) = @_; + my $blockno = 1; + my $data; + do { + $blockno &= 0xffff; + $data = substr($$contentref, ($blockno - 1) * $bsize, $bsize); + # syslog('info', "Block $blockno length " . length($data)); + log_and_exit('Abort received or retransmit limit reached, exiting') + unless send_ack_retry($iaddr, 2, 5, $blockno, + sub { send($sockh, pack('nna*', TFTP_DATA, $blockno, $data), 0, $iaddr); }); + $blockno++; + } while (length($data) >= $bsize); +} + +sub do_rrq ($$) { + my ($iaddr, $packetref) = @_; + # fork and handle request in child so that *inetd can continue + # to serve incoming requests + defined(my $pid = fork) or log_and_exit("Can't fork: $!"); + exit if $pid; # parent exits + setsid or log_and_exit("Can't start a new session: $!"); + socket(SOCK, PF_INET, SOCK_DGRAM, getprotobyname('udp')) or log_and_exit('Cannot create UDP socket'); + $sockh = *SOCK{IO}; + my ($opcode, $operand) = unpack('na*', $$packetref); + my ($filename, $mode) = unpack('Z*Z*', $operand); + syslog('info', "RRQ $filename $mode"); + my $length = length($filename) + length($mode) + 2; + $operand = substr($operand, $length); + handle_options($iaddr, $operand) if ($operand ne ''); + my ($success, $status_line, $result) = http_get($prefix . $filename); + syslog('info', $status_line); + if ($success) { + send_file($iaddr, $result); + } else { + send_error($iaddr, E_FNF, $status_line); + } +} + +$prefix = 'http://localhost/'; +$timeout = 60; +GetOptions('prefix=s' => \$prefix, + 'proxy=s' => \$proxy, + 'timeout=i' => \$timeout); +$bsize = 512; +openlog(PROGNAME, 'cons,pid', 'user'); +syslog('info', PROGNAME . ' version ' . VERSION); +my $packet; +my $theiriaddr = recv(STDIN, $packet, ETH_DATA_LEN, 0); +my ($host, $port) = what_source($theiriaddr); +syslog('info', "Connection from $host:$port"); +my $opcode = unpack('n', $packet); +if ($opcode == TFTP_RRQ) { + do_rrq($theiriaddr, \$packet); +} else { # anything else is an error + send_error($theiriaddr, E_ILLOP, 'Illegal operation'); +} +exit 0; diff --git a/contrib/t2hproxy/t2hproxy.xinetd b/contrib/t2hproxy/t2hproxy.xinetd new file mode 100644 index 0000000..ea6a03f --- /dev/null +++ b/contrib/t2hproxy/t2hproxy.xinetd @@ -0,0 +1,29 @@ +# Description: tftp to http proxy +# A sample config file for xinetd, edit and put in /etc/xinetd.d +# then killall -HUP xinetd, or restart xinetd + +service t2hproxy +{ + type = UNLISTED + id = t2hproxy + socket_type = dgram + protocol = udp +# +# The pathname to where you have installed it +# + server = /usr/local/sbin/t2hproxy.pl +# +# If your filenames don't start with /, then the trailing +# slash is needed +# + server_args = --prefix http://localhost/ +# +# --proxy http://proxyhost:3128/ can also be appended +# + log_type = FILE /var/log/t2hproxy.log + user = nobody + wait = yes + instances = 10 + disable = no + port = 69 +} diff --git a/contrib/tftp/Makefile b/contrib/tftp/Makefile new file mode 100644 index 0000000..bd427cd --- /dev/null +++ b/contrib/tftp/Makefile @@ -0,0 +1,56 @@ +# +# Copyright (c) 1987 Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms are permitted +# provided that the above copyright notice and this paragraph are +# duplicated in all such forms and that any documentation, +# advertising materials, and other materials related to such +# distribution and use acknowledge that the software was developed +# by the University of California, Berkeley. The name of the +# University may not be used to endorse or promote products derived +# from this software without specific prior written permission. +# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +# +# @(#)Makefile 5.8 (Berkeley) 9/20/88 +# +# We override /usr/include/arpa/tftp.h with our own because +# we want tu_block to be unsigned short, not short as on most platforms +# +CFLAGS= -I. -O2 -Dsin=sin_x +SRCS= main.c tftp.c tftpsubs.c tftpd.c +OBJS= main.o tftp.o tftpsubs.o +DOBJS= tftpd.o tftpsubs.o +CC= gcc +LIBS= # -linet + +all: tftp tftpd + +tftp: ${OBJS} + ${CC} -o $@ ${CFLAGS} ${OBJS} # -linet + +tftpd: ${DOBJS} + ${CC} -o $@ ${CFLAGS} ${DOBJS} ${LIBS} + +clean: + rm -f ${OBJS} ${DOBJS} core tftp tftpd + +cleandir: clean + rm -f tags .depend + +depend: ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +install: + install -s -o root -g root -m 755 tftp /usr/bin/tftp + install -c -o root -g root -m 444 tftp.1 /usr/man/man1 + install -s -o root -g root -m 755 tftpd /usr/sbin/in.tftpd + install -c -o root -g root -m 444 tftpd.8 /usr/man/man8 + +lint: ${SRCS} + lint ${CFLAGS} ${SRCS} + +tags: ${SRCS} + ctags ${SRCS} diff --git a/contrib/tftp/README b/contrib/tftp/README new file mode 100644 index 0000000..e495720 --- /dev/null +++ b/contrib/tftp/README @@ -0,0 +1,28 @@ +This is a copy of the TFTP client as available from +ftp://sunsite.unc.edu/pub/linux/system/Network/file-transfer; I +modified the code, so that it understands RFC1782 and RFC1783 +extensions to the TFTP protocol. This allows for negotating an +extended transfer block size of up to 1432 bytes (as oppossed to the +standard 512 bytes). On busy networks, this will result in +considerably improved throughput and less load on the network. + +For further information and for licensing conditions, please have a +look at the header of the source files. + +Markus Gutschke <gutschk@math.uni-muenster.de> + +This is a copy of the TFTP server as available from +ftp://sunsite.unc.edu/pub/linux/system/Network/file-transfer; I +modified the code, so that it understands RFC1782 and RFC1783 +extensions to the TFTP protocol. This allows for negotating an +extended transfer block size of up to 1432 bytes (as oppossed to the +standard 512 bytes). On busy networks, this will result in +considerably improved throughput and less load on the network. + +I also added two command line options for changing the root directory +and for enabling debugging output. + +For further information and for licensing conditions, please have a +look at the header of the source files. + +Markus Gutschke <gutschk@math.uni-muenster.de> diff --git a/contrib/tftp/arpa/tftp.h b/contrib/tftp/arpa/tftp.h new file mode 100644 index 0000000..0904407 --- /dev/null +++ b/contrib/tftp/arpa/tftp.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tftp.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef _ARPA_TFTP_H +#define _ARPA_TFTP_H 1 + +/* + * Trivial File Transfer Protocol (IEN-133) + */ +#define SEGSIZE 512 /* data segment size */ + +/* + * Packet types. + */ +#define RRQ 01 /* read request */ +#define WRQ 02 /* write request */ +#define DATA 03 /* data packet */ +#define ACK 04 /* acknowledgement */ +#define ERROR 05 /* error code */ + +struct tftphdr { + short th_opcode; /* packet type */ + union { + unsigned short tu_block; /* block # */ + short tu_code; /* error code */ + char tu_stuff[1]; /* request packet stuff */ + } th_u; + char th_data[1]; /* data or error string */ +}; + +#define th_block th_u.tu_block +#define th_code th_u.tu_code +#define th_stuff th_u.tu_stuff +#define th_msg th_data + +/* + * Error codes. + */ +#define EUNDEF 0 /* not defined */ +#define ENOTFOUND 1 /* file not found */ +#define EACCESS 2 /* access violation */ +#define ENOSPACE 3 /* disk full or allocation exceeded */ +#define EBADOP 4 /* illegal TFTP operation */ +#define EBADID 5 /* unknown transfer ID */ +#define EEXISTS 6 /* file already exists */ +#define ENOUSER 7 /* no such user */ + +#endif /* arpa/tftp.h */ diff --git a/contrib/tftp/main.c b/contrib/tftp/main.c new file mode 100644 index 0000000..ca4427a --- /dev/null +++ b/contrib/tftp/main.c @@ -0,0 +1,684 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1983 Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 5.8 (Berkeley) 10/11/88"; +#endif /* not lint */ + +/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ + +/* + * TFTP User Program -- Command Interface. + */ +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/file.h> + +#include <netinet/in.h> + +#include <signal.h> +#include <stdio.h> +#include <errno.h> +#include <setjmp.h> +#include <ctype.h> +#include <netdb.h> + +#define TIMEOUT 5 /* secs between rexmt's */ + +struct sockaddr_in sin; +int f; +short port; +int trace; +int verbose; +int connected; +char mode[32]; +char line[200]; +int margc; +char *margv[20]; +char *prompt = "tftp"; +jmp_buf toplevel; +void intr(int); +struct servent *sp; + +int segsize = 512; + +int quit(), help(), setverbose(), settrace(), status(); +int get(), put(), setpeer(), modecmd(), setrexmt(), settimeout(); +int setbinary(), setascii(), setblocksize(); + +#define HELPINDENT (sizeof("connect")) + +struct cmd { + char *name; + char *help; + int (*handler)(); +}; + +char vhelp[] = "toggle verbose mode"; +char thelp[] = "toggle packet tracing"; +char chelp[] = "connect to remote tftp"; +char qhelp[] = "exit tftp"; +char hhelp[] = "print help information"; +char shelp[] = "send file"; +char rhelp[] = "receive file"; +char mhelp[] = "set file transfer mode"; +char sthelp[] = "show current status"; +char xhelp[] = "set per-packet retransmission timeout"; +char ihelp[] = "set total retransmission timeout"; +char ashelp[] = "set mode to netascii"; +char bnhelp[] = "set mode to octet"; +char bshelp[] = "set blocksize for next transfer"; + +struct cmd cmdtab[] = { + { "connect", chelp, setpeer }, + { "mode", mhelp, modecmd }, + { "put", shelp, put }, + { "get", rhelp, get }, + { "quit", qhelp, quit }, + { "verbose", vhelp, setverbose }, + { "trace", thelp, settrace }, + { "status", sthelp, status }, + { "binary", bnhelp, setbinary }, + { "ascii", ashelp, setascii }, + { "rexmt", xhelp, setrexmt }, + { "timeout", ihelp, settimeout }, + { "blocksize", bshelp, setblocksize }, + { "?", hhelp, help }, + 0 +}; + +struct cmd *getcmd(); +char *tail(); +char *index(); +char *rindex(); + +main(argc, argv) + char *argv[]; +{ + struct sockaddr_in sin; + int top; + + sp = getservbyname("tftp", "udp"); + if (sp == 0) { + fprintf(stderr, "tftp: udp/tftp: unknown service\n"); + exit(1); + } + f = socket(AF_INET, SOCK_DGRAM, 0); + if (f < 0) { + perror("tftp: socket"); + exit(3); + } + bzero((char *)&sin, sizeof (sin)); + sin.sin_family = AF_INET; + if (bind(f, (struct sockaddr *)&sin, sizeof (sin)) < 0) { + perror("tftp: bind"); + exit(1); + } + strcpy(mode, "netascii"); + signal(SIGINT, intr); + if (argc > 1) { + if (setjmp(toplevel) != 0) + exit(0); + setpeer(argc, argv); + } + top = setjmp(toplevel) == 0; + for (;;) + command(top); +} + +char hostname[100]; + +setpeer(argc, argv) + int argc; + char *argv[]; +{ + struct hostent *host; + + if (argc < 2) { + strcpy(line, "Connect "); + printf("(to) "); + fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin); + makeargv(); + argc = margc; + argv = margv; + } + if (argc > 3) { + printf("usage: %s host-name [port]\n", argv[0]); + return; + } + host = gethostbyname(argv[1]); + if (host) { + sin.sin_family = host->h_addrtype; + bcopy(host->h_addr, &sin.sin_addr, host->h_length); + strcpy(hostname, host->h_name); + } else { + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = inet_addr(argv[1]); + if (sin.sin_addr.s_addr == -1) { + connected = 0; + printf("%s: unknown host\n", argv[1]); + return; + } + strcpy(hostname, argv[1]); + } + port = sp->s_port; + if (argc == 3) { + port = atoi(argv[2]); + if (port < 0) { + printf("%s: bad port number\n", argv[2]); + connected = 0; + return; + } + port = htons(port); + } + connected = 1; +} + +struct modes { + char *m_name; + char *m_mode; +} modes[] = { + { "ascii", "netascii" }, + { "netascii", "netascii" }, + { "binary", "octet" }, + { "image", "octet" }, + { "octet", "octet" }, +/* { "mail", "mail" }, */ + { 0, 0 } +}; + +modecmd(argc, argv) + char *argv[]; +{ + register struct modes *p; + char *sep; + + if (argc < 2) { + printf("Using %s mode to transfer files.\n", mode); + return; + } + if (argc == 2) { + for (p = modes; p->m_name; p++) + if (strcmp(argv[1], p->m_name) == 0) + break; + if (p->m_name) { + setmode(p->m_mode); + return; + } + printf("%s: unknown mode\n", argv[1]); + /* drop through and print usage message */ + } + + printf("usage: %s [", argv[0]); + sep = " "; + for (p = modes; p->m_name; p++) { + printf("%s%s", sep, p->m_name); + if (*sep == ' ') + sep = " | "; + } + printf(" ]\n"); + return; +} + +setbinary(argc, argv) +char *argv[]; +{ setmode("octet"); +} + +setascii(argc, argv) +char *argv[]; +{ setmode("netascii"); +} + +setmode(newmode) +char *newmode; +{ + strcpy(mode, newmode); + if (verbose) + printf("mode set to %s\n", mode); +} + + +/* + * Send file(s). + */ +put(argc, argv) + char *argv[]; +{ + int fd; + register int n; + register char *cp, *targ; + + if (argc < 2) { + strcpy(line, "send "); + printf("(file) "); + fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin); + makeargv(); + argc = margc; + argv = margv; + } + if (argc < 2) { + putusage(argv[0]); + return; + } + targ = argv[argc - 1]; + if (index(argv[argc - 1], ':')) { + char *cp; + struct hostent *hp; + + for (n = 1; n < argc - 1; n++) + if (index(argv[n], ':')) { + putusage(argv[0]); + return; + } + cp = argv[argc - 1]; + targ = index(cp, ':'); + *targ++ = 0; + hp = gethostbyname(cp); + if (hp == NULL) { + fprintf(stderr, "tftp: %s: ", cp); + herror((char *)NULL); + return; + } + bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length); + sin.sin_family = hp->h_addrtype; + connected = 1; + strcpy(hostname, hp->h_name); + } + if (!connected) { + printf("No target machine specified.\n"); + return; + } + if (argc < 4) { + cp = argc == 2 ? tail(targ) : argv[1]; + fd = open(cp, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "tftp: "); perror(cp); + return; + } + if (verbose) + printf("putting %s to %s:%s [%s]\n", + cp, hostname, targ, mode); + sin.sin_port = port; + sendfile(fd, targ, mode); + return; + } + /* this assumes the target is a directory */ + /* on a remote unix system. hmmmm. */ + cp = index(targ, '\0'); + *cp++ = '/'; + for (n = 1; n < argc - 1; n++) { + strcpy(cp, tail(argv[n])); + fd = open(argv[n], O_RDONLY); + if (fd < 0) { + fprintf(stderr, "tftp: "); perror(argv[n]); + continue; + } + if (verbose) + printf("putting %s to %s:%s [%s]\n", + argv[n], hostname, targ, mode); + sin.sin_port = port; + sendfile(fd, targ, mode); + } +} + +putusage(s) + char *s; +{ + printf("usage: %s file ... host:target, or\n", s); + printf(" %s file ... target (when already connected)\n", s); +} + +/* + * Receive file(s). + */ +get(argc, argv) + char *argv[]; +{ + int fd; + register int n; + register char *cp; + char *src; + + if (argc < 2) { + strcpy(line, "get "); + printf("(files) "); + fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin); + makeargv(); + argc = margc; + argv = margv; + } + if (argc < 2) { + getusage(argv[0]); + return; + } + if (!connected) { + for (n = 1; n < argc ; n++) + if (index(argv[n], ':') == 0) { + getusage(argv[0]); + return; + } + } + for (n = 1; n < argc ; n++) { + src = index(argv[n], ':'); + if (src == NULL) + src = argv[n]; + else { + struct hostent *hp; + + *src++ = 0; + hp = gethostbyname(argv[n]); + if (hp == NULL) { + fprintf(stderr, "tftp: %s: ", argv[n]); + herror((char *)NULL); + continue; + } + bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length); + sin.sin_family = hp->h_addrtype; + connected = 1; + strcpy(hostname, hp->h_name); + } + if (argc < 4) { + cp = argc == 3 ? argv[2] : tail(src); + fd = creat(cp, 0644); + if (fd < 0) { + fprintf(stderr, "tftp: "); perror(cp); + return; + } + if (verbose) + printf("getting from %s:%s to %s [%s]\n", + hostname, src, cp, mode); + sin.sin_port = port; + recvfile(fd, src, mode); + break; + } + cp = tail(src); /* new .. jdg */ + fd = creat(cp, 0644); + if (fd < 0) { + fprintf(stderr, "tftp: "); perror(cp); + continue; + } + if (verbose) + printf("getting from %s:%s to %s [%s]\n", + hostname, src, cp, mode); + sin.sin_port = port; + recvfile(fd, src, mode); + } +} + +getusage(s) +char * s; +{ + printf("usage: %s host:file host:file ... file, or\n", s); + printf(" %s file file ... file if connected\n", s); +} + +int rexmtval = TIMEOUT; + +setrexmt(argc, argv) + char *argv[]; +{ + int t; + + if (argc < 2) { + strcpy(line, "Rexmt-timeout "); + printf("(value) "); + fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin); + makeargv(); + argc = margc; + argv = margv; + } + if (argc != 2) { + printf("usage: %s value\n", argv[0]); + return; + } + t = atoi(argv[1]); + if (t < 0) + printf("%d: bad value\n", t); + else + rexmtval = t; +} + +int maxtimeout = 5 * TIMEOUT; + +settimeout(argc, argv) + char *argv[]; +{ + int t; + + if (argc < 2) { + strcpy(line, "Maximum-timeout "); + printf("(value) "); + fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin); + makeargv(); + argc = margc; + argv = margv; + } + if (argc != 2) { + printf("usage: %s value\n", argv[0]); + return; + } + t = atoi(argv[1]); + if (t < 0) + printf("%d: bad value\n", t); + else + maxtimeout = t; +} + +status(argc, argv) + char *argv[]; +{ + if (connected) + printf("Connected to %s.\n", hostname); + else + printf("Not connected.\n"); + printf("Mode: %s Verbose: %s Tracing: %s\n", mode, + verbose ? "on" : "off", trace ? "on" : "off"); + printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n", + rexmtval, maxtimeout); +} + +void intr(int sig) +{ + signal(SIGALRM, SIG_IGN); + alarm(0); + longjmp(toplevel, -1); +} + +char * +tail(filename) + char *filename; +{ + register char *s; + + while (*filename) { + s = rindex(filename, '/'); + if (s == NULL) + break; + if (s[1]) + return (s + 1); + *s = '\0'; + } + return (filename); +} + +/* + * Command parser. + */ +command(top) + int top; +{ + register struct cmd *c; + + if (!top) + putchar('\n'); + for (;;) { + printf("%s> ", prompt); + if (fgets(line, sizeof(line), stdin) == 0) { + if (feof(stdin)) { + quit(); + } else { + continue; + } + } + if (line[0] == 0) + continue; + makeargv(); + c = getcmd(margv[0]); + if (c == (struct cmd *)-1) { + printf("?Ambiguous command\n"); + continue; + } + if (c == 0) { + printf("?Invalid command\n"); + continue; + } + (*c->handler)(margc, margv); + } +} + +struct cmd * +getcmd(name) + register char *name; +{ + register char *p, *q; + register struct cmd *c, *found; + register int nmatches, longest; + + longest = 0; + nmatches = 0; + found = 0; + for (c = cmdtab; p = c->name; c++) { + for (q = name; *q == *p++; q++) + if (*q == 0) /* exact match? */ + return (c); + if (!*q) { /* the name was a prefix */ + if (q - name > longest) { + longest = q - name; + nmatches = 1; + found = c; + } else if (q - name == longest) + nmatches++; + } + } + if (nmatches > 1) + return ((struct cmd *)-1); + return (found); +} + +/* + * Slice a string up into argc/argv. + */ +makeargv() +{ + register char *cp; + register char **argp = margv; + + margc = 0; + for (cp = line; *cp;) { + while (isspace(*cp)) + cp++; + if (*cp == '\0') + break; + *argp++ = cp; + margc += 1; + while (*cp != '\0' && !isspace(*cp)) + cp++; + if (*cp == '\0') + break; + *cp++ = '\0'; + } + *argp++ = 0; +} + +/*VARARGS*/ +quit() +{ + exit(0); +} + +/* + * Help command. + */ +help(argc, argv) + int argc; + char *argv[]; +{ + register struct cmd *c; + + if (argc == 1) { + printf("Commands may be abbreviated. Commands are:\n\n"); + for (c = cmdtab; c->name; c++) + printf("%-*s\t%s\n", HELPINDENT, c->name, c->help); + return; + } + while (--argc > 0) { + register char *arg; + arg = *++argv; + c = getcmd(arg); + if (c == (struct cmd *)-1) + printf("?Ambiguous help command %s\n", arg); + else if (c == (struct cmd *)0) + printf("?Invalid help command %s\n", arg); + else + printf("%s\n", c->help); + } +} + +/*VARARGS*/ +settrace() +{ + trace = !trace; + printf("Packet tracing %s.\n", trace ? "on" : "off"); +} + +/*VARARGS*/ +setverbose() +{ + verbose = !verbose; + printf("Verbose mode %s.\n", verbose ? "on" : "off"); +} + +setblocksize(argc, argv) + char *argv[]; +{ + int t; + + if (argc < 2) { + strcpy(line, "blocksize "); + printf("(value) "); + fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin); + makeargv(); + argc = margc; + argv = margv; + } + if (argc != 2) { + printf("usage: %s value\n", argv[0]); + return; + } + t = atoi(argv[1]); + if (t < 8 || t > 1432) + printf("%d: bad value\n", t); + else + segsize = t; +} diff --git a/contrib/tftp/tftp.1 b/contrib/tftp/tftp.1 new file mode 100644 index 0000000..fc235b2 --- /dev/null +++ b/contrib/tftp/tftp.1 @@ -0,0 +1,159 @@ +.\" Copyright (c) 1986 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms are permitted +.\" provided that the above copyright notice and this paragraph are +.\" duplicated in all such forms and that any documentation, +.\" advertising materials, and other materials related to such +.\" distribution and use acknowledge that the software was developed +.\" by the University of California, Berkeley. The name of the +.\" University may not be used to endorse or promote products derived +.\" from this software without specific prior written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.\" @(#)tftp.1 5.3 (Berkeley) 9/20/88 +.\" +.TH TFTP 1 "September 20, 1988" +.UC 6 +.SH NAME +tftp \- trivial file transfer program +.SH SYNOPSIS +.B tftp +[ +host +] +.SH DESCRIPTION +.I Tftp +is the user interface to the Internet TFTP +(Trivial File Transfer Protocol), +which allows users to transfer files to and from a remote machine. +The remote +.I host +may be specified on the command line, in which case +.I tftp +uses +.I host +as the default host for future transfers (see the +.B connect +command below). +.SH COMMANDS +Once +.I tftp +is running, it issues the prompt +.B tftp> +and recognizes the following commands: +.TP +\fBconnect\fP \fIhost-name\fP [ \fIport\fP ] +Set the +.I host +(and optionally +.IR port ) +for transfers. +Note that the TFTP protocol, unlike the FTP protocol, +does not maintain connections betweeen transfers; thus, the +.I connect +command does not actually create a connection, +but merely remembers what host is to be used for transfers. +You do not have to use the +.I connect +command; the remote host can be specified as part of the +.I get +or +.I put +commands. +.TP +\fBmode\fP \fItransfer-mode\fP +Set the mode for transfers; +.I transfer-mode +may be one of +.IR ascii +or +.IR binary . +The default is +.IR ascii . +.TP +\fBput\fP \fIfile\fP +.ns +.TP +\fBput\fP \fIlocalfile remotefile\fP +.ns +.TP +\fBput\fP \fIfile1 file2 ... fileN remote-directory\fP +Put a file or set of files to the specified +remote file or directory. +The destination +can be in one of two forms: +a filename on the remote host, if the host has already been specified, +or a string of the form +.I host:filename +to specify both a host and filename at the same time. +If the latter form is used, +the hostname specified becomes the default for future transfers. +If the remote-directory form is used, the remote host is +assumed to be a +.I UNIX +machine. +.TP +\fBget\fP \fIfilename\fP +.ns +.TP +\fBget\fP \fIremotename\fP \fIlocalname\fP +.ns +.TP +\fBget\fP \fIfile1\fP \fIfile2\fP ... \fIfileN\fP +Get a file or set of files from the specified +.IR sources . +.I Source +can be in one of two forms: +a filename on the remote host, if the host has already been specified, +or a string of the form +.I host:filename +to specify both a host and filename at the same time. +If the latter form is used, +the last hostname specified becomes the default for future transfers. +.TP +.B quit +Exit +.IR tftp . +An end of file also exits. +.TP +.B verbose +Toggle verbose mode. +.TP +.B trace +Toggle packet tracing. +.TP +.B status +Show current status. +.TP +\fBrexmt\fP \fIretransmission-timeout\fP +Set the per-packet retransmission timeout, in seconds. +.TP +\fBtimeout\fP \fItotal-transmission-timeout\fP +Set the total transmission timeout, in seconds. +.TP +.B ascii +Shorthand for "mode ascii" +.TP +.B binary +Shorthand for "mode binary" +.TP +\fBblocksize\fP \fItransfer-blocksize\fP +Set the blocksize that is used for transfers. This assumes that the +server knows about RFC1782 and RFC1783 extensions to the TFTP +protocol; automatic fallback is supported and will result in a default +blocksize of 512 octets. +.TP +\fB?\fP \ [ \fIcommand-name\fP ... ] +Print help information. +.SH BUGS +.PP +Because there is no user-login or validation within +the +.I TFTP +protocol, the remote site will probably have some +sort of file-access restrictions in place. The +exact methods are specific to each site and therefore +difficult to document here. diff --git a/contrib/tftp/tftp.c b/contrib/tftp/tftp.c new file mode 100644 index 0000000..894e535 --- /dev/null +++ b/contrib/tftp/tftp.c @@ -0,0 +1,536 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char sccsid[] = "@(#)tftp.c 5.7 (Berkeley) 6/29/88"; +#endif /* not lint */ + +/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ + +/* + * TFTP User Program -- Protocol Machines + */ +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> + +#include <netinet/in.h> + +#include <arpa/tftp.h> + +#include <signal.h> +#include <stdio.h> +#include <errno.h> +#include <setjmp.h> + +extern int errno; + +extern struct sockaddr_in sin; /* filled in by main */ +extern int f; /* the opened socket */ +extern int trace; +extern int verbose; +extern int rexmtval; +extern int maxtimeout; +extern int segsize; + +#define PKTSIZE (1432+4) /* SEGSIZE+4 */ +char ackbuf[PKTSIZE]; +int timeout; +jmp_buf toplevel; +jmp_buf timeoutbuf; + +#ifndef OACK +#define OACK 6 +#endif + +void timer(int sig) +{ + + signal(SIGALRM, timer); + timeout += rexmtval; + if (timeout >= maxtimeout) { + printf("Transfer timed out.\n"); + longjmp(toplevel, -1); + } + longjmp(timeoutbuf, 1); +} + +strnlen(s, n) + char *s; + int n; +{ + int i = 0; + + while (n-- > 0 && *s++) i++; + return(i); +} + +/* + * Parse an OACK package and set blocksize accordingly + */ +parseoack(cp, sz) + char *cp; + int sz; +{ + int n; + + segsize = 512; + while (sz > 0 && *cp) { + n = strnlen(cp, sz); + if (n == 7 && !strncmp("blksize", cp, 7)) { + cp += 8; + sz -= 8; + if (sz <= 0) + break; + for (segsize = 0, n = strnlen(cp, sz); n > 0; + n--, cp++, sz--) { + if (*cp < '0' || *cp > '9') + break; + segsize = 10*segsize + *cp - '0'; } + } + cp += n + 1; + sz -= n + 1; + } + if (segsize < 8 || segsize > 1432) { + printf("Remote host negotiated illegal blocksize %d\n", + segsize); + segsize = 512; + longjmp(timeoutbuf, -1); + } +} + +/* + * Send the requested file. + */ +sendfile(fd, name, mode) + int fd; + char *name; + char *mode; +{ + register struct tftphdr *ap; /* data and ack packets */ + struct tftphdr *r_init(), *dp; + register int size, n; + u_short block = 0; + register unsigned long amount = 0; + struct sockaddr_in from; + int fromlen; + int convert; /* true if doing nl->crlf conversion */ + FILE *file; + + startclock(); /* start stat's clock */ + dp = r_init(); /* reset fillbuf/read-ahead code */ + ap = (struct tftphdr *)ackbuf; + file = fdopen(fd, "r"); + convert = !strcmp(mode, "netascii"); + + signal(SIGALRM, timer); + do { + if (block == 0) + size = makerequest(WRQ, name, dp, mode) - 4; + else { + /* size = read(fd, dp->th_data, SEGSIZE); */ + size = readit(file, &dp, convert); + if (size < 0) { + nak(errno + 100); + break; + } + dp->th_opcode = htons((u_short)DATA); + dp->th_block = htons(block); + } + timeout = 0; + (void) setjmp(timeoutbuf); +send_data: + if (trace) + tpacket("sent", dp, size + 4); + n = sendto(f, dp, size + 4, 0, (struct sockaddr *)&sin, + sizeof (sin)); + if (n != size + 4) { + perror("tftp: sendto"); + goto abort; + } + if (block) /* do not start reading until the blocksize + has been negotiated */ + read_ahead(file, convert); + for ( ; ; ) { + alarm(rexmtval); + do { + fromlen = sizeof (from); + n = recvfrom(f, ackbuf, sizeof (ackbuf), 0, + (struct sockaddr *)&from, + &fromlen); + } while (n <= 0); + alarm(0); + if (n < 0) { + perror("tftp: recvfrom"); + goto abort; + } + sin.sin_port = from.sin_port; /* added */ + if (trace) + tpacket("received", ap, n); + /* should verify packet came from server */ + ap->th_opcode = ntohs(ap->th_opcode); + if (ap->th_opcode == ERROR) { + printf("Error code %d: %s\n", ap->th_code, + ap->th_msg); + goto abort; + } + if (ap->th_opcode == ACK) { + int j; + + ap->th_block = ntohs(ap->th_block); + + if (block == 0) { + if (trace) + printf("server does not know " + "about RFC1782; reset" + "ting blocksize\n"); + segsize = 512; + } + if (ap->th_block == block) { + break; + } + /* On an error, try to synchronize + * both sides. + */ + j = synchnet(f); + if (j && trace) { + printf("discarded %d packets\n", + j); + } + if (ap->th_block == (block-1)) { + goto send_data; + } + } + else if (ap->th_opcode == OACK) { + if (block) { + printf("protocol violation\n"); + longjmp(toplevel, -1); + } + parseoack(&ap->th_stuff, n - 2); + break; + } + } + if (block > 0) + amount += size; + else + read_ahead(file, convert); + block++; + } while (size == segsize || block == 1); +abort: + fclose(file); + stopclock(); + if (amount > 0) + printstats("Sent", amount); +} + +/* + * Receive a file. + */ +recvfile(fd, name, mode) + int fd; + char *name; + char *mode; +{ + register struct tftphdr *ap; + struct tftphdr *dp, *w_init(); + register int n, size; + u_short block = 1; + unsigned long amount = 0; + struct sockaddr_in from; + int fromlen, firsttrip = 1; + FILE *file; + int convert; /* true if converting crlf -> lf */ + int waitforoack = 1; + + startclock(); + dp = w_init(); + ap = (struct tftphdr *)ackbuf; + file = fdopen(fd, "w"); + convert = !strcmp(mode, "netascii"); + + signal(SIGALRM, timer); + do { + if (firsttrip) { + size = makerequest(RRQ, name, ap, mode); + firsttrip = 0; + } else { + ap->th_opcode = htons((u_short)ACK); + ap->th_block = htons(block); + size = 4; + block++; + } + timeout = 0; + (void) setjmp(timeoutbuf); +send_ack: + if (trace) + tpacket("sent", ap, size); + if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&sin, + sizeof (sin)) != size) { + alarm(0); + perror("tftp: sendto"); + goto abort; + } + if (!waitforoack) + write_behind(file, convert); + for ( ; ; ) { + alarm(rexmtval); + do { + fromlen = sizeof (from); + n = recvfrom(f, dp, PKTSIZE, 0, + (struct sockaddr *)&from, &fromlen); + } while (n <= 0); + alarm(0); + if (n < 0) { + perror("tftp: recvfrom"); + goto abort; + } + sin.sin_port = from.sin_port; /* added */ + if (trace) + tpacket("received", dp, n); + /* should verify client address */ + dp->th_opcode = ntohs(dp->th_opcode); + if (dp->th_opcode == ERROR) { + printf("Error code %d: %s\n", dp->th_code, + dp->th_msg); + goto abort; + } + if (dp->th_opcode == DATA) { + int j; + + if (waitforoack) { + if (trace) + printf("server does not know " + "about RFC1782; reset" + "ting blocksize\n"); + waitforoack = 0; + segsize = 512; + } + dp->th_block = ntohs(dp->th_block); + if (dp->th_block == block) { + break; /* have next packet */ + } + /* On an error, try to synchronize + * both sides. + */ + j = synchnet(f); + if (j && trace) { + printf("discarded %d packets\n", j); + } + if (dp->th_block == (block-1)) { + goto send_ack; /* resend ack */ + } + } + else if (dp->th_opcode == OACK) { + if (block != 1 || !waitforoack) { + printf("protocol violation\n"); + longjmp(toplevel, -1); + } + waitforoack = 0; + parseoack(&dp->th_stuff, n - 2); + ap->th_opcode = htons((u_short)ACK); + ap->th_block = htons(0); + size = 4; + goto send_ack; + } + } + /* size = write(fd, dp->th_data, n - 4); */ + size = writeit(file, &dp, n - 4, convert); + if (size < 0) { + nak(errno + 100); + break; + } + amount += size; + } while (size == segsize); +abort: /* ok to ack, since user */ + ap->th_opcode = htons((u_short)ACK); /* has seen err msg */ + ap->th_block = htons(block); + (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&sin, sizeof (sin)); + write_behind(file, convert); /* flush last buffer */ + fclose(file); + stopclock(); + if (amount > 0) + printstats("Received", amount); +} + +makerequest(request, name, tp, mode) + int request; + char *name, *mode; + struct tftphdr *tp; +{ + register char *cp; + + tp->th_opcode = htons((u_short)request); + cp = tp->th_stuff; + strcpy(cp, name); + cp += strlen(name); + *cp++ = '\0'; + strcpy(cp, mode); + cp += strlen(mode); + *cp++ = '\0'; + strcpy(cp, "blksize"); + cp += 7; + *cp++ = '\0'; + sprintf(cp, "%d", segsize); + cp += strlen(cp) + 1; + return (cp - (char *)tp); +} + +struct errmsg { + int e_code; + const char *e_msg; +} errmsgs[] = { + { EUNDEF, "Undefined error code" }, + { ENOTFOUND, "File not found" }, + { EACCESS, "Access violation" }, + { ENOSPACE, "Disk full or allocation exceeded" }, + { EBADOP, "Illegal TFTP operation" }, + { EBADID, "Unknown transfer ID" }, + { EEXISTS, "File already exists" }, + { ENOUSER, "No such user" }, + { -1, 0 } +}; + +/* + * Send a nak packet (error message). + * Error code passed in is one of the + * standard TFTP codes, or a UNIX errno + * offset by 100. + */ +nak(error) + int error; +{ + register struct tftphdr *tp; + int length; + register struct errmsg *pe; +/* extern char *sys_errlist[]; */ + + tp = (struct tftphdr *)ackbuf; + tp->th_opcode = htons((u_short)ERROR); + tp->th_code = htons((u_short)error); + for (pe = errmsgs; pe->e_code >= 0; pe++) + if (pe->e_code == error) + break; + if (pe->e_code < 0) { + pe->e_msg = sys_errlist[error - 100]; + tp->th_code = EUNDEF; + } + strcpy(tp->th_msg, pe->e_msg); + length = strlen(pe->e_msg) + 4; + if (trace) + tpacket("sent", tp, length); + if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&sin, sizeof (sin)) + != length) + perror("nak"); +} + +topts(cp, sz) + char *cp; + int sz; +{ + int n, i = 0; + + while (sz > 0 && *cp) { + n = strnlen(cp, sz); + if (n > 0) { + printf("%s%s=", i++ ? ", " : "", cp); + cp += n + 1; + sz -= n + 1; + if (sz <= 0) + break; + n = strnlen(cp, sz); + if (n > 0) + printf("%s", cp); + } + cp += n + 1; + sz -= n + 1; + } +} + +tpacket(s, tp, n) + char *s; + struct tftphdr *tp; + int n; +{ + static char *opcodes[] = + { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" }; + register char *cp, *file; + u_short op = ntohs(tp->th_opcode); + char *index(); + + if (op < RRQ || op > OACK) + printf("%s opcode=%x ", s, op); + else + printf("%s %s ", s, opcodes[op]); + switch (op) { + + case RRQ: + case WRQ: + n -= 2; + file = cp = tp->th_stuff; + cp = index(cp, '\0'); + printf("<file=%s, mode=%s, opts: ", file, cp + 1); + topts(index(cp + 1, '\000') + 1, n - strlen(file) + - strlen(cp + 1) - 2); + printf(">\n"); + break; + + case DATA: + printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4); + break; + + case ACK: + printf("<block=%d>\n", ntohs(tp->th_block)); + break; + + case ERROR: + printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg); + break; + case OACK: + printf("<"); + topts(tp->th_stuff, n - 2); + printf(">\n"); + break; + } +} + +struct timeval tstart; +struct timeval tstop; +struct timezone zone; + +startclock() { + gettimeofday(&tstart, &zone); +} + +stopclock() { + gettimeofday(&tstop, &zone); +} + +printstats(direction, amount) +char *direction; +unsigned long amount; +{ + double delta; + /* compute delta in 1/10's second units */ + delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) - + ((tstart.tv_sec*10.)+(tstart.tv_usec/100000)); + delta = delta/10.; /* back to seconds */ + printf("%s %ld bytes in %.1f seconds", direction, amount, delta); + if ((verbose) && (delta >= 0.1)) + printf(" [%.0f bits/sec]", (amount*8.)/delta); + putchar('\n'); +} + diff --git a/contrib/tftp/tftpd.8 b/contrib/tftp/tftpd.8 new file mode 100644 index 0000000..6a154c1 --- /dev/null +++ b/contrib/tftp/tftpd.8 @@ -0,0 +1,75 @@ +.\" Copyright (c) 1983 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms are permitted +.\" provided that the above copyright notice and this paragraph are +.\" duplicated in all such forms and that any documentation, +.\" advertising materials, and other materials related to such +.\" distribution and use acknowledge that the software was developed +.\" by the University of California, Berkeley. The name of the +.\" University may not be used to endorse or promote products derived +.\" from this software without specific prior written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.\" @(#)tftpd.8 6.3 (Berkeley) 9/20/88 +.\" +.TH TFTPD 8 "September 20, 1988" +.UC 5 +.SH NAME +tftpd \- DARPA Trivial File Transfer Protocol server +.SH SYNOPSIS +.B /etc/tftpd +[ +.SM \-c +<rootdir> ] [ +.SM \-d +] [ +.SM \-r +<filter> ] +.SH DESCRIPTION +.I Tftpd +is a server which supports the DARPA Trivial File Transfer +Protocol. +The TFTP server operates +at the port indicated in the ``tftp'' service description; +see +.IR services (5). +The server is normally started by +.IR inetd (8). +.PP +The use of +.I tftp +does not require an account or password on the remote system. +Due to the lack of authentication information, +.I tftpd +will allow only publicly readable files to be +accessed. +Files may be written only if they already exist and are publicly writable. +Note that this extends the concept of ``public'' to include +all users on all hosts that can be reached through the network; +this may not be appropriate on all systems, and its implications +should be considered before enabling tftp service. +The server should have the user ID with the lowest possible privilege. +.SH OPTIONS +.TP +.B \-c +Pathname of a directory that is considered the rootdirectory for all +transfers. N.B. +.I tftpd +does not actually perform a +.IR chroot (2) +call; you should be aware of the security implications and you +probably should run the server from an unpriviledged account. +.TP +.B \-d +Increased debugging level. +.TP +.B \-r +Pathname of a file that is considered to be a filter program. Whenever +a client tries to download this file, the filter will be started and +its output is send to the client. An arbitrary amount of these +filters can be specified. +.SH "SEE ALSO" +tftp(1), inetd(8) diff --git a/contrib/tftp/tftpd.c b/contrib/tftp/tftpd.c new file mode 100644 index 0000000..325a713 --- /dev/null +++ b/contrib/tftp/tftpd.c @@ -0,0 +1,742 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1983 Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)tftpd.c 5.8 (Berkeley) 6/18/88"; +#endif /* not lint */ + +/* + * Trivial file transfer protocol server. + * + * This version includes many modifications by Jim Guyton <guyton@rand-unix> + * + * Further modifications by Markus Gutschke <gutschk@math.uni-muenster.de> + * - RFC1782 option parsing + * - RFC1783 extended blocksize + * - "-c" option for changing the root directory + * - "-d" option for debugging output + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/wait.h> +#include <sys/stat.h> + +#include <netinet/in.h> + +#include <arpa/tftp.h> + +#include <alloca.h> +#include <string.h> +#include <signal.h> +#include <stdio.h> +#include <errno.h> +#include <ctype.h> +#include <netdb.h> +#include <setjmp.h> +#include <syslog.h> + +#define TIMEOUT 5 + +#ifndef OACK +#define OACK 06 +#endif + +#ifndef EOPTNEG +#define EOPTNEG 8 +#endif + +extern int errno; +struct sockaddr_in sin = { AF_INET }; +int peer; +int rexmtval = TIMEOUT; +int maxtimeout = 5*TIMEOUT; + +#define PKTSIZE (1432+4) /* SEGSIZE+4 */ +int segsize = SEGSIZE; +char buf[PKTSIZE]; +char ackbuf[PKTSIZE]; +struct sockaddr_in from; +int fromlen; + +char *rootdir = NULL; +int debug = 0; + +struct filters { + struct filters *next; + char *fname; +} *filters = NULL; +int isfilter = 0; + +main(argc, argv) + char *argv[]; +{ + register struct tftphdr *tp; + register int n; + int on = 1; + extern int optind; + extern char *optarg; + + openlog(argv[0], LOG_PID, LOG_DAEMON); + + while ((n = getopt(argc, argv, "c:dr:")) >= 0) { + switch (n) { + case 'c': + if (rootdir) + goto usage; + rootdir = optarg; + break; + case 'd': + debug++; + break; + case 'r': { + struct filters *fp = (void *) + malloc(sizeof(struct filters) + + strlen(optarg) + 1); + fp->next = filters; + fp->fname = (char *)(fp + 1); + strcpy(fp->fname, optarg); + filters = fp; + break; } + default: + usage: + syslog(LOG_ERR, "Usage: %s [-c chroot] " + "[-r readfilter] [-d]\n", + argv[0]); + exit(1); + } + } + if (argc-optind != 0) + goto usage; + + ioctl(0, FIONBIO, &on); +/* if (ioctl(0, FIONBIO, &on) < 0) { + syslog(LOG_ERR, "ioctl(FIONBIO): %m\n"); + exit(1); + } +*/ + fromlen = sizeof (from); + n = recvfrom(0, buf, segsize+4, 0, + (struct sockaddr *)&from, &fromlen); + if (n < 0) { + syslog(LOG_ERR, "recvfrom: %m\n"); + exit(1); + } + /* + * Now that we have read the message out of the UDP + * socket, we fork and exit. Thus, inetd will go back + * to listening to the tftp port, and the next request + * to come in will start up a new instance of tftpd. + * + * We do this so that inetd can run tftpd in "wait" mode. + * The problem with tftpd running in "nowait" mode is that + * inetd may get one or more successful "selects" on the + * tftp port before we do our receive, so more than one + * instance of tftpd may be started up. Worse, if tftpd + * break before doing the above "recvfrom", inetd would + * spawn endless instances, clogging the system. + */ + { + int pid; + int i, j; + + for (i = 1; i < 20; i++) { + pid = fork(); + if (pid < 0) { + sleep(i); + /* + * flush out to most recently sent request. + * + * This may drop some request, but those + * will be resent by the clients when + * they timeout. The positive effect of + * this flush is to (try to) prevent more + * than one tftpd being started up to service + * a single request from a single client. + */ + j = sizeof from; + i = recvfrom(0, buf, segsize+4, 0, + (struct sockaddr *)&from, &j); + if (i > 0) { + n = i; + fromlen = j; + } + } else { + break; + } + } + if (pid < 0) { + syslog(LOG_ERR, "fork: %m\n"); + exit(1); + } else if (pid != 0) { + exit(0); + } + } + from.sin_family = AF_INET; + alarm(0); + close(0); + close(1); + peer = socket(AF_INET, SOCK_DGRAM, 0); + if (peer < 0) { + syslog(LOG_ERR, "socket: %m\n"); + exit(1); + } + if (bind(peer, (struct sockaddr *)&sin, sizeof (sin)) < 0) { + syslog(LOG_ERR, "bind: %m\n"); + exit(1); + } + if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) { + syslog(LOG_ERR, "connect: %m\n"); + exit(1); + } + tp = (struct tftphdr *)buf; + tp->th_opcode = ntohs(tp->th_opcode); + if (tp->th_opcode == RRQ || tp->th_opcode == WRQ) + tftp(tp, n); + exit(1); +} + +int validate_access(); +int sendfile(), recvfile(); + +struct formats { + char *f_mode; + int (*f_validate)(); + int (*f_send)(); + int (*f_recv)(); + int f_convert; +} formats[] = { + { "netascii", validate_access, sendfile, recvfile, 1 }, + { "octet", validate_access, sendfile, recvfile, 0 }, +#ifdef notdef + { "mail", validate_user, sendmail, recvmail, 1 }, +#endif + { 0 } +}; + +int set_blksize(); + +struct options { + char *o_opt; + int (*o_fnc)(); +} options[] = { + { "blksize", set_blksize }, + { 0 } +}; + +/* + * Set a non-standard block size (c.f. RFC1783) + */ + +set_blksize(val, ret) + char *val; + char **ret; +{ + static char b_ret[5]; + int sz = atoi(val); + + if (sz < 8) { + if (debug) + syslog(LOG_ERR, "Requested packetsize %d < 8\n", sz); + return(0); + } else if (sz > PKTSIZE-4) { + if (debug) + syslog(LOG_INFO, "Requested packetsize %d > %d\n", + sz, PKTSIZE-4); + sz = PKTSIZE-4; + } else if (debug) + syslog(LOG_INFO, "Adjusted packetsize to %d octets\n", sz); + + segsize = sz; + sprintf(*ret = b_ret, "%d", sz); + return(1); +} + +/* + * Parse RFC1782 style options + */ + +do_opt(opt, val, ap) + char *opt; + char *val; + char **ap; +{ + struct options *po; + char *ret; + + for (po = options; po->o_opt; po++) + if (strcasecmp(po->o_opt, opt) == 0) { + if (po->o_fnc(val, &ret)) { + if (*ap + strlen(opt) + strlen(ret) + 2 >= + ackbuf + sizeof(ackbuf)) { + if (debug) + syslog(LOG_ERR, + "Ackbuf overflow\n"); + nak(ENOSPACE); + exit(1); + } + *ap = strrchr(strcpy(strrchr(strcpy(*ap, opt), + '\000')+1, val), + '\000')+1; + } else { + nak(EOPTNEG); + exit(1); + } + break; + } + if (debug && !po->o_opt) + syslog(LOG_WARNING, "Unhandled option: %d = %d\n", opt, val); + return; +} + +/* + * Handle initial connection protocol. + */ +tftp(tp, size) + struct tftphdr *tp; + int size; +{ + register char *cp; + int argn = 0, ecode; + register struct formats *pf; + char *filename, *mode; + char *val, *opt; + char *ap = ackbuf+2; + int isopts; + + ((struct tftphdr *)ackbuf)->th_opcode = ntohs(OACK); + filename = cp = tp->th_stuff; +again: + while (cp < buf + size) { + if (*cp == '\0') + break; + cp++; + } + if (*cp != '\0') { + if (debug) + syslog(LOG_WARNING, "Received illegal request\n"); + nak(EBADOP); + exit(1); + } + if (!argn++) { + mode = ++cp; + goto again; + } else { + if (debug && argn == 3) + syslog(LOG_INFO, "Found RFC1782 style options\n"); + *(argn & 1 ? &val : &opt) = ++cp; + if (argn & 1) + do_opt(opt, val, &ap); + if (cp < buf + size && *cp != '\000') + goto again; + } + + for (cp = mode; *cp; cp++) + if (isupper(*cp)) + *cp = tolower(*cp); + for (pf = formats; pf->f_mode; pf++) + if (strcmp(pf->f_mode, mode) == 0) + break; + if (pf->f_mode == 0) { + if (debug) + syslog(LOG_WARNING, "Unknown data format: %s\n", mode); + nak(EBADOP); + exit(1); + } + + if (rootdir) { + cp = alloca(strlen(rootdir) + strlen(filename) + 1); + if (cp == NULL) { + nak(100+ENOMEM); + exit(1); + } + if (*filename != '/') { + if (debug) + syslog(LOG_ERR, + "Filename has to be absolute: %s\n", + filename); + nak(EACCESS); + exit(1); + } + filename = strcat(strcpy(cp, rootdir), filename); + } + + ecode = (*pf->f_validate)(filename, tp->th_opcode); + if (ecode) { + nak(ecode, ERROR); + exit(1); + } + isopts = ap != (ackbuf+2); + (tp->th_opcode == WRQ ? *pf->f_recv : *pf->f_send) + (pf, isopts ? ackbuf : NULL, isopts ? ap-ackbuf : 0); + exit(0); +} + + +FILE *file; + +/* + * Validate file access. Since we + * have no uid or gid, for now require + * file to exist and be publicly + * readable/writable. + * Note also, full path name must be + * given as we have no login directory. + */ +validate_access(filename, mode) + char *filename; + int mode; +{ + struct stat stbuf; + int fd; + char *cp; + + isfilter = 0; + if (mode == RRQ) { + struct filters *fp = filters; + for (; fp; fp = fp->next) { + if (!strcmp(fp->fname, + filename + + (rootdir ? strlen(rootdir) : 0))) { + if (debug) + syslog(LOG_INFO, "Opening input " + "filter: %s\n", filename); + if ((file = popen(filename, "r")) == NULL) { + syslog(LOG_ERR, "Failed to open input " + "filter\n"); + return (EACCESS); } + fd = fileno(file); + isfilter = 1; + return (0); + } + } + } + + if (*filename != '/') { + if (debug) + syslog(LOG_ERR, "Filename has to be absolute: %s\n", + filename); + return (EACCESS); + } + for (cp = filename; *cp; cp++) + if (*cp == '~' || *cp == '$' || + (*cp == '/' && cp[1] == '.' && cp[2] == '.')) { + if (debug) + syslog(LOG_ERR, "Illegal filename: %s\n", + filename); + return (EACCESS); + } + if (debug) + syslog(LOG_INFO, "Validating \"%s\" for %sing\n", + filename, mode == RRQ ? "read" : "writ"); + if (stat(filename, &stbuf) < 0) + return (errno == ENOENT ? ENOTFOUND : EACCESS); + if (mode == RRQ) { + if ((stbuf.st_mode&(S_IREAD >> 6)) == 0) + return (EACCESS); + } else { + if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0) + return (EACCESS); + } + fd = open(filename, mode == RRQ ? 0 : 1); + if (fd < 0) + return (errno + 100); + file = fdopen(fd, (mode == RRQ)? "r":"w"); + if (file == NULL) { + return errno+100; + } + return (0); +} + +int timeout; +jmp_buf timeoutbuf; + +void timer(int sig) +{ + + timeout += rexmtval; + if (timeout >= maxtimeout) { + if (debug) + syslog(LOG_WARNING, "Timeout!\n"); + exit(1); + } + longjmp(timeoutbuf, 1); +} + +/* + * Send the requested file. + */ +sendfile(pf, oap, oacklen) + struct formats *pf; + struct tftphdr *oap; + int oacklen; +{ + struct tftphdr *dp, *r_init(); + register struct tftphdr *ap; /* ack packet */ + register int size, n; + u_short block = 1; + + signal(SIGALRM, timer); + + ap = (struct tftphdr *)ackbuf; + + if (oap) { + timeout = 0; + (void) setjmp(timeoutbuf); + oack: + if (send(peer, oap, oacklen, 0) != oacklen) { + syslog(LOG_ERR, "tftpd: write: %m\n"); + goto abort; + } + for ( ; ; ) { + alarm(rexmtval); + n = recv(peer, ackbuf, sizeof (ackbuf), 0); + alarm(0); + if (n < 0) { + syslog(LOG_ERR, "tftpd: read: %m\n"); + goto abort; + } + ap->th_opcode = ntohs((u_short)ap->th_opcode); + ap->th_block = ntohs(ap->th_block); + + if (ap->th_opcode == ERROR) { + if (debug) + syslog(LOG_ERR, "Client does not " + "accept options\n"); + goto abort; } + + if (ap->th_opcode == ACK) { + if (ap->th_block == 0) { + if (debug) + syslog(LOG_DEBUG, + "RFC1782 option " + "negotiation " + "succeeded\n"); + break; + } + /* Re-synchronize with the other side */ + (void) synchnet(peer); + goto oack; + } + } + } + + dp = r_init(); + do { + size = readit(file, &dp, pf->f_convert); + if (size < 0) { + nak(errno + 100); + goto abort; + } + dp->th_opcode = htons((u_short)DATA); + dp->th_block = htons(block); + timeout = 0; + (void) setjmp(timeoutbuf); + +send_data: + if (send(peer, dp, size + 4, 0) != size + 4) { + syslog(LOG_ERR, "tftpd: write: %m\n"); + goto abort; + } + read_ahead(file, pf->f_convert); + for ( ; ; ) { + alarm(rexmtval); /* read the ack */ + n = recv(peer, ackbuf, sizeof (ackbuf), 0); + alarm(0); + if (n < 0) { + syslog(LOG_ERR, "tftpd: read: %m\n"); + goto abort; + } + ap->th_opcode = ntohs((u_short)ap->th_opcode); + ap->th_block = ntohs(ap->th_block); + + if (ap->th_opcode == ERROR) + goto abort; + + if (ap->th_opcode == ACK) { + if (ap->th_block == block) { + break; + } + /* Re-synchronize with the other side */ + (void) synchnet(peer); + if (ap->th_block == (block -1)) { + goto send_data; + } + } + + } + block++; + } while (size == segsize); +abort: + if (isfilter) + pclose(file); + else + (void) fclose(file); + isfilter = 0; +} + +void justquit(int sig) +{ + exit(0); +} + + +/* + * Receive a file. + */ +recvfile(pf, oap, oacklen) + struct formats *pf; + struct tftphdr *oap; + int oacklen; +{ + struct tftphdr *dp, *w_init(); + register struct tftphdr *ap; /* ack buffer */ + register int acksize, n, size; + u_short block = 0; + + signal(SIGALRM, timer); + dp = w_init(); + do { + timeout = 0; + + if (!block++ && oap) { + ap = (struct tftphdr *)oap; + acksize = oacklen; + } else { + ap = (struct tftphdr *)ackbuf; + ap->th_opcode = htons((u_short)ACK); + ap->th_block = htons(block-1); + acksize = 4; + } + (void) setjmp(timeoutbuf); +send_ack: + if (send(peer, (char *)ap, acksize, 0) != acksize) { + syslog(LOG_ERR, "tftpd: write: %m\n"); + goto abort; + } + write_behind(file, pf->f_convert); + for ( ; ; ) { + alarm(rexmtval); + n = recv(peer, dp, segsize+4, 0); + alarm(0); + if (n < 0) { /* really? */ + syslog(LOG_ERR, "tftpd: read: %m\n"); + goto abort; + } + dp->th_opcode = ntohs((u_short)dp->th_opcode); + dp->th_block = ntohs(dp->th_block); + if (dp->th_opcode == ERROR) + goto abort; + if (dp->th_opcode == DATA) { + if (dp->th_block == block) { + break; /* normal */ + } + /* Re-synchronize with the other side */ + (void) synchnet(peer); + if (dp->th_block == (block-1)) + goto send_ack; /* rexmit */ + } + } + /* size = write(file, dp->th_data, n - 4); */ + size = writeit(file, &dp, n - 4, pf->f_convert); + if (size != (n-4)) { /* ahem */ + if (size < 0) nak(errno + 100); + else nak(ENOSPACE); + goto abort; + } + } while (size == segsize); + write_behind(file, pf->f_convert); + if (isfilter) + pclose(file); + else + (void) fclose(file); /* close data file */ + isfilter = 0; + + ap = (struct tftphdr *)ackbuf; + ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */ + ap->th_block = htons(block); + (void) send(peer, ackbuf, 4, 0); + + signal(SIGALRM, justquit); /* just quit on timeout */ + alarm(rexmtval); + n = recv(peer, buf, segsize, 0); /* normally times out and quits */ + alarm(0); + if (n >= 4 && /* if read some data */ + dp->th_opcode == DATA && /* and got a data block */ + block == dp->th_block) { /* then my last ack was lost */ + (void) send(peer, ackbuf, 4, 0); /* resend final ack */ + } +abort: + return; +} + +struct errmsg { + int e_code; + const char *e_msg; +} errmsgs[] = { + { EUNDEF, "Undefined error code" }, + { ENOTFOUND, "File not found" }, + { EACCESS, "Access violation" }, + { ENOSPACE, "Disk full or allocation exceeded" }, + { EBADOP, "Illegal TFTP operation" }, + { EBADID, "Unknown transfer ID" }, + { EEXISTS, "File already exists" }, + { ENOUSER, "No such user" }, + { EOPTNEG, "Failure to negotiate RFC1782 options" }, + { -1, 0 } +}; + +/* + * Send a nak packet (error message). + * Error code passed in is one of the + * standard TFTP codes, or a UNIX errno + * offset by 100. + */ +nak(error) + int error; +{ + register struct tftphdr *tp; + int length; + register struct errmsg *pe; +/* extern char *sys_errlist[]; */ + + tp = (struct tftphdr *)buf; + tp->th_opcode = htons((u_short)ERROR); + tp->th_code = htons((u_short)error); + for (pe = errmsgs; pe->e_code >= 0; pe++) + if (pe->e_code == error) + break; + if (pe->e_code < 0) { + pe->e_msg = sys_errlist[error -100]; + tp->th_code = EUNDEF; /* set 'undef' errorcode */ + } + strcpy(tp->th_msg, pe->e_msg); + length = strlen(pe->e_msg); + tp->th_msg[length] = '\0'; + length += 5; + if (debug) + syslog(LOG_ERR, "Negative acknowledge: %s\n", tp->th_msg); + if (send(peer, buf, length, 0) != length) + syslog(LOG_ERR, "nak: %m\n"); +} diff --git a/contrib/tftp/tftpsubs.c b/contrib/tftp/tftpsubs.c new file mode 100644 index 0000000..608d64e --- /dev/null +++ b/contrib/tftp/tftpsubs.c @@ -0,0 +1,260 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char sccsid[] = "@(#)tftpsubs.c 5.4 (Berkeley) 6/29/88"; +#endif /* not lint */ + +/* Simple minded read-ahead/write-behind subroutines for tftp user and + server. Written originally with multiple buffers in mind, but current + implementation has two buffer logic wired in. + + Todo: add some sort of final error check so when the write-buffer + is finally flushed, the caller can detect if the disk filled up + (or had an i/o error) and return a nak to the other side. + + Jim Guyton 10/85 + */ + +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <arpa/tftp.h> +#include <stdio.h> + +#define PKTSIZE (1432+4) /* SEGSIZE+4 */ /* should be moved to tftp.h */ + +struct bf { + int counter; /* size of data in buffer, or flag */ + char buf[PKTSIZE]; /* room for data packet */ +} bfs[2]; + + /* Values for bf.counter */ +#define BF_ALLOC -3 /* alloc'd but not yet filled */ +#define BF_FREE -2 /* free */ +/* [-1 .. SEGSIZE] = size of data in the data buffer */ + +extern int segsize; + +static int nextone; /* index of next buffer to use */ +static int current; /* index of buffer in use */ + + /* control flags for crlf conversions */ +int newline = 0; /* fillbuf: in middle of newline expansion */ +int prevchar = -1; /* putbuf: previous char (cr check) */ + +struct tftphdr *rw_init(); + +struct tftphdr *w_init() { return rw_init(0); } /* write-behind */ +struct tftphdr *r_init() { return rw_init(1); } /* read-ahead */ + +struct tftphdr * +rw_init(x) /* init for either read-ahead or write-behind */ +int x; /* zero for write-behind, one for read-head */ +{ + newline = 0; /* init crlf flag */ + prevchar = -1; + bfs[0].counter = BF_ALLOC; /* pass out the first buffer */ + current = 0; + bfs[1].counter = BF_FREE; + nextone = x; /* ahead or behind? */ + return (struct tftphdr *)bfs[0].buf; +} + + +/* Have emptied current buffer by sending to net and getting ack. + Free it and return next buffer filled with data. + */ +readit(file, dpp, convert) + FILE *file; /* file opened for read */ + struct tftphdr **dpp; + int convert; /* if true, convert to ascii */ +{ + struct bf *b; + + bfs[current].counter = BF_FREE; /* free old one */ + current = !current; /* "incr" current */ + + b = &bfs[current]; /* look at new buffer */ + if (b->counter == BF_FREE) /* if it's empty */ + read_ahead(file, convert); /* fill it */ +/* assert(b->counter != BF_FREE); /* check */ + *dpp = (struct tftphdr *)b->buf; /* set caller's ptr */ + return b->counter; +} + +/* + * fill the input buffer, doing ascii conversions if requested + * conversions are lf -> cr,lf and cr -> cr, nul + */ +read_ahead(file, convert) + FILE *file; /* file opened for read */ + int convert; /* if true, convert to ascii */ +{ + register int i; + register char *p; + register int c; + struct bf *b; + struct tftphdr *dp; + + b = &bfs[nextone]; /* look at "next" buffer */ + if (b->counter != BF_FREE) /* nop if not free */ + return; + nextone = !nextone; /* "incr" next buffer ptr */ + + dp = (struct tftphdr *)b->buf; + + if (convert == 0) { + int i; + b->counter = 0; + do { + i = read(fileno(file), dp->th_data + b->counter, + segsize - b->counter); + if (i > 0) + b->counter += i; + } while (i != 0 && !(i < 0 && errno != EINTR) && + b->counter < segsize); + return; + } + + p = dp->th_data; + for (i = 0 ; i < segsize; i++) { + if (newline) { + if (prevchar == '\n') + c = '\n'; /* lf to cr,lf */ + else c = '\0'; /* cr to cr,nul */ + newline = 0; + } + else { + c = getc(file); + if (c == EOF) break; + if (c == '\n' || c == '\r') { + prevchar = c; + c = '\r'; + newline = 1; + } + } + *p++ = c; + } + b->counter = (int)(p - dp->th_data); +} + +/* Update count associated with the buffer, get new buffer + from the queue. Calls write_behind only if next buffer not + available. + */ +writeit(file, dpp, ct, convert) + FILE *file; + struct tftphdr **dpp; + int convert; +{ + bfs[current].counter = ct; /* set size of data to write */ + current = !current; /* switch to other buffer */ + if (bfs[current].counter != BF_FREE) /* if not free */ + write_behind(file, convert); /* flush it */ + bfs[current].counter = BF_ALLOC; /* mark as alloc'd */ + *dpp = (struct tftphdr *)bfs[current].buf; + return ct; /* this is a lie of course */ +} + +/* + * Output a buffer to a file, converting from netascii if requested. + * CR,NUL -> CR and CR,LF => LF. + * Note spec is undefined if we get CR as last byte of file or a + * CR followed by anything else. In this case we leave it alone. + */ +write_behind(file, convert) + FILE *file; + int convert; +{ + char *buf; + int count; + register int ct; + register char *p; + register int c; /* current character */ + struct bf *b; + struct tftphdr *dp; + + b = &bfs[nextone]; + if (b->counter < -1) /* anything to flush? */ + return 0; /* just nop if nothing to do */ + + count = b->counter; /* remember byte count */ + b->counter = BF_FREE; /* reset flag */ + dp = (struct tftphdr *)b->buf; + nextone = !nextone; /* incr for next time */ + buf = dp->th_data; + + if (count <= 0) return -1; /* nak logic? */ + + if (convert == 0) + return write(fileno(file), buf, count); + + p = buf; + ct = count; + while (ct--) { /* loop over the buffer */ + c = *p++; /* pick up a character */ + if (prevchar == '\r') { /* if prev char was cr */ + if (c == '\n') /* if have cr,lf then just */ + fseek(file, -1, 1); /* smash lf on top of the cr */ + else + if (c == '\0') /* if have cr,nul then */ + goto skipit; /* just skip over the putc */ + /* else just fall through and allow it */ + } + putc(c, file); +skipit: + prevchar = c; + } + return count; +} + + +/* When an error has occurred, it is possible that the two sides + * are out of synch. Ie: that what I think is the other side's + * response to packet N is really their response to packet N-1. + * + * So, to try to prevent that, we flush all the input queued up + * for us on the network connection on our host. + * + * We return the number of packets we flushed (mostly for reporting + * when trace is active). + */ + +int +synchnet(f) +int f; /* socket to flush */ +{ + int i, j = 0; + char rbuf[PKTSIZE]; + struct sockaddr_in from; + int fromlen; + + while (1) { + (void) ioctl(f, FIONREAD, &i); + if (i) { + j++; + fromlen = sizeof from; + (void) recvfrom(f, rbuf, sizeof (rbuf), 0, + (struct sockaddr *)&from, &fromlen); + } else { + return(j); + } + } +} diff --git a/contrib/tomsrtbt/tomsrtbt-net.txt b/contrib/tomsrtbt/tomsrtbt-net.txt new file mode 100644 index 0000000..c5e1b0f --- /dev/null +++ b/contrib/tomsrtbt/tomsrtbt-net.txt @@ -0,0 +1,37 @@ +Notes on turning tomsrtbt El Torito into a Etherboot image: + +0. Tomsrtbt (http://www.toms.net/) is an all-purpose rescue and utility +1-floppy Linux system. You can read all about it at the web site. These +notes explain how to turn the El Torito version of it into a netbootable +image for Etherboot. Note that the .img file is not an ISO image, it is +a 2.88M floppy emulation image for writing onto a CD-R(W) with mkisofs. +It's actually a minix filesystem. Inside it are the kernel bz2bzImage +and initrd.bz2. + +1. First uncompress the .img: + + bunzip2 tomsrtbt-2.0.103.ElTorito.288.img.bz2 + +2. Mount the image using loopback. You probably need to be root to do +this: + + mount -o ro,loop tomsrtbt-2.0.103.ElTorito.288.img /media/floppy + +I've specified /media/floppy which is the floppy mount point for my +system, but any convenient directory will do. + +3. Copy the kernel image and initrd off it: + + cp -p /media/floppy/bz2bzImage /media/floppy/initrd.bz2 . + +4. Use mkelf-linux (or mknbi-linux) to make a netbootable image: + +mkelf-linux --append='root=100' bz2bzImage initrd.bz2 > tomsrtbt.nb + +root=100 means use /dev/ram0 (device 1,0) as the root device. + +5. That's it. Clean up by unmounting the .img: + + umount /media/cdrom + +tomsrtbt.nb can now be loaded with Etherboot. Have fun. diff --git a/contrib/wakeonlan/Makefile b/contrib/wakeonlan/Makefile new file mode 100644 index 0000000..563faa9 --- /dev/null +++ b/contrib/wakeonlan/Makefile @@ -0,0 +1,37 @@ +## Makefile for use with gnu make and MinGW32 gnu gcc + +TARGET=wol + +CC=gcc +LD=gcc + +CPPFLAGS= -Wall -O2 +LFLAGS= -s + +#LIBFILES= -lwsock +#LIBPATH= -L/usr/lib + +ICON=$(TARGET).ico +OBJS=$(TARGET).o +RESF=$(TARGET).rc + +#RESNAME=$(TARGET).res +#BINNAME=$(TARGET).exe +BINNAME=$(TARGET) + +$(BINNAME): $(OBJS) $(RESNAME) + $(LD) $(LFLAGS) -o $@ $^ $(LIBPATH) $(LIBFILES) + +%.res:%.rc + windres -I rc -O coff -i $< -o $@ + +%.rc:Makefile + @echo 100 ICON "$(ICON)" > $@ + +dist:$(BINNAME) + rm -f $(OBJS) $(RESNAME) $(RESF) + +clean: + rm -f $(OBJS) $(RESNAME) $(RESF) + rm -f $(BINNAME) + diff --git a/contrib/wakeonlan/README b/contrib/wakeonlan/README new file mode 100644 index 0000000..03b7e61 --- /dev/null +++ b/contrib/wakeonlan/README @@ -0,0 +1,3 @@ +Here are two programs to send Wake-On-LAN packets to a dormant workstation +using the WOL feature. Please contact the respective authors for any +queries. diff --git a/contrib/wakeonlan/maclist.txt b/contrib/wakeonlan/maclist.txt new file mode 100644 index 0000000..b96b3e4 --- /dev/null +++ b/contrib/wakeonlan/maclist.txt @@ -0,0 +1,9 @@ +# maclist - mac addresses for wakeonlan +00:BA:BE:FA:CE:00 mainframe +00:11:22:33:44:5A maschine1 +00:11:22:33:44:B5 maschine2 +00:11:22:33:44:5C maschine3 +0A:BB:CC:DD:EE:F9 macintosh +1A:BB:CC:DD:E6:FF +3A:BB:CC:DD:EE:F5 testpc +3A:BB:CC:DD:EE:F6 123.45.6.7 diff --git a/contrib/wakeonlan/mp-form.pl b/contrib/wakeonlan/mp-form.pl new file mode 100644 index 0000000..144b507 --- /dev/null +++ b/contrib/wakeonlan/mp-form.pl @@ -0,0 +1,172 @@ +#!/perl/bin/perl -w
+# Magic Packet for the Web
+# Perl version by ken.yap@acm.org after DOS/Windows C version posted by
+# Steve_Marfisi@3com.com on the Netboot mailing list
+# modified to work with web by G. Knauf <info@gknw.de>
+# Released under GNU Public License
+#
+use CGI qw(:standard); # import shortcuts
+use Socket;
+
+$ver = 'v0.52 © gk 2003-Apr-24 11:00:00';
+
+# Defaults - Modify to point to the location of your mac file
+$www = "$ENV{'DOCUMENT_ROOT'}/perldemo";
+$maclist = "$www/maclist.txt";
+# Defaults - Modify to fit to your network
+$defbc = '255.255.255.255';
+$port = 60000;
+
+MAIN:
+{
+ # Read in all the variables set by the form
+ if (param()) {
+ &process_form();
+ } else {
+ &print_form();
+ }
+}
+
+sub process_form {
+ # Print the header
+ print header();
+ print start_html("Mp-Form - send Magic Packets");
+ # If defined new mac save it
+ if (defined(param("mac"))) {
+ print h1("Result of adding an entry to the maclist");
+ print '<HR><H3><TT>';
+ &add_entry();
+ print '</TT></H3><HR>';
+ print '<FORM method="POST"><input type="submit" value="ok"></FORM>';
+ } else {
+ # send magic packets to selected macs
+ print h1("Result of sending magic packets to multiple PCs");
+ print '<HR><H3><TT>';
+ if (param("all")) {
+ &process_file(S);
+ } else {
+ for (param()) {
+ my ($brc,$mac) = split(/-/,param($_));
+ &send_broadcast_packet(inet_aton($brc),$mac);
+ }
+ }
+ print '</TT></H3><HR>';
+ print '<FORM><input type="button" value="back" onClick="history.back()"></FORM>';
+ }
+ # Close the document cleanly.
+ print end_html;
+}
+
+sub print_form {
+ # Print the header
+ print header();
+ print start_html("Mp-Form - send Magic Packets");
+ print h1("Form for sending magic packets to multiple PCs");
+ print <<ENDOFTEXT;
+<HR>
+<FORM method="POST">
+<H2>Select the destination mac addresses:</H2>
+<TABLE BORDER COLS=3 WIDTH="80%">
+<TR>
+<TD><CENTER><B><FONT SIZE="+1">Broadcast address</FONT></B></CENTER></TD>
+<TD><CENTER><B><FONT SIZE="+1">MAC address</FONT></B></CENTER></TD>
+<TD><CENTER><B><FONT SIZE="+1">Name</FONT></B></CENTER></TD>
+<TD><CENTER><B><FONT SIZE="+1"><input type=checkbox name="all" value="all">Select all</FONT></B></CENTER></TD>
+</TR>
+ENDOFTEXT
+ # build up table with mac addresses
+ &process_file(R);
+ # print rest of the form
+ print <<ENDOFTEXT;
+</TABLE>
+<P><B><FONT SIZE="+1">
+Press <input type="submit" value="wakeup"> to send the magic packets to your selections.
+Press <input type="reset" value="clear"> to reset the form.
+</FONT></B>
+</FORM>
+<HR>
+<FORM method="POST">
+<H2>Enter new destination mac address:</H2>
+<B><FONT SIZE="+1">Broadcast: </FONT></B><input name="brc" size="15" maxlength="15" value="$defbc">
+<B><FONT SIZE="+1">MAC: </FONT></B><input name="mac" size="17" maxlength="17">
+<B><FONT SIZE="+1">Name: </FONT></B><input name="ip" size="40" maxlength="40">
+<P><B><FONT SIZE="+1">
+Press <input type="submit" value="save"> to add the entry to your maclist.
+Press <input type="reset" value="clear"> to reset the form.
+</FONT></B>
+</FORM>
+<HR>
+$ver
+ENDOFTEXT
+ # Close the document cleanly.
+ print end_html;
+}
+
+sub send_broadcast_packet {
+ my ($nbc,$mac) = @_;
+ if ($mac !~ /^[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}$/i) {
+ print "Malformed MAC address $mac<BR>\n";
+ return;
+ }
+ printf("Sending wakeup packet to %04X:%08X-%s<BR>\n", $port, unpack('N',$nbc), $mac);
+ # Remove colons
+ $mac =~ tr/://d;
+ # Magic packet is 6 bytes of FF followed by the MAC address 16 times
+ $magic = ("\xff" x 6) . (pack('H12', $mac) x 16);
+ # Create socket
+ socket(S, PF_INET, SOCK_DGRAM, getprotobyname('udp')) or die "socket: $!\n";
+ # Enable broadcast
+ setsockopt(S, SOL_SOCKET, SO_BROADCAST, 1) or die "setsockopt: $!\n";
+ # Send the wakeup packet
+ defined(send(S, $magic, 0, sockaddr_in($port, $nbc))) or print "send: $!\n";
+ close(S);
+}
+
+sub process_file {
+ unless (open(F, $maclist)) {
+ print "Error reading $maclist: $!\n";
+ } else {
+ while (<F>) {
+ next if (/^\s*#|^\s*;/); # skip comments
+ my ($mac, $ip) = split;
+ next if (!defined($mac) or $mac eq '');
+ $mac = uc($mac);
+ my $bc = $defbc;
+ ($bc,$mac) = split(/-/,$mac) if ($mac =~ /-/);
+ my $nbc = inet_aton($bc);
+ if ($_[0] eq 'S') {
+ &send_broadcast_packet($nbc, $mac);
+ } else {
+ my $hbc = sprintf("0x%08X", unpack('N',$nbc));
+ print "<TD WIDTH=20%><CENTER><TT>$hbc</TT></CENTER></TD>";
+ print "<TD WIDTH=30%><CENTER><TT>$mac</TT></CENTER></TD>";
+ $ip = ' ' if (!defined($ip) or $ip eq '');
+ print "<TD WIDTH=30%><CENTER><TT>$ip</TT></CENTER></TD>";
+ print "<TD WIDTH=20%><CENTER><input type=checkbox name=mac$. value=$hbc-$mac><TT>WakeUp</TT></CENTER></TD></TR>\n";
+ }
+ }
+ close(F);
+ }
+}
+
+sub add_entry {
+ if (param("brc") !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/i) {
+ print "Malformed broadcast address ",param("brc"),"\n";
+ return;
+ }
+ if (param("mac") !~ /^[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}$/i) {
+ print "Malformed MAC address ",param("mac"),"\n";
+ return;
+ }
+ unless (open(F, ">> $maclist")) {
+ print "Error writing $maclist: $!\n";
+ } else {
+ #my $nbc = inet_aton(param("brc"));
+ #my $hbc = sprintf("0x%8X", unpack('N',$nbc));
+ #print F $hbc."-".uc(param("mac"))." ".param("ip")."\n";
+ print F param("brc")."-".uc(param("mac"))." ".param("ip")."\n";
+ close(F);
+ print "Saved entry to maclist: ".param("brc")."-".uc(param("mac"))." ".param("ip")."\n";
+ }
+}
+
diff --git a/contrib/wakeonlan/mp-form.txt b/contrib/wakeonlan/mp-form.txt new file mode 100644 index 0000000..2c2ca5b --- /dev/null +++ b/contrib/wakeonlan/mp-form.txt @@ -0,0 +1,26 @@ +mp-form.pl - Send magic packets with your web server
+
+This is my trial of waking up PCs with a form via web server.
+The perl script reads in a text file which contains lines of the form
+aa:bb:cc:dd:ee:ff 12.34.56.78 or
+aa:bb:cc:dd:ee:ff foo.bar.com
+aa:bb:cc:dd:ee:ff
+The script is based on wake.pl by Ken Yap who is also the author of the Etherboot package.
+The script uses CGI.pm to parse form input and Socket.pm to send the magic packets, both
+modules should belong to your perl distribution. The script runs with linux as well as
+with NT, with NetWare you have to use the Socket.NLP from recent Perl build #334, with
+Perl build #333 and earlier I got an error from the Socket.pm.
+This script uses only broadcast so you don't need root rights to use it.
+
+To install the script copy it to your ../cgi-bin directory. Then for Linux do a chmod 755
+to the script. Modify the lines which point to the location of the maclist. If you do not
+have a maclist, the form could save new entries to a list (with unix perhaps you have to
+create an empty file). Check also the first line of mp-form.pl and modify it to point to
+your perl5 location. For NetWare copy the script to /novonyx/suitespot/docs/perlroot.
+
+Older version: If you have problems running the script with CGI.pm you could try the older
+version mp-form1.pl which uses cgi-lib.pl to parse form input. You can get cgi-lib.pl
+from http://cgi-lib.berkeley.edu/. With NetWare you should also use mp-form1.pl as using
+CGI.pm consumes much memory. The older version is also included in the zip archive.
+
+Homepage of the script: http://www.gknw.de/mpform.html
diff --git a/contrib/wakeonlan/mp-form1.pl b/contrib/wakeonlan/mp-form1.pl new file mode 100644 index 0000000..d42624a --- /dev/null +++ b/contrib/wakeonlan/mp-form1.pl @@ -0,0 +1,171 @@ +#!/usr/bin/perl -w
+# Magic Packet for the Web
+# Perl version by ken.yap@acm.org after DOS/Windows C version posted by
+# Steve_Marfisi@3com.com on the Netboot mailing list
+# modified to work with web by G. Knauf <info@gknw.de>
+# Released under GNU Public License
+#
+require "cgi-lib.pl";
+use Socket;
+
+$ver = 'v0.52 © gk 2003-Apr-24 11:00:00';
+
+# Defaults - Modify to point to the location of your mac file
+$www = "$ENV{'DOCUMENT_ROOT'}/perldemo";
+$maclist = "$www/maclist.txt";
+# Defaults - Modify to fit to your network
+$defbc = '255.255.255.255';
+$port = 60000;
+
+MAIN:
+{
+ # Read in all the variables set by the form
+ if (&ReadParse(*input)) {
+ &process_form();
+ } else {
+ &print_form();
+ }
+}
+
+sub process_form {
+ # Print the header
+ print &PrintHeader();
+ # If defined new mac save it
+ if (defined($input{'mac'})) {
+ print &HtmlTop("Result of adding an entry to the maclist");
+ print '<HR><H3><TT>';
+ &add_entry;
+ print '</TT></H3><HR>';
+ print '<FORM method="POST"><input type=submit value="ok"></FORM>';
+ } else {
+ # send magic packets to selected macs
+ print &HtmlTop("Result of sending magic packets to multiple PCs");
+ print '<HR><H3><TT>';
+ if (defined($input{'all'})) {
+ &process_file(S);
+ } else {
+ foreach $x (keys %input) {
+ my ($brc,$mac) = split(/-/,$input{$x});
+ &send_broadcast_packet(inet_aton($brc),$mac);
+ }
+ }
+ print '</TT></H3><HR>';
+ print '<form><input type=button value="back" onClick="history.back()"></FORM>';
+ }
+ # Close the document cleanly.
+ print &HtmlBot;
+ exit;
+}
+
+sub print_form {
+ print &PrintHeader();
+ print &HtmlTop("Form for sending magic packets to multiple PCs");
+ # Print out the body of the form
+ print <<ENDOFTEXT;
+<HR>
+<FORM method="POST">
+<H2> Select the destination mac addresses: </H2>
+<TABLE BORDER COLS=3 WIDTH="80%">
+<TR>
+<TD><CENTER><B><FONT SIZE="+1">Broadcast address</FONT></B></CENTER></TD>
+<TD><CENTER><B><FONT SIZE="+1">MAC address</FONT></B></CENTER></TD>
+<TD><CENTER><B><FONT SIZE="+1">Name</FONT></B></CENTER></TD>
+<TD><CENTER><B><FONT SIZE="+1"><input type=checkbox name="all" value="all">Select all</FONT></B></CENTER></TD>
+</TR>
+ENDOFTEXT
+ # build up table with mac addresses
+ &process_file;
+ # print rest of the form
+ print <<ENDOFTEXT;
+</TABLE>
+<P><B><FONT SIZE="+1">
+Press <input type="submit" value="wakeup"> to send the magic packets to your selections.
+Press <input type="reset" value="clear"> to reset the form.
+</FONT></B>
+</FORM>
+<HR>
+<FORM method="POST">
+<H2>Enter new destination mac address:</H2>
+<B><FONT SIZE="+1">Broadcast: </FONT></B><input name="brc" size="15" maxlength="15" value="$defbc">
+<B><FONT SIZE="+1">MAC: </FONT></B><input name="mac" size=17 maxlength=17>
+<B><FONT SIZE="+1">Name: </FONT></B><input name="ip" size=40 maxlength=40>
+<P><B><FONT SIZE="+1">
+Press <input type="submit" value="save"> to add the entry to your maclist.
+Press <input type="reset" value="clear"> to reset the form.
+</FONT></B>
+</FORM>
+<HR>
+$ver
+ENDOFTEXT
+ # Close the document cleanly.
+ print &HtmlBot;
+}
+
+sub send_broadcast_packet {
+ my ($nbc,$mac) = @_;
+ if ($mac !~ /^[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}$/i) {
+ print "Malformed MAC address $mac<BR>\n";
+ return;
+ }
+ printf("Sending wakeup packet to %04X:%08X-%s<BR>\n", $port, unpack('N',$nbc), $mac);
+ # Remove colons
+ $mac =~ tr/://d;
+ # Magic packet is 6 bytes of FF followed by the MAC address 16 times
+ $magic = ("\xff" x 6) . (pack('H12', $mac) x 16);
+ # Create socket
+ socket(S, PF_INET, SOCK_DGRAM, getprotobyname('udp')) or die "socket: $!\n";
+ # Enable broadcast
+ setsockopt(S, SOL_SOCKET, SO_BROADCAST, 1) or die "setsockopt: $!\n";
+ # Send the wakeup packet
+ defined(send(S, $magic, 0, sockaddr_in($port, $nbc))) or print "send: $!\n";
+ close(S);
+}
+
+sub process_file {
+ unless (open(F, $maclist)) {
+ print "Error reading $maclist: $!\n";
+ } else {
+ while (<F>) {
+ next if (/^\s*#|^\s*;/); # skip comments
+ my ($mac, $ip) = split;
+ next if (!defined($mac) or $mac eq '');
+ $mac = uc($mac);
+ my $bc = $defbc;
+ ($bc,$mac) = split(/-/,$mac) if ($mac =~ /-/);
+ my $nbc = inet_aton($bc);
+ if ($_[0] eq 'S') {
+ &send_broadcast_packet($nbc, $mac);
+ } else {
+ my $hbc = sprintf("0x%08X", unpack('N',$nbc));
+ print "<TD WIDTH=20%><CENTER><TT>$hbc</TT></CENTER></TD>";
+ print "<TD WIDTH=30%><CENTER><TT>$mac</TT></CENTER></TD>";
+ $ip = ' ' if (!defined($ip) or $ip eq '');
+ print "<TD WIDTH=30%><CENTER><TT>$ip</TT></CENTER></TD>";
+ print "<TD WIDTH=20%><CENTER><input type=checkbox name=mac$. value=$hbc-$mac><TT>WakeUp</TT></CENTER></TD></TR>\n";
+ }
+ }
+ close(F);
+ }
+}
+
+sub add_entry {
+ if (param("brc") !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/i) {
+ print "Malformed broadcast address ",param("brc"),"\n";
+ return;
+ }
+ if (param("mac") !~ /^[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}$/i) {
+ print "Malformed MAC address ",param("mac"),"\n";
+ return;
+ }
+ unless (open(F, ">> $maclist")) {
+ print "Error writing $maclist: $!\n";
+ } else {
+ #my $nbc = inet_aton(param("brc"));
+ #my $hbc = sprintf("0x%8X", unpack('N',$nbc));
+ #print F $hbc."-".uc(param("mac"))." ".param("ip")."\n";
+ print F param("brc")."-".uc(param("mac"))." ".param("ip")."\n";
+ close(F);
+ print "Saved entry to maclist: ".param("brc")."-".uc(param("mac"))." ".param("ip")."\n";
+ }
+}
+
diff --git a/contrib/wakeonlan/readme.txt b/contrib/wakeonlan/readme.txt new file mode 100644 index 0000000..94f2ef3 --- /dev/null +++ b/contrib/wakeonlan/readme.txt @@ -0,0 +1,35 @@ +mp-form.pl - Send magic packets with your web server
+
+This is my trial of waking up PCs with a form via web server.
+The perl script reads in a text file which contains lines of the form
+aa:bb:cc:dd:ee:ff 12.34.56.78 or
+aa:bb:cc:dd:ee:ff foo.bar.com
+aa:bb:cc:dd:ee:ff
+optional a broadcast address mask can be prefixed:
+192.168.1.255-aa:bb:cc:dd:ee:ff
+
+The script is based on wake.pl by Ken Yap who is also the author of the Etherboot package.
+The script uses CGI.pm to parse form input and Socket.pm to send the magic packets, both
+modules should belong to your perl distribution. The script runs with linux as well as
+with NT, with NetWare you have to use the Socket.NLP from recent Perl build #334, with
+Perl build #333 and earlier I got an error from the Socket.pm. You should also update
+your Perl to minimum #331 from CPAN: http://www.cpan.org/ports/index.html#netware.
+This script uses only broadcast so you don't need root rights to use it.
+
+To install the script copy it to your ../cgi-bin directory. Then for Linux do a chmod 755
+to the script. Modify the lines which point to the location of the maclist. If you do not
+have a maclist, the form could save new entries to a list (with unix perhaps you have to
+create an empty file). Check also the first line of mp-form.pl and modify it to point to
+your perl5 location. For NetWare copy the script to /novonyx/suitespot/docs/perlroot.
+
+Older version: If you have problems running the script with CGI.pm you could try the older
+version mp-form1.pl which uses cgi-lib.pl to parse form input. You can get cgi-lib.pl
+from http://cgi-lib.berkeley.edu/. With NetWare you should also use mp-form1.pl as using
+CGI.pm consumes much memory. The older version is also included in the zip archive.
+
+A modified version of the original script is now also included which runs with older
+Getopt::Std.pm as shipped with NetWare. This script you could use from command line
+or from cron. With NetWare copy the script to /perl/scripts; then call from console with:
+perl wakeup.pl <parameters>.
+
+Homepage of the script: http://www.gknw.de/mpform.html
diff --git a/contrib/wakeonlan/wake.pl b/contrib/wakeonlan/wake.pl new file mode 100644 index 0000000..d9be35b --- /dev/null +++ b/contrib/wakeonlan/wake.pl @@ -0,0 +1,116 @@ +#!/usr/bin/perl -w +# +# If called as wake.pl -f file it reads lines of the form +# +# aa:bb:cc:dd:ee;ff 12.34.56.78 or +# aa:bb:cc:dd:ee:ff foo.bar.com +# aa:bb:cc:dd:ee:ff +# +# which are MAC addresses and hostnames of NICs to send a wakeup packet. +# In the first two cases, unicast is used (and root permission may be +# required if the ARP cache needs to be injected with a mapping). +# In the third case, broadcast is used, and anybody can run the command. +# Comments in the file start with #. +# +# Or MAC addresses can be specified on the command line +# +# wake.pl aa.bb.cc.dd.ee.ff +# +# Or both can be used: +# +# wake.pl -f addresses.cfg 11:22:33:44:55:66 +# +# This program may have to be run with superuser privilege because it +# may need to inject an ARP entry into the cache. +# Be careful, you could corrupt valid entries if those NICs are +# already active. +# +# Perl version by ken_yap@users.sourceforge.net after DOS/Windows C version posted by +# Steve_Marfisi@3com.com on the Netboot mailing list +# Released under GNU Public License, 2000-01-08 +# Added switch -q for quiet mode, changed Getopt usage to work with older versions, +# added switch -u for unicast mode, now default is always broadcast mode, +# added switch -s for seach pattern so you could filter entries from file. +# Guenter.Knauf@dialup.soco.de, 2000-10-14 +# +use Getopt::Std; +use Socket; + +getopts('quf:s:'); +if (defined($opt_f)) { + unless (open(F, $opt_f)) { + print STDERR "open: $opt_f: $!\n"; + } else { + while (<F>) { + next if /^\s*#/; # skip comments + ($mac, $ip) = split; + next if !defined($mac) or $mac eq ''; + next if defined($opt_s) and (!/$opt_s/); + if (!defined($ip) or $ip eq '' or !$opt_u) { + &send_broadcast_packet($mac); + } else { + &send_unicast_packet($mac, $ip); + } + } + close(F); + } +} +while (@ARGV) { + send_broadcast_packet(shift(@ARGV)); +} + +sub send_broadcast_packet { + ($mac) = @_; + + if ($mac !~ /^[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}$/i) { + print STDERR "Malformed MAC address $mac\n"; + return; + } + # Remove colons + $mac =~ tr/://d; + # Magic packet is 6 bytes of FF followed by the MAC address 16 times + $magic = ("\xff" x 6) . (pack('H12', $mac) x 16); + # Create socket + socket(S, PF_INET, SOCK_DGRAM, getprotobyname('udp')) + or die "socket: $!\n"; + # Enable broadcast + setsockopt(S, SOL_SOCKET, SO_BROADCAST, 1) + or die "setsockopt: $!\n"; + # Send the wakeup packet + if (!$opt_q) { + print "Sending wakeup packet to MAC address $mac"; + print " ($ip)" if (defined($ip)); + print "\n"; + } + defined(send(S, $magic, 0, sockaddr_in(0x2fff, INADDR_BROADCAST))) + or print STDERR "send: $!\n"; + close(S); +} + +sub send_unicast_packet { + ($mac, $ip) = @_; + + if (!defined($iaddr = inet_aton($ip))) { + print STDERR "Cannot resolve $ip\n"; + return; + } + if ($mac !~ /^[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}$/i) { + print STDERR "Malformed MAC address $mac\n"; + return; + } + # Inject entry into ARP table, in case it's not there already + system("arp -s $ip $mac") == 0 + or print STDERR "Warning: arp command failed, you need to be root\n"; + # Remove colons + $mac =~ tr/://d; + # Magic packet is 6 bytes of FF followed by the MAC address 16 times + $magic = ("\xff" x 6) . (pack('H12', $mac) x 16); + # Create socket + socket(S, PF_INET, SOCK_DGRAM, getprotobyname('udp')) + or die "socket: $!\n"; + # Send the wakeup packet + print "Sending wakeup packet to $ip at MAC address $mac\n" if (!$opt_q); + defined(send(S, $magic, 0, sockaddr_in(0x2fff, $iaddr))) + or print STDERR "send: $!\n"; + close(S); +} diff --git a/contrib/wakeonlan/wakeserver.patch b/contrib/wakeonlan/wakeserver.patch new file mode 100644 index 0000000..43e78b1 --- /dev/null +++ b/contrib/wakeonlan/wakeserver.patch @@ -0,0 +1,179 @@ +To: etherboot-developers@lists.sourceforge.net +X-face: #Qvg5o3u!)WoVDDi4-bFy`fl@""4^pm68%_,`puon{0Q6lQ-O,)3D.J.":A&^,#4O2vc8`? + 3^1lhBh=EQH,"Qq*e1vY":she&t^8:!&Fb32Ed:nM2Y<E9|i[+z20G?CO=E=-IWv;bL"=Y`+`q,ML6 + ,!Me?==j&In1 +Mime-Version: 1.0 +Content-Type: multipart/mixed ; + boundary="==_Exmh_-19971541890" +From: Tilmann Bubeck <bubeck@think-at-work.de> +Message-Id: <20010219195622.C97A84ABD8@chaos.think-at-work.de> +Subject: [Etherboot-developers] Wake-on-LAN patch +Sender: etherboot-developers-admin@lists.sourceforge.net +Errors-To: etherboot-developers-admin@lists.sourceforge.net +X-BeenThere: etherboot-developers@lists.sourceforge.net +X-Mailman-Version: 2.0 +Precedence: bulk +List-Help: <mailto:etherboot-developers-request@lists.sourceforge.net?subject=help> +List-Post: <mailto:etherboot-developers@lists.sourceforge.net> +List-Subscribe: <http://lists.sourceforge.net/lists/listinfo/etherboot-developers>, + <mailto:etherboot-developers-request@lists.sourceforge.net?subject=subscribe> +List-Id: Discussion list for Etherboot developers <etherboot-developers.lists.sourceforge.net> +List-Unsubscribe: <http://lists.sourceforge.net/lists/listinfo/etherboot-developers>, + <mailto:etherboot-developers-request@lists.sourceforge.net?subject=unsubscribe> +List-Archive: <http://lists.sourceforge.net/archives//etherboot-developers/> +Date: Mon, 19 Feb 2001 20:56:22 +0100 +Status: RO +Content-Length: 5351 +Lines: 152 + +This is a multipart MIME message. + +--==_Exmh_-19971541890 +Content-Type: text/plain; charset=us-ascii + + +Hello! + +please find enclosed a patch to optionally enable etherboot to start the +server it is booting from by sending a magic wake-on-lan packet to the +sleeping server first. + +This is very important for an etherboot-server, which is not running all the +time and is not easily accessible from the etherboot machine (e.g. because it +is installed in the basement of the house and one must climb several stairs to +switch the server on...) + +Are the authors of etherboot willing to accept this patch for inclusion? +Please note, that the wake-on-lan code is only compiled in, when setting +appropriate flags in src/Config. + +If you don't want to include the patch, should I change anything of the +implementation or do you dislike the idea at all? + +Thanks! + Till + ++-------+--------------------------------------------------------------+ +| | dr. tilmann bubeck think@work it consulting | +| | professional services | +| think | cell.: +49 172 8842972 widmaierstrasse 58 | +| @work | fax : +49 711 7227734 70567 stuttgart | +| | email: bubeck@think-at-work.de http://www.think-at-work.de | ++-------+ -------------------------------------------------------------+ + + +--==_Exmh_-19971541890 +Content-Type: application/x-patch ; name="etherboot-4.7.17-wol.patch" +Content-Description: etherboot-4.7.17-wol.patch +Content-Disposition: attachment; filename="etherboot-4.7.17-wol.patch" + +diff -r -u etherboot-4.7.17/src/Config etherboot-4.7.17-wol/src/Config +--- etherboot-4.7.17/src/Config Sat Jan 6 16:25:23 2001 ++++ etherboot-4.7.17-wol/src/Config Mon Feb 19 20:28:00 2001 +@@ -113,6 +113,16 @@ + # -DINTERNAL_BOOTP_DATA + # - define if the area 0x93C00-0x93FFF is not available + # for use for bootpd_data by the loader for some reason ++# -DWAKEUP_SERVER ++# - define this for sending a Wake-On-LAN (WOL) ++# "Magic Packet" to a sleeping server, before trying ++# a etherboot. Useful if your server is soft-off all ++# the time and must be switched on when booting a ++# client. Define SERVER_MAC with the MAC address of the ++# server to wakeup. CAUTION! This MAC address is ++# stored in the rom image. The rom is therefore not ++# generic anymore but tailored for a specific ++# server! + + # These default settings compile Etherboot with a small number of options. + # You may wish to enable more of the features if the size of your ROM allows. +@@ -142,6 +152,10 @@ + + # These flags affect the loader that is prepended to the Etherboot image + LCONFIG+= -DMOVEROM ++ ++# Include code for sending a Wake-On-LAN (WOL) "Magic Packet" to a sleeping ++# server, before trying a etherboot. ++CFLAGS32+= -DWAKEUP_SERVER -DSERVER_MAC=0x00,0x01,0x02,0xDA,0xDF,0x77 + + # you should normally not need to change these + RM= rm -f +diff -r -u etherboot-4.7.17/src/main.c etherboot-4.7.17-wol/src/main.c +--- etherboot-4.7.17/src/main.c Fri Jan 5 12:45:29 2001 ++++ etherboot-4.7.17-wol/src/main.c Thu Feb 8 20:46:59 2001 +@@ -137,6 +137,7 @@ + * declarations, but in this case I like to see main() as the first + * routine. + */ ++static void wakeup_server(void) ; + static int bootp(void); + static int rarp(void); + static void load(void); +@@ -217,6 +218,11 @@ + rfc951_sleep(++card_retries); + } + #endif ++ ++#ifdef WAKEUP_SERVER ++ wakeup_server(); ++#endif ++ + while (1) { + /* -1: timeout or ESC + -2: error return from loader +@@ -650,6 +656,46 @@ + return (0); + } + #endif /* DOWNLOAD_PROTO_TFTP */ ++ ++#ifdef WAKEUP_SERVER ++#ifndef SERVER_MAC ++#error "Please define SERVER_MAC to the MAC address of the sleeping server" ++#endif ++ ++/************************************************************************** ++WOL - Wake up a sleeping server by transmitting a Wake-On-LAN (WOL) "Magic ++ Packet", used for restarting machines that have been soft-powered-down ++ (ACPI D3-warm state). It currently generates the standard AMD Magic ++ Packet format. ++**************************************************************************/ ++static void wakeup_server(void) ++{ ++ unsigned char data[100]; ++ int i, len, retry; ++ char server_adr[] = { SERVER_MAC }; ++ unsigned long time; ++ ++ /* build "Magic Packet" */ ++ len = 0; ++ data[len++] = 0xff; ++ data[len++] = 0xff; ++ data[len++] = 0xff; ++ data[len++] = 0xff; ++ data[len++] = 0xff; ++ data[len++] = 0xff; ++ for ( i = 0; i < 16; i++ ) { ++ memcpy(&data[len], server_adr, 6); ++ len += 6; ++ } ++ ++ printf("Sending Wake-On-LAN (WOL) \"Magic Packet\" to server %b:%b:%b:%b:%b:%b...", ++ server_adr[0], server_adr[1], server_adr[2], ++ server_adr[3], server_adr[4], server_adr[5]); ++ ++ eth_transmit(broadcast, 0x0842, len, data); ++ printf("done\n"); ++} ++#endif + + #ifdef RARP_NOT_BOOTP + /************************************************************************** + +--==_Exmh_-19971541890-- + + + +_______________________________________________ +Etherboot-developers mailing list +Etherboot-developers@lists.sourceforge.net +http://lists.sourceforge.net/lists/listinfo/etherboot-developers diff --git a/contrib/wakeonlan/wakeup.pl b/contrib/wakeonlan/wakeup.pl new file mode 100644 index 0000000..83cf363 --- /dev/null +++ b/contrib/wakeonlan/wakeup.pl @@ -0,0 +1,86 @@ +#!/usr/bin/perl
+#!/usr/bin/perl -w
+#
+# If called as wakeup.pl -f file it reads lines of the form
+#
+# aa:bb:cc:dd:ee;ff 12.34.56.78 or
+# aa:bb:cc:dd:ee:ff foo.bar.com
+# aa:bb:cc:dd:ee:ff
+#
+# which are MAC addresses and hostnames of NICs to send a wakeup packet.
+# Broadcast is used to send the magic packets, so anybody can run the command.
+# Notice that many routers do NOT forward broadcasts automatically!!
+# Comments in the file start with #.
+#
+# Or MAC addresses can be specified on the command line
+#
+# wakeup.pl aa.bb.cc.dd.ee.ff
+#
+# Or both can be used:
+#
+# wakeup.pl -f addresses.cfg 11:22:33:44:55:66
+#
+# Use option -b to specify broadcast mask.
+# Use option -d for screen output.
+#
+# Perl version by ken.yap@acm.org after DOS/Windows C version posted by
+# Steve_Marfisi@3com.com on the Netboot mailing list
+# Released under GNU Public License, 2000-01-08
+# Modified for use with NetWare by gk@gknw.de, 2000-09-18
+# With NetWare you have to use Socket.NLP from NetWare Perl #334 or higher!
+# You could download Socket.NLP #334 from: http://www.gknw.de/mpform.html
+#
+
+use Getopt::Std;
+use Socket;
+
+getopts('b:df:p:q');
+
+$brc = $opt_b || '255.255.255.255';
+$port = $opt_p || 60000;
+die "Malformed broadcast address: $brc!\n" if ($brc !~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$)/);
+
+if (defined($opt_f)) {
+ unless (open(F, $opt_f)) {
+ print "open: $opt_f: $!\n";
+ } else {
+ print "Using file $opt_f...\n" if ($opt_d);
+ while (<F>) {
+ next if /^\s*#/; # skip comments
+ my ($mac, $ip) = split;
+ next if !defined($mac) or $mac eq '';
+ &send_broadcast_packet($mac,$ip);
+ }
+ close(F);
+ }
+}
+while (@ARGV) {
+ send_broadcast_packet(shift(@ARGV));
+}
+
+sub send_broadcast_packet {
+ my ($mac,$ip) = @_;
+ if ($mac =~ /-/) {
+ ($bc,$mac) = split(/-/,$mac);
+ } else {
+ $bc = $brc;
+ }
+ if ($mac !~ /^[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}$/i) {
+ print "Malformed MAC address $mac\n";
+ return;
+ }
+ my $nbc = inet_aton($bc);
+ # Remove colons
+ $mac =~ tr/://d;
+ # Magic packet is 6 bytes of FF followed by the MAC address 16 times
+ $magic = ("\xff" x 6) . (pack('H12', $mac) x 16);
+ # Create socket
+ socket(S, PF_INET, SOCK_DGRAM, getprotobyname('udp')) or die "socket: $!\n";
+ # Enable broadcast
+ setsockopt(S, SOL_SOCKET, SO_BROADCAST, 1) or die "setsockopt: $!\n";
+ # Send the wakeup packet
+ printf("$0: Sending wakeup packet to %04X:%08X-%s %s\n",$port,unpack('N',$nbc),uc($mac),$ip) if ($opt_d);
+ defined(send(S, $magic, 0, sockaddr_in($port, $nbc)))
+ or print "send: $!\n";
+ close(S);
+}
diff --git a/contrib/wakeonlan/wakeup.txt b/contrib/wakeonlan/wakeup.txt new file mode 100644 index 0000000..b96b3e4 --- /dev/null +++ b/contrib/wakeonlan/wakeup.txt @@ -0,0 +1,9 @@ +# maclist - mac addresses for wakeonlan +00:BA:BE:FA:CE:00 mainframe +00:11:22:33:44:5A maschine1 +00:11:22:33:44:B5 maschine2 +00:11:22:33:44:5C maschine3 +0A:BB:CC:DD:EE:F9 macintosh +1A:BB:CC:DD:E6:FF +3A:BB:CC:DD:EE:F5 testpc +3A:BB:CC:DD:EE:F6 123.45.6.7 diff --git a/contrib/wakeonlan/wol.c b/contrib/wakeonlan/wol.c new file mode 100644 index 0000000..07b7e4f --- /dev/null +++ b/contrib/wakeonlan/wol.c @@ -0,0 +1,374 @@ +/***************************************************************************** + * + * wol.c - Wake-On-LAN utility to wake a networked PC + * + * by R. Edwards (bob@cs.anu.edu.au), January 2000 + * (in_ether routine adapted from net-tools-1.51/lib/ether.c by + * Fred N. van Kempen) + * added file input, some minor changes for compiling for NetWare + * added switches -q and -d=<ms>, added Win32 target support + * by G. Knauf (gk@gknw.de), 30-Jan-2001 + * added switches -b=<bcast> and -p=<port> + * by G. Knauf (gk@gknw.de), 10-Okt-2001 + * added OS/2 target support + * by G. Knauf (gk@gknw.de), 24-May-2002 + * + * This utility allows a PC with WOL configured to be powered on by + * sending a "Magic Packet" to it's network adaptor (see: + * http://www.amd.com/products/npd/overview/20212.html). + * Only the ethernet dest address needs to be given to make this work. + * Current version uses a UDP broadcast to send out the Magic Packet. + * + * compile with: gcc -Wall -o wol wol.c + * with Solaris: (g)cc -o wol wol.c -lsocket -lnsl + * with MingW32: gcc -Wall -o wol wol.c -lwsock32 + * + * usage: wol <dest address> + * where <dest address> is in [ddd.ddd.ddd.ddd-]xx:xx:xx:xx:xx:xx format. + * or: wol [-q] [-b=<bcast>] [-p=<port>] [-d=<ms>] -f=<File name> + * where <File name> is a file containing one dest address per line, + * optional followed by a hostname or ip separated by a blank. + * -b sets optional broadcast address, -p sets optional port, + * -q supresses output, -d=<ms> delays ms milliseconds between sending. + * + * Released under GNU Public License January, 2000. + */ + +#define VERSION "1.12.2 (c) G.Knauf http://www.gknw.de/" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef WATTCP + #define strncasecmp strnicmp + #include <ctype.h> + #include <dos.h> + #include <tcp.h> +#else +#ifdef WIN32 /* Win32 platform */ + #define USE_WINSOCKAPI + #define delay Sleep + #if (defined(__LCC__) || defined(__BORLANDC__)) + #define strncasecmp strnicmp + #else + #define strncasecmp _strnicmp + #endif +#elif defined(N_PLAT_NLM) /* NetWare platform */ +#ifdef __NOVELL_LIBC__ + #include <ctype.h> +#else + extern int isdigit(int c); /* no ctype.h for NW3.x */ + #include <nwthread.h> + #define strncasecmp strnicmp +#endif +#elif defined(__OS2__) /* OS/2 platform */ + #ifdef __EMX__ + #define strncasecmp strnicmp + #endif + extern int DosSleep(long t); + #define delay DosSleep +#else /* all other platforms */ + #define delay(t) usleep(t*1000) +#endif +#ifndef N_PLAT_NLM /* ! NetWare platform */ + #include <ctype.h> +#endif +#ifndef WIN32 /* ! Win32 platform */ + #include <unistd.h> +#endif +#ifdef USE_WINSOCKAPI /* Winsock2 platforms */ + #ifdef N_PLAT_NLM /* NetWare platform */ + #include <ws2nlm.h> + #else + #include <winsock.h> + #endif + #define close(s) { \ + closesocket(s); \ + WSACleanup(); \ + } +#else /* Socket platforms */ + #include <sys/types.h> + #include <sys/socket.h> + #include <netinet/in.h> + #if defined(__OS2__) && !defined(__EMX__) + #include <utils.h> + #else + #include <arpa/inet.h> + #endif +#endif + +#endif + +static int read_file (char *destfile); +static int in_ether (char *bufp, unsigned char *addr); +static int send_wol (char *dest, char *host); + + +char *progname; +int quiet = 0; +int twait = 0; +unsigned int port = 60000; +unsigned long bcast = 0xffffffff; + +int main (int argc, char *argv[]) { + + int cmdindx = 0; + progname = argv[0]; + + if (argc > 1) { + /* parse input parameters */ + for (argc--, argv++; *argv; argc--, argv++) { + char *bp; + char *ep; + + if (strncasecmp (*argv, "-", 1) == 0) { + if (strncasecmp (*argv, "-F=", 3) == 0) { + bp = *argv + 3; + read_file (bp); + } else if (strncasecmp (*argv, "-B=", 3) == 0) { + bp = *argv + 3; + bcast = inet_addr(bp); + if (bcast == -1) { + fprintf (stderr, "%s: expected address argument at %s\n", progname, *argv); + exit (1); + } + } else if (strncasecmp (*argv, "-D=", 3) == 0) { + bp = *argv + 3; + twait = strtol (bp, &ep, 0); + if (ep == bp || *ep != '\0') { + fprintf (stderr, "%s: expected integer argument at %s\n", progname, *argv); + exit (1); + } + } else if (strncasecmp (*argv, "-P=", 3) == 0) { + bp = *argv + 3; + port = strtol (bp, &ep, 0); + if (ep == bp || *ep != '\0') { + fprintf (stderr, "%s: expected integer argument at %s\n", progname, *argv); + exit (1); + } + } else if (strncasecmp (*argv, "-Q", 2) == 0) { + quiet = 1; + } else if (strncasecmp (*argv, "-V", 2) == 0) { + fprintf (stderr, "\r%s Version %s\n", progname, VERSION); + exit (0); + } else { + fprintf (stderr, "\r%s: invalid or unknown option %s\n", progname, *argv); + exit (1); + } + } else { + send_wol (*argv, ""); + } + cmdindx++; + } + return (0); + } else { + /* No arguments given -> usage message */ + fprintf (stderr, "\rUsage: %s [-q] [-b=<bcast>] [-p=<port>] [-d=<ms>] -f=<file> | <dest>\n", progname); + fprintf (stderr, " need at least hardware address or file option\n"); + return (-1); + } +} + + + +static int in_ether (char *bufp, unsigned char *addr) { + + char c, *orig; + int i; + unsigned char *ptr = addr; + unsigned val; + + i = 0; + orig = bufp; + while ((*bufp != '\0') && (i < 6)) { + val = 0; + c = *bufp++; + if (isdigit(c)) + val = c - '0'; + else if (c >= 'a' && c <= 'f') + val = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + val = c - 'A' + 10; + else { +#ifdef DEBUG + fprintf (stderr, "\rin_ether(%s): invalid ether address!\n", orig); +#endif + errno = EINVAL; + return (-1); + } + val <<= 4; + c = *bufp; + if (isdigit(c)) + val |= c - '0'; + else if (c >= 'a' && c <= 'f') + val |= c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + val |= c - 'A' + 10; + else if (c == ':' || c == 0) + val >>= 4; + else { +#ifdef DEBUG + fprintf (stderr, "\rin_ether(%s): invalid ether address!\n", orig); +#endif + errno = EINVAL; + return (-1); + } + if (c != 0) + bufp++; + *ptr++ = (unsigned char) (val & 0377); + i++; + + /* We might get a semicolon here - not required. */ + if (*bufp == ':') { + if (i == 6) { + ; /* nothing */ + } + bufp++; + } + } + if (bufp - orig != 17) { + return (-1); + } else { + return (0); + } +} /* in_ether */ + + +static int read_file (char *destfile) { + + FILE *pfile = NULL; + char dest[64]; + char host[32]; + char buffer[512]; + + pfile = fopen (destfile, "r+"); + + if (pfile) { + while (fgets (buffer, 511, pfile) != NULL) { + if (buffer[0] != '#' && buffer[0] != ';') { + dest[0] = host[0] = '\0'; + sscanf (buffer, "%s %s", dest, host); + send_wol (dest, host); + } + } + fclose (pfile); + return (0); + } else { + fprintf (stderr, "\r%s: destfile '%s' not found\n", progname, destfile); + return (-1); + } +} + + +static int send_wol (char *dest, char *host) { + + int i, j; + int packet; + struct sockaddr_in sap; + unsigned char ethaddr[8]; + unsigned char *ptr; + unsigned char buf [128]; + unsigned long bc; + char mask[32]; + char *tmp; +#ifdef USE_WINSOCKAPI + WORD wVersionRequested; + WSADATA wsaData; + int err; +#endif +#ifdef WATTCP + static udp_Socket sock; + udp_Socket *s; +#else + int optval = 1; +#endif + + /* Fetch the broascast address if present. */ + if ((tmp = strstr(dest,"-"))) { +printf("found: %s\n", tmp); + tmp[0] = 32; + sscanf (dest, "%s %s", mask, dest); + bc = inet_addr(mask); +printf("bc: string %s address %08lX\n", mask, bc); + if (bc == -1) { + fprintf (stderr, "\r%s: expected address argument at %s\n", progname, mask); + return (-1); + } + } else + bc = bcast; + + /* Fetch the hardware address. */ + if (in_ether (dest, ethaddr) < 0) { + fprintf (stderr, "\r%s: invalid hardware address\n", progname); + return (-1); + } + +#ifdef USE_WINSOCKAPI + /* I would like to have Socket Vers. 1.1 */ + wVersionRequested = MAKEWORD(1, 1); + err = WSAStartup (wVersionRequested, &wsaData); + if (err != 0) { + fprintf (stderr, "\r%s: couldn't init Winsock Version 1.1\n", progname); + WSACleanup (); + return (-1); + } +#endif + + /* setup the packet socket */ +#ifdef WATTCP + sock_init(); + s = &sock; + if (!udp_open( s, 0, bc, port, NULL )) { +#else + if ((packet = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { +#endif + fprintf (stderr, "\r%s: socket failed\n", progname); +#ifdef USE_WINSOCKAPI + WSACleanup (); +#endif + return (-1); + } + +#ifndef WATTCP + /* Set socket options */ + if (setsockopt (packet, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof (optval)) < 0) { + fprintf (stderr, "\r%s: setsocket failed %s\n", progname, strerror (errno)); + close (packet); + return (-1); + } + + /* Set up broadcast address */ + sap.sin_family = AF_INET; + sap.sin_addr.s_addr = bc; /* broadcast address */ + sap.sin_port = htons(port); +#endif + + /* Build the message to send - 6 x 0xff then 16 x dest address */ + ptr = buf; + for (i = 0; i < 6; i++) + *ptr++ = 0xff; + for (j = 0; j < 16; j++) + for (i = 0; i < 6; i++) + *ptr++ = ethaddr [i]; + + /* Send the packet out */ +#ifdef WATTCP + sock_write( s, buf, 102 ); + sock_close( s ); +#else + if (sendto (packet, (char *)buf, 102, 0, (struct sockaddr *)&sap, sizeof (sap)) < 0) { + fprintf (stderr, "\r%s: sendto failed, %s\n", progname, strerror(errno)); + close (packet); + return (-1); + } + close (packet); +#endif + if (!quiet) fprintf (stderr, "\r%s: packet sent to %04X:%08lX-%s %s\n", + progname, port, (unsigned long)htonl(bc), dest, host); + if (twait > 0 ) { + delay (twait); + } + return (0); +} + |