Submitted By: Ken Moffat <ken@linuxfromscratch.org>
Date: 2005-11-17
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.

 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 Makefile CFLAGS change 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	= -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;
+    }
+}
