Subject: Re: [PATCH] powerpc: fix large nvram access

From: Olaf Hering <[email-masked]>
Date: Wed, 11 Jan 2006 13:20:20 +0100

On Wed, Jan 11, Olaf Hering wrote:

> > I think this has uncovered a bug that has been in nvsetenv for a long time.

I made this change.

Index: pmac-utils-2.1/nvsetenv.c
===================================================================
--- pmac-utils-2.1.orig/nvsetenv.c
+++ pmac-utils-2.1/nvsetenv.c
@@ -110,12 +110,21 @@ int nvcsum( void )
 static void nvload( int nvfd )
 {
     int s;
+    ssize_t r, toread = 0;
+    char *buf = (char *)&nvbuf;
 
-    if (lseek(nvfd, NVSTART, 0) < 0
-	|| read(nvfd, &nvbuf, NVSIZE) != NVSIZE) {
-	perror("Error reading /dev/nvram");
+    if ((off_t)-1 == lseek(nvfd, NVSTART, 0)) {
+	perror("Error seeking /dev/nvram");
 	exit(EXIT_FAILURE);
     }
+    do {
+	r = read(nvfd, buf + toread, NVSIZE - toread);
+	if (r < 0) {
+		perror("Error reading /dev/nvram");
+		exit(EXIT_FAILURE);
+	}
+	toread += r;
+    } while (toread < NVSIZE && r);
     if (nvbuf.nv.magic != NVMAGIC)
 	(void) fprintf(stderr, "Warning: Bad magic number %x\n",
 			 nvbuf.nv.magic);
@@ -127,11 +136,21 @@ static void nvload( int nvfd )
 
 static void nvstore(int nvfd)
 {
-    if (lseek(nvfd, NVSTART, 0) < 0
-	|| write(nvfd, &nvbuf, NVSIZE) != NVSIZE) {
-	perror("Error writing /dev/nvram");
+    char *p = (char *)&nvbuf;
+    size_t count = 0;
+    off_t w;
+    if (lseek(nvfd, NVSTART, 0) < 0) {
+	perror("Error seeking /dev/nvram");
 	exit(EXIT_FAILURE);
     }
+    do {
+	w = write(nvfd, p + count, NVSIZE - count);
+	if (w < 0) {
+		perror("Error writing /dev/nvram");
+		exit(EXIT_FAILURE);
+	}
+	count += w;
+   } while (count < NVSIZE);
 }
 
 void nvunpack( void )
Index: pmac-utils-2.1/nwnvsetenv.c
===================================================================
--- pmac-utils-2.1.orig/nwnvsetenv.c
+++ pmac-utils-2.1/nwnvsetenv.c
@@ -88,15 +88,20 @@ int nvscan(int nvfd, chrp_header* chrph,
 static char* nvload( int nvfd , int nvsize)
 {
     char* nvbuf = malloc(nvsize);
+    ssize_t r, toread = 0;
 
     if (!nvbuf) {
 	perror("Error allocating buffer");
 	exit(EXIT_FAILURE);
     }
-    if (read(nvfd, nvbuf, nvsize) != nvsize) {
-	perror("Error reading /dev/nvram");
-	exit(EXIT_FAILURE);
-    }
+    do {
+	r = read(nvfd, nvbuf + toread, nvsize - toread);
+	if (r < 0) {
+		perror("Error reading /dev/nvram");
+		exit(EXIT_FAILURE);
+	}
+	toread += r;
+    } while (toread < nvsize && r);
     return nvbuf;
 }
 
@@ -182,6 +187,7 @@ print_var(char* nvbuf, int nvsize, char*
 	printf("%s\n",buf);
 }
 
+#if 0
 /* This fucntion is not used here, it is left
    her for the curious */
 
@@ -197,26 +203,28 @@ unsigned short chrp_checksum(chrp_header
 	sum = (sum & 0xFF) + (sum>>8);
     return sum;
 }                                                                                                 
+#endif
 
 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)
-    {
+    size_t count = 0;
+    off_t w, seek =  nvstart + sizeof(chrp_header);
+    w = lseek(nvfd, seek, SEEK_SET);
+    if (w != 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);
-    }
+    do {
+	w = write(nvfd, nvbuf + count, nvsize - count);
+	if (w < 0) {
+		perror("Error writing /dev/nvram");
+		exit(EXIT_FAILURE);
+	}
+	count += w;
+   } while (count < (size_t)nvsize);
 }
 
 /* print / set the New World NVRAM */

-- 
short story of a lazy sysadmin:
 alias appserv=wotan