Index: patches/powerpc-utils_1.1.3-fixes-2.patch
===================================================================
--- patches/powerpc-utils_1.1.3-fixes-2.patch	(revision f2b4aa359ed1efb8e2135b995e9a4ec5ecf1ed13)
+++ patches/powerpc-utils_1.1.3-fixes-2.patch	(revision f2b4aa359ed1efb8e2135b995e9a4ec5ecf1ed13)
@@ -0,0 +1,963 @@
+Submitted By: Ken Moffat <ken@linuxfromscratch.org>
+Date: 2005-11-23
+Initial Package Version: 1.1.3
+Upstream Status: Package is maintained by debian, this cherry-picks
+Origin: From debian 1.1.3-18.diff, edited
+Description: Makes it work on New World, fixes compile error, updated to
+ allow -m32 to be passed via EXTRACFLAGS in multilib.
+
+ Some of the debian powerpc-utils_1.1.3-18.diff, but only the parts relevant
+to nvsetenv and nvsetvol - the remainder may be useful on an Old World Mac,
+but they are no use on New World.  The -D_GNU_SOURCE apparently helps on
+powerpc64.  I've also removed bogus messages advising you to update your
+headers when IOC_NVRAM_SYNC isn't defined : it hasn't existed for a long
+time.  Finally, I ran the nvsetenv.sgml through docbook2txt -man to get a
+proper man page, because most people won't have docbook utils installed. 
+
+diff -Nuar pmac-utils.orig/Makefile pmac-utils/Makefile
+--- pmac-utils.orig/Makefile	1998-07-21 14:22:28.000000000 +0100
++++ pmac-utils/Makefile	2005-11-17 15:16:52.000000000 +0000
+@@ -22,8 +22,8 @@
+ 
+ SGMLMAN	= sgml2txt -man
+ CC	= gcc -Wall -Wstrict-prototypes
+-CFLAGS	= -O2 -fsigned-char 
+-LDFLAGS = -s
++CFLAGS	= $(EXTRACFLAGS) -O2 -fsigned-char -D_GNU_SOURCE
++LDFLAGS =
+ INSTALL	= /usr/bin/install -c
+ SOUND_INC = -I.
+ 
+@@ -42,8 +42,12 @@
+ mousemode:
+ 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $@.c
+ 
+-nvsetenv:
++nvsetenv: nvsetenv.c nwnvsetenv.c
++	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $@.c nwnvsetenv.c
++
++nvsetvol:
+ 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $@.c
++ 
+ 
+ nvvideo:
+ 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $@.c
+diff -Nuar pmac-utils.orig/nvsetenv.8 pmac-utils/nvsetenv.8
+--- pmac-utils.orig/nvsetenv.8	1970-01-01 01:00:00.000000000 +0100
++++ pmac-utils/nvsetenv.8	2005-11-17 20:39:47.000000000 +0000
+@@ -0,0 +1,256 @@
++.if n .ds Q \&"
++.if t .ds Q ``
++.if n .ds U \&"
++.if t .ds U ''
++.TH "NVSETENV" 8 
++.tr \&
++.nr bi 0
++.nr ll 0
++.nr el 0
++.de DS
++..
++.de DE
++..
++.de Pp
++.ie \\n(ll>0 \{\
++.ie \\n(bi=1 \{\
++.nr bi 0
++.if \\n(t\\n(ll=0 \{.IP \\(bu\}
++.if \\n(t\\n(ll=1 \{.IP \\n+(e\\n(el.\}
++.\}
++.el .sp 
++.\}
++.el \{\
++.ie \\nh=1 \{\
++.LP
++.nr h 0
++.\}
++.el .PP 
++.\}
++..
++.SH NAME
++
++.Pp
++\fBnvsetenv\fP - change/view Open Firmware environment variables 
++.Pp
++.SH SYNOPSIS
++
++.Pp
++\fBnvsetenv 
++\f(CR[\fP\fIvariable\fP \f(CR[\fP\fIvalue\fP\f(CR\fB]]\fP\fP\fP
++.Pp
++.SH DESCRIPTION
++
++.Pp
++\fBnvsetenv\fP is a program to adjust or view the Open Firmware (OF)
++boot parameters stored in non-volatile (battery-powered) RAM.
++\fBnvsetenv\fP will show the current values of all OF's environment
++variables when no parameters are given.
++.Pp
++.SH OPTIONS
++
++.Pp
++.nr ll +1
++.nr t\n(ll 2
++.if \n(ll>1 .RS
++.IP "\fIvariable\fP"
++.nr bi 1
++.Pp
++nvsetenv will show current value of an OF's
++variable, if no value is given
++.IP "\fIvariable value\fP"
++.nr bi 1
++.Pp
++nvsetenv will set \fIvariable\fP to
++\fIvalue\fP
++.if \n(ll>1 .RE
++.nr ll -1
++.Pp
++.SH EXAMPLES
++
++.Pp
++This example will set the boot device to the first SCSI disk on the
++internal SCSI bus, using /vmlinux as boot image, trying to
++use the third partition as root partition.
++.DS
++.sp 
++.ft RR
++.nf
++        > nvsetenv boot-device  \&"scsi-int/sd@0:0\&"
++        > nvsetenv boot-file    \&" /vmlinux root=/dev/sda3\&"
++.DE
++.fi 
++.ec
++.ft P
++.sp
++.Pp
++Alternatives boot devices are: 
++.DS
++.sp 
++.ft RR
++.nf
++        scsi/sd@1:0             SCSI disk at ID 1
++        ata/ata-disk@0:0        Internal IDE disk
++.DE
++.fi 
++.ec
++.ft P
++.sp
++.Pp
++You can also boot from a floppy, you need a XCOFF-format kernel image
++(in this example: vmlinux.coff), copied to a HFS format high-density
++(1.44Mb) floppy.
++.DS
++.sp 
++.ft RR
++.nf
++        > nvsetenv boot-device  \&"fd:vmlinux.coff\&"
++        > nvsetenv boot-file    \&" root=/dev/sda3\&"
++.DE
++.fi 
++.ec
++.ft P
++.sp
++
++To return to MacOS, do:
++.DS
++.sp 
++.ft RR
++.nf
++        > nvsetenv boot-device  \&"/AAPL,ROM\&"
++.DE
++.fi 
++.ec
++.ft P
++.sp
++.Pp
++Valid values for \&"input-devices\&" are:
++.DS
++.sp 
++.ft RR
++.nf
++        ttya                    Modem serial port
++        ttyb                    Printer serial port
++        kbd                     Keyboard
++        enet                    Ethernet interface
++.DE
++.fi 
++.ec
++.ft P
++.sp
++.Pp
++Valid values for \&"output-devices\&" are (machine and/or OF dependent):
++.DS
++.sp 
++.ft RR
++.nf
++        screen                  Screen display (newer machines)
++        /chaos/control          Screen display (7500, 7600 and 8500)
++        /bandit/ATY,264GT-B     Screen display (6500)
++.DE
++.fi 
++.ec
++.ft P
++.sp
++.Pp
++OF is not designed to wait for your hard disk to spin up
++(remember MacOS boots from ROM).
++Use the following setting to have OF retry to boot from your disk 
++until is has spun up:
++.DS
++.sp 
++.ft RR
++.nf
++        > nvsetenv boot-command \&"begin ['] boot catch 1000 ms cr again\&"
++.DE
++.fi 
++.ec
++.ft P
++.sp
++.Pp
++You only have to append an \&"S\&" to the \&"boot-file\&" variable to boot
++Linux in single user mode.
++.Pp
++You can use install your own nvramrc patch using the following command:
++.DS
++.sp 
++.ft RR
++.nf
++        > nvsetenv nvramrc \&"`cat file.patch`\&"
++.DE
++.fi 
++.ec
++.ft P
++.sp
++
++(please note the backticks!), or: 
++.DS
++.sp 
++.ft RR
++.nf
++        > nvsetenv nvramrc \&"$(cat file.patch)\&"
++.DE
++.fi 
++.ec
++.ft P
++.sp
++.Pp
++.SH FILES
++
++.Pp
++.nr ll +1
++.nr t\n(ll 2
++.if \n(ll>1 .RS
++.IP "\fI/dev/nvram\fP"
++.nr bi 1
++.Pp
++character device with major number 10
++and minor number 144
++.IP "\fI/proc/cpuinfo\fP"
++.nr bi 1
++.Pp
++to identify New/Old-World machines
++.if \n(ll>1 .RE
++.nr ll -1
++.Pp
++.SH SEE ALSO
++
++.Pp
++macos(8)
++.Pp
++.SH AUTHORS
++
++.Pp
++.DS
++.sp 
++.ft RR
++.nf
++Paul Mackerras <paulus@cs.anu.edu.au> (program)
++.DE
++.fi 
++.ec
++.ft P
++.sp
++
++.DS
++.sp 
++.ft RR
++.nf
++Richard van Hees <R.M.vanHees@phys.uu.nl> (documentation)
++.DE
++.fi 
++.ec
++.ft P
++.sp
++
++.DS
++.sp 
++.ft RR
++.nf
++Klaus Halfmann  <halfmann@libra.de> (NewWorld code)
++.DE
++.fi 
++.ec
++.ft P
++.sp
++.Pp
+diff -Nuar pmac-utils.orig/nvsetenv.c pmac-utils/nvsetenv.c
+--- pmac-utils.orig/nvsetenv.c	1997-04-28 14:29:05.000000000 +0100
++++ pmac-utils/nvsetenv.c	2005-11-17 14:57:57.000000000 +0000
+@@ -1,15 +1,32 @@
++/*	nvsetnv.c
++
++	used to set the Envenrioment variables in power macs NVram.
++	Decides via /proc/cpuinfo which type of machine is used.
++
++		Copyright (C) 1996-1998 by Paul Mackerras.
++	nwcode: Copyright (C) 2000	by Klaus Halfmann
++
++	see README for details
++*/
++
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
+ #include <fcntl.h>
++#include <sys/ioctl.h>
++#include <asm/nvram.h>
++#ifndef IOC_NVRAM_SYNC
++#define IOC_NVRAM_SYNC _IO('p', 0x43)
++#endif
+ 
+-#define NVSTART	0x1800
+-#define NVSIZE	0x800
++#define NVSTART		0x1800 	// Start of the NVRam OF partition
++#define NVSIZE		0x800	// Size of of the NVRam
+ #define MXSTRING        128
+ #define N_NVVARS	(int)(sizeof(nvvars) / sizeof(nvvars[0]))
++#define NVMAGIC		0x1275
+ 
+-static int nvfd, nvstr_used;
++static int  nvstr_used;
+ static char nvstrbuf[NVSIZE];
+ 
+ struct nvram {
+@@ -24,12 +41,13 @@
+     unsigned long  vals[1];
+ };
+ 
+-union {
+-    struct nvram nv;
+-    char c[NVSIZE];
+-    unsigned short s[NVSIZE/2];
+-} nvbuf;
++typedef union {
++    struct nvram 	nv;
++    char 		c[NVSIZE];
++    unsigned short 	s[NVSIZE/2];
++} nvbuftype;
+ 
++nvbuftype nvbuf;
+ 
+ enum nvtype {
+     boolean,
+@@ -70,16 +88,21 @@
+     {"boot-command", string},
+ };
+ 
++	// Calculated number of variables
++#define N_NVVARS	(int)(sizeof(nvvars) / sizeof(nvvars[0]))
++
+ union nvval {
+-    unsigned long word_val;
+-    char *str_val;
++    unsigned long 	word_val;
++    char 		*str_val;
+ } nvvals[32];
+ 
+-int
+-nvcsum( void )
++extern int checkNewWorld(void); 		// from nwnvsetenv
++extern int nvNew(int ac, char** av, int nfd); 	// from nwnvsetenv
++
++int nvcsum( void )
+ {
+-    int i;
+-    unsigned c;
++    int 	i;
++    unsigned	c;
+     
+     c = 0;
+     for (i = 0; i < NVSIZE/2; ++i)
+@@ -89,28 +112,29 @@
+     return c & 0xffff;
+ }
+ 
+-void
+-nvload( void )
++static void nvload( int nvfd )
+ {
+     int s;
+ 
+     if (lseek(nvfd, NVSTART, 0) < 0
+ 	|| read(nvfd, &nvbuf, NVSIZE) != NVSIZE) {
+-	perror("Error reading /dev/nvram");
++	perror("Error reading nvram device");
+ 	exit(EXIT_FAILURE);
+     }
++    if (nvbuf.nv.magic != NVMAGIC)
++	(void) fprintf(stderr, "Warning: Bad magic number %x\n",
++			 nvbuf.nv.magic);
+     s = nvcsum();
+     if (s != 0xffff)
+        (void) fprintf(stderr, "Warning: checksum error (%x) on nvram\n", 
+ 		      s ^ 0xffff);
+ }
+ 
+-void
+-nvstore(void)
++static void nvstore(int nvfd)
+ {
+     if (lseek(nvfd, NVSTART, 0) < 0
+ 	|| write(nvfd, &nvbuf, NVSIZE) != NVSIZE) {
+-	perror("Error writing /dev/nvram");
++	perror("Error writing nvram device");
+ 	exit(EXIT_FAILURE);
+     }
+ }
+@@ -145,8 +169,7 @@
+     }
+ }
+ 
+-void
+-nvpack( void )
++void nvpack( void )
+ {
+     int     i, vi;
+     size_t  off, len;
+@@ -184,7 +207,7 @@
+     nvbuf.nv.cksum = (unsigned short int) (~nvcsum());
+ }
+ 
+-void
++static void
+ print_var(int i, int indent)
+ {
+     char *p;
+@@ -207,8 +230,7 @@
+     (void) printf("\n");
+ }
+ 
+-void
+-parse_val(int i, char *str)
++void parse_val(int i, char *str)
+ {
+     char *endp;
+ 
+@@ -238,12 +260,38 @@
+     }
+ }
+ 
+-int 
+-main(int ac, char **av)
++
++void nvOld(int ac, char** av, int i, int nvfd)
++{
++    nvload(nvfd);
++    nvunpack();
++
++    switch (ac) {
++    case 1:
++	for (i = 0; i < N_NVVARS; ++i) {
++	    (void) printf("%-16s", nvvars[i].name);
++	    print_var(i, 16);
++	}
++	break;
++
++    case 2:
++	print_var(i, 0);
++	break;
++	
++    case 3:
++	parse_val(i, av[2]);
++	nvpack();
++	nvstore(nvfd);
++	break;
++    }
++}
++
++int main(int ac, char **av)
+ {
+-    int i = 0, l, print;
++    int i = 0, l, print, nvfd, newWorld;
+ 
+     l = (int) strlen(av[0]);
++    // print when no value is set OR we are aclled as <xxx>printenv
+     print = (int) (ac <= 2 || 
+ 		   (l > 8 && strcmp(&av[0][l-8], "printenv") == 0));
+     if (print != 0 && ac > 2) {
+@@ -255,7 +303,9 @@
+ 	exit(EXIT_FAILURE);
+     }
+ 
+-    if (ac >= 2) {
++    newWorld = checkNewWorld();
++    
++    if (!newWorld && ac >= 2) {
+ 	for (i = 0; i < N_NVVARS; ++i)
+ 	    if (strcmp(av[1], nvvars[i].name) == 0)
+ 		break;
+@@ -266,33 +316,21 @@
+ 	}
+     }
+ 
+-    nvfd = open("/dev/nvram", ac <= 2 ? O_RDONLY: O_RDWR);
++    nvfd = open("/dev/misc/nvram", ac <= 2 ? O_RDONLY: O_RDWR);
+     if (nvfd < 0) {
+-	perror("Couldn't open /dev/nvram");
++      nvfd = open("/dev/nvram", ac <= 2 ? O_RDONLY: O_RDWR);
++      if (nvfd < 0) {
++	perror("Couldn't open nvram device");
+ 	exit(EXIT_FAILURE);
+-    }
+-    nvload();
+-    nvunpack();
+-
+-    switch (ac) {
+-    case 1:
+-	for (i = 0; i < N_NVVARS; ++i) {
+-	    (void) printf("%-16s", nvvars[i].name);
+-	    print_var(i, 16);
+-	}
+-	break;
+-
+-    case 2:
+-	print_var(i, 0);
+-	break;
+-	
+-    case 3:
+-	parse_val(i, av[2]);
+-	nvpack();
+-	nvstore();
+-	break;
++      }
+     }
+ 
++    if (newWorld)
++    	nvNew(ac, av, nvfd);
++    else
++    	nvOld(ac, av, i, nvfd);
++    
++    (void) ioctl(nvfd, IOC_NVRAM_SYNC);
+     (void) close(nvfd);
+     exit(EXIT_SUCCESS);
+ }
+diff -Nuar pmac-utils.orig/nvsetvol.8 pmac-utils/nvsetvol.8
+--- pmac-utils.orig/nvsetvol.8	1970-01-01 01:00:00.000000000 +0100
++++ pmac-utils/nvsetvol.8	2005-11-17 21:37:20.000000000 +0000
+@@ -0,0 +1,27 @@
++.TH NVSETVOL 8 "16th February 2003"
++
++.SH NAME
++nvsetvol \- tool for changing startup volume of PowerMac machines
++
++.SH SYNOPSIS
++.B nvsetvol
++[
++.B volume
++]
++
++.SH DESCRIPTION
++.B nvsetvol
++queries and sets the base volume of a PowerMac machine.  With no options,
++.B nvsetvol
++displays the current volume; with a numerical argument, it sets the volume.
++The
++.B volume
++argument should be a number from 0 to 255.  0 will turn off the annoying
++startup chime.
++
++.SH AUTHOR
++.B nvsetvol
++was written by Matteo Frigo <athena@fftw.org>.
++
++This manual page was written by Daniel Jacobowitz <dan@debian.org> for the
++Debian GNU/Linux distribution.
+diff -Nuar pmac-utils.orig/nvsetvol.c pmac-utils/nvsetvol.c
+--- pmac-utils.orig/nvsetvol.c	1970-01-01 01:00:00.000000000 +0100
++++ pmac-utils/nvsetvol.c	2005-11-17 21:43:16.000000000 +0000
+@@ -0,0 +1,110 @@
++/* set volume of the startup chime in the PowerMac nvram. 
++
++   Written by Matteo Frigo <athena@fftw.org>.
++   $Id: nvsetvol.c,v 1.1 2003/01/11 11:26:30 athena Exp $
++
++   This program is in the public domain.
++*/
++
++/* The volume is stored as a byte at address 8 in the parameter ram. */
++
++#include <string.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <sys/ioctl.h>
++#include <asm/nvram.h>
++#ifndef IOC_NVRAM_SYNC
++#define IOC_NVRAM_SYNC _IO('p', 0x43)
++#endif
++
++typedef struct {
++     unsigned char sig;
++     unsigned char cksum;
++     unsigned short len;
++     char name[12];
++} header;
++
++void die(const char *s) __attribute__((noreturn));
++void die(const char *s)
++{
++     perror(s);
++     exit(1);
++}
++
++void seek_pram(int fd, int offset)
++{
++     if (lseek(fd, offset, SEEK_SET) < 0)
++	  die("lseek");
++}
++
++// MSch: only works for newworld - oldworld have XPRAM at offset 0x1300 fixed. 
++
++int find_pram(int fd, int *size)
++{
++     header buf;
++     int offset = 0;
++     int rc = 0;
++     while((rc = read(fd, &buf, sizeof(header))) == sizeof(header)) {
++	  int sz = buf.len * 16;
++	  // what's the sig in char?
++	  // if (buf.sig == 0x1275) fprintf(stderr, "sig at offset %d rc %d buf.len %d buf.name %s \n", offset, rc, buf.len, buf.name);
++	  // if (buf.sig == 0x5a) fprintf(stderr, "sig at offset %x rc %d buf.len %x buf.name %s \n", offset, rc, buf.len, buf.name);
++	  // if (sz) fprintf(stderr, "offset %x rc %d sig %x buf.len %x buf.name %s \n", offset, rc, buf.sig, buf.len, buf.name);
++	  if (!strncmp(buf.name, "APL,MacOS75", 11)) {
++	       *size = sz - sizeof(header);
++	       // fprintf(stderr, "XPRAM offset %x size %x\n", offset + sizeof(header), *size); 
++	       return offset + sizeof(header);
++	  }
++	  if (sz)
++	    offset += sz;
++          else
++            offset += sizeof(header);
++	  seek_pram(fd, offset);
++     }
++     // no Core99 style PRAM found - just assume hard coded values as set in kernel:
++     // XPRAM 0x1300
++     // NR    0x1400
++     // OF    0x1800
++     // TODO: use ioctl to get PRAM offset
++     // fprintf(stderr, "no NW PRAM found, assuming OW XPRAM offset 0x1300 size 0x100\n");
++     *size = 0x100;
++     return (0x1300);
++     die("no PRAM found");
++}
++
++#define VOLADDR 8
++
++int main(int argc, char *argv[])
++{
++     int fd, offset, size;
++     char *buf;
++
++     fd = open("/dev/nvram", O_RDWR);
++     if (fd < 0) die("can't open /dev/nvram");
++     
++     offset = find_pram(fd, &size);
++     buf = malloc(size);
++     if (!buf) die("can't malloc()");
++
++     seek_pram(fd, offset);
++     if (read(fd, buf, size) != size)
++	  die("error reading /dev/nvram");
++
++     printf("current volume is %d\n", (unsigned char) buf[VOLADDR]);
++     
++     if (argc > 1) {
++	  buf[VOLADDR] = atoi(argv[1]);
++
++	  seek_pram(fd, offset);
++	  if (write(fd, buf, size) != size)
++	       die("error writing /dev/nvram");
++	  printf("new volume is %d\n", (unsigned char) buf[VOLADDR]);
++     }
++     ioctl(fd, IOC_NVRAM_SYNC);
++     close(fd);
++     return 0;
++}
+diff -Nuar pmac-utils.orig/nwnvsetenv.c pmac-utils/nwnvsetenv.c
+--- pmac-utils.orig/nwnvsetenv.c	1970-01-01 01:00:00.000000000 +0100
++++ pmac-utils/nwnvsetenv.c	2005-11-17 21:37:27.000000000 +0000
+@@ -0,0 +1,261 @@
++/*	nwnvsetnv.c
++
++	used to set the Envenrioment variables in power macs NVram.
++	This is for the NewWorld nvram only
++
++	nwcode: Copyright (C) 2000	by Klaus Halfmann
++
++	see README for details
++*/
++#include <stdio.h>
++#include <stdlib.h>
++
++#define __USE_GNU	// need strnlen
++
++#include <string.h>
++#include <unistd.h>
++#include <fcntl.h>
++
++// #define MXSTRING        128:
++// #define N_NVVARS	(int)(sizeof(nvvars) / sizeof(nvvars[0]))
++// #define NVMAGIC		0x1275
++
++/* CHRP NVRAM header */
++typedef struct {
++  unsigned char		signature;
++  unsigned char		cksum;
++  unsigned short	len;
++  char			name[12];
++  // unsigned char data[0];
++} chrp_header;
++
++/* Check in proc/cpuinfo if this is a new world machine */
++
++int checkNewWorld(void)
++{
++    FILE* cpuf = fopen("/proc/cpuinfo","r");
++    char  buf[256]; // "pmac-generation    : NewWolrd|OldWorld 
++    int	  result = 0, found = 0;
++
++    if (!cpuf) {
++	perror("Couldn't open /proc/cpuinfo");
++	exit(EXIT_FAILURE);
++    }
++
++    while (NULL != fgets(buf, 255, cpuf))
++    {
++	if (!strncmp(buf, "pmac-generation" ,15))
++	{
++	    char* index = strchr(buf, ':') + 2;
++	    if (!index) // ???
++		continue;
++	    result = !strncmp(index,"NewWorld",8);
++	    found = 1;
++	    break;
++	}
++    }
++    fclose(cpuf);
++
++    /* Some kernels don't have pmac-generation ( <= 2.2.15 and earlier 2.3.x ) */
++    /* Look for AAPL in /proc/device-tree/compatible instead. */
++    if (!found) {
++	cpuf = fopen("/proc/device-tree/compatible", "r");
++	if(!cpuf)
++	    return 0;
++	
++	fgets(buf, 255, cpuf);
++	fclose(cpuf);
++	if (strncmp(buf, "AAPL", 4) != 0)
++	    result = 1;
++    }
++
++    return result; // assume OldWorld
++}
++
++/* seek NVRAM until common (OF) part 
++   return the lenght of the part in case of sucess,
++   	  0 otherwise.
++   chrph is set to the value of the "coommon" blocek eventually found
++   *nvstart is set to the seekpoint where common block starts.
++*/
++   
++int nvscan(int nvfd, chrp_header* chrph, int* nvstart)
++{
++    int		start = 0;
++    
++    while (read(nvfd, chrph, sizeof(chrp_header)) == sizeof(chrp_header))
++    {
++	int size = chrph->len * 0x10 - sizeof(chrp_header);    	
++	if (!strncmp(chrph->name, "common", 7))
++	{
++	    *nvstart = start;
++	    return size; // seeked upto start
++	}
++	if (lseek(nvfd, size, SEEK_CUR) < 0)
++	   break;
++	start += size + sizeof(chrp_header);
++    }
++    fprintf(stderr,"No common Block found\n");
++    exit(EXIT_FAILURE);
++}
++
++static char* nvload( int nvfd , int nvsize)
++{
++    char* nvbuf = malloc(nvsize);
++
++    if (!nvbuf) {
++	perror("Error allocating buffer");
++	exit(EXIT_FAILURE);
++    }
++    if (read(nvfd, nvbuf, nvsize) != nvsize) {
++	perror("Error reading /dev/nvram");
++	exit(EXIT_FAILURE);
++    }
++    return nvbuf;
++}
++
++static void
++print_vars(char* nvbuf, int nvsize)
++{
++    int i = 0;
++
++    while (i < nvsize)
++    {
++ 	int size = strnlen(nvbuf, nvsize);
++	if (size == 0)
++	    break;
++	printf("%s\n",nvbuf);
++	nvbuf += (size + 1);	// count 0-byte, too
++    }
++}
++
++/* move memory around to insert the value.
++ *
++ * @param nvbufend 	byte AFTER the end of the buffer
++ * @param varsize 	length of the variable name
++ * @param buf		byte where varaible NAME starts
++ * @param newval	new value to replace old one
++ * @param foundsize 	lenght of varible + '=' + value
++ * @param equalpos 	position relative to buf where '=' was found
++ */
++static void 
++insert_val (char* nvbufend, int varsize,   char* buf, 
++	    char* newval,   int foundsize, int equalpos)
++{
++    int 	oldlen 	= foundsize - equalpos -1; // account for the '='
++    int		newlen 	= strlen(newval);
++    char* 	valpos 	= buf + varsize + 1;
++    int 	delta 	= newlen - oldlen;
++
++    if (delta > 0) // expand mem
++	memmove(valpos + newlen,
++		valpos + oldlen, (nvbufend - valpos - newlen));
++    else if (delta < 0) // shrink mem
++    {
++	memmove(valpos + newlen, 
++		valpos + oldlen, (nvbufend - valpos - oldlen));
++	memset (nvbufend + delta, 0, -delta );
++    }
++    strncpy(valpos, newval, newlen);
++}
++
++/* return position where variable is found,
++ * newval may be null.
++ */
++
++static char* set_var(char* nvbuf, int nvsize, char* varname, char* newval)
++{
++    int i =0;
++    int varsize = strlen(varname);
++    int equalpos;
++    while (i < nvsize)
++    {
++	char* buf = &nvbuf[i];
++ 	int foundsize = strnlen(buf, nvsize -i);
++	if (foundsize == 0)
++	    break;
++	equalpos = (int) (strchr(buf, '=') - buf);
++	if (equalpos == varsize &&
++	    !strncmp(buf, varname, equalpos))
++	{
++	    if (newval)	// set the value 
++		insert_val(nvbuf + nvsize, varsize, buf, 
++			   newval, foundsize, equalpos);
++	    return buf;
++	}
++	i += foundsize + 1;	// count 0-byte, too
++    }
++    return NULL;
++}
++
++static void
++print_var(char* nvbuf, int nvsize, char* varname)
++{
++    char* buf = set_var(nvbuf, nvsize, varname, NULL);
++    if (buf)
++	printf("%s\n",buf);
++}
++
++/* This fucntion is not used here, it is left
++   her for the curious */
++
++unsigned short chrp_checksum(chrp_header* hdr, char* nvbuf, int nvsize)
++{
++    unsigned char* 	ptr = (unsigned char*) &hdr->len;
++    unsigned char* 	end = ptr + sizeof(chrp_header);
++    unsigned short 	sum = hdr->signature;
++	// this in fact skips the checksum
++    for (; ptr < end; ptr++)
++	sum += *ptr;
++    while (sum > 0xFF)
++	sum = (sum & 0xFF) + (sum>>8);
++    return sum;
++}                                                                                                 
++
++static void
++nvstore(int nvfd, chrp_header* chrph, char* nvbuf, int nvstart, int nvsize)
++{
++    // mmh, the checksum is calculated for the header only
++    // since we did not modify the header we can just ignore it.
++    ssize_t written;
++    ssize_t seek =  nvstart + sizeof(chrp_header);
++    written = lseek(nvfd, seek, SEEK_SET);
++    if (written != seek)
++    {
++    	fprintf(stderr,"Error seeking /dev/nvram\n");
++	exit(EXIT_FAILURE);
++    }
++    written = write(nvfd, nvbuf, nvsize);
++    if (written != nvsize)
++    {
++    	fprintf(stderr,"Error writing /dev/nvram %x %x\n", nvsize, seek);
++	exit(EXIT_FAILURE);
++    }
++}
++
++/* print / set the New World NVRAM */
++
++void nvNew(int ac, char** av, int nvfd)
++{
++    int 		nvsize, nvstart;
++    chrp_header		chrph;
++    char*		nvbuf;
++
++    nvsize = nvscan(nvfd, &chrph, &nvstart);
++    nvbuf  = nvload(nvfd, nvsize);
++
++    switch (ac) {
++    case 1:
++	print_vars(nvbuf, nvsize);
++	break;
++
++    case 2:
++	print_var(nvbuf, nvsize, av[1]);
++	break;
++	
++    case 3:
++	set_var(nvbuf, nvsize, av[1], av[2]);
++	nvstore(nvfd, &chrph, nvbuf, nvstart, nvsize);
++	break;
++    }
++}
