//// revision history:// this program is based on pe.c and modified to parse the command line.// if no arguments are present, the parameters are simply dumped.//// NOTE: the caller must put complex values in "" or '' when changing // environment values.//#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdlib.h>#include <stdio.h>//// our environment structure, local to our program only//struct envvar { char name[32]; char value[256];};// #define DATAFLASH_SIZE 0x21000// #define DATAFLASH_ALIGNMENT 0x00200#define START_OF_UBOOT_ENV 0x20000#define SIZE_OF_UBOOT_ENV 0x01000//// a buffer to hold the entire dataflash// ok, well, if you remove the __attribute__ for the forced alignment,// bad things happen to the CRC when it's written back:// it could be skipped, or it could be missing one byte.//unsigned char uboot_env[SIZE_OF_UBOOT_ENV] __attribute__((aligned (4)));//// function to read nbuf bytes into buf in one pass for the caller.//int blockread (int fd, unsigned char *buf, int nbuf){ int nleft = nbuf; int nread; int offs = 0; while (nleft > 0 && ((nread = read (fd, buf + offs, nleft)) > 0)) { nleft -= nread; offs += nread; } return nbuf - nleft;}//// from the crc32.c in this directory//extern unsigned long crc32 (unsigned long crc, const unsigned char *buf, unsigned int len);//// function to dump the current environment.//void dumpVars (struct envvar env[], int nenv){ int i; for (i = 0; i < nenv; i++) { printf ("%s = %s\n", env[i].name, env[i].value); }}//// parse: open the named file 'name' and fill in up to 'nenv' records// from the u-boot environment file.//// note: the environment file is expected to be NO MORE THAN 4K (0x1000) bytes!//int parse (const char *name, struct envvar env[], int nenv){ int fd; int rc = 0; off_t offs; if ((fd = open (name, O_RDONLY)) > -1) { int nr; if ((offs = lseek (fd, START_OF_UBOOT_ENV, SEEK_SET)) == START_OF_UBOOT_ENV) { // // we're going to assume the read will complete in one pass. // if ((nr = blockread (fd, uboot_env, sizeof uboot_env)) == sizeof uboot_env) { int r, p, i; unsigned long crc; printf ("Current CRC = 0x%08x\n", * (unsigned long *) uboot_env); p = 4; // skip the CRC r = 0; crc = crc32 (0, uboot_env + sizeof crc, sizeof uboot_env - sizeof crc); printf ("Calculated CRC = 0x%08x\n", crc); // go until we hit the end of the buffer or the max # of env vars while ((uboot_env[p] != '\0') && (r < nenv)) { i = 0; // parse the name do { if (i < sizeof env[r].name / sizeof env[r].name[0]) env[r].name[i++] = uboot_env[p]; else { fprintf (stderr, "Invalid environment partition. " "Try a different raw device (0, i = %d).\n", i); exit (-1); } } while (uboot_env[p++] != '='); // terminate the name env[r].name[i-1] = '\0'; // printf ("parsed environment name: %s\n", env[r].name); i = 0; // parse the value do { if (i < sizeof env[r].value / sizeof env[r].value[0]) env[r].value[i++] = uboot_env[p]; else { fprintf (stderr, "Invalid environment partition. " "Try a different raw device (1, i = %d).\n", i); exit (-1); } } while (uboot_env[p++] != '\0'); // terminate the value env[r].value[i] = '\0'; // printf ("parsed environment value: %s\n", env[r].value); // move to the next var r++; } rc = r; } else { rc = -1; } } else { rc = -1; } close (fd); } else rc = -1; return rc;}//// write the modified environment back to the file.//int write_env (const char *name, struct envvar env[], int nenv){ int fd; off_t offs; int rc = 0; unsigned long crc; if ((fd = open (name, O_WRONLY)) > -1) { int nw; // // position the file to the spot we will write to. // note this is the aligned block offset. it will contain the area // we modified, plus some that we didn't. // if ((offs = lseek (fd, START_OF_UBOOT_ENV, SEEK_SET)) == START_OF_UBOOT_ENV) { int i; int bufoff = sizeof crc; // // clear the buffer where we're going to start writing. // remember that this is past 'block_offs' into the dataflash memory // space. // memset (uboot_env, 0, sizeof uboot_env); // // write out all the variables. // the format is // name=value\0 // ... // \0 // for (i = 0; i < nenv; i++) { nw = sprintf (uboot_env + bufoff, "%s=%s", env[i].name, env[i].value); // // the '+1' is because of the memset above: // since the buffer already has all zeros in it, it's not // necessary to put another one. // // recall that sprintf does NOT include the NUL byte in it's // return value. // bufoff += nw + 1; } // // compute the CRC and then store it. // crc = crc32 (0, uboot_env + sizeof crc, sizeof uboot_env - sizeof crc); memcpy (uboot_env, &crc, sizeof crc); printf ("New CRC = 0x%08x\n", crc); // // we're all done. // write the partial buffer back to the file. // we don't want to write the whole thing because we don't // want to have to write over part of u-boot. so do the // minimal write we can and still write back the whole thing. // rc = write (fd, uboot_env, sizeof uboot_env); // // temp // close (fd); fd = open ("u-boot_env.dat", O_CREAT | O_WRONLY, 0666); rc = write (fd, uboot_env, sizeof uboot_env); close (fd); } else { rc = -1; } } else { rc = -1; } return rc;}//// findVar looks for 'name' as the .name field in the env[] array.// nvars is the number of elements in env[].//int findVar (const char *name, struct envvar env[], int nenv){ int rc = -1; int i; // // loop over env[] and find where name == env[i].name. // terminate if we find a match, at which time we terminate the loop. // for (i = 0; i < nenv && rc == -1; i++) if (strcmp (name, env[i].name) == 0) rc = i; return rc;}int main (int argc, char *argv[]){ if (argc >= 2) { struct envvar env[128]; int i, nenv; nenv = parse (argv[1], env, sizeof env / sizeof env[0]); if (nenv > 0) { // // successfully parse the list. // rc is the number of elements in the list. // // see if the user wants to modify anything (in which case argc > 2) or // just wants a dump (argc == 2) // if (argc > 2) { if (argc % 2 == 0) { // // for argv[i] (i even && i >= 2): // argv[i] is the name of a parameter // argv[i+1] is the value to be set. // int i, idx; for (i = 2; i < argc; i += 2) { idx = findVar (argv[i], env, nenv); if (idx >= 0) { strcpy (env[idx].value, argv[i+1]); } else { // // we add a new variable. // strcpy (env[nenv].name, argv[i]); strcpy (env[nenv].value, argv[i+1]); // // add one to the variable count. // nenv++; } } i = write_env (argv[1], env, nenv); } else { printf ("Error: argc not an even number: argc == %d\n", argc); } } else { dumpVars (env, nenv); } } else { printf ("Error: empty environment list\n"); } } return EXIT_SUCCESS;}