Skip to content
Snippets Groups Projects
fw_env.c 29.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	if (mode == O_RDWR) {
    
    			/* switch to next partition for writing */
    			dev_target = !dev_current;
    			/* dev_target: fd_target, erase_target */
    			fd_target = open (DEVNAME (dev_target), mode);
    			if (fd_target < 0) {
    
    					 "Can't open %s: %s\n",
    					 DEVNAME (dev_target),
    					 strerror (errno));
    				rc = -1;
    				goto exit;
    
    		} else {
    			dev_target = dev_current;
    			fd_target = fd_current;
    
    
    		rc = flash_write (fd_current, fd_target, dev_target);
    
    
    			if (close (fd_target)) {
    
    					"I/O error on %s: %s\n",
    
    					DEVNAME (dev_target),
    
    					strerror (errno));
    
    		rc = flash_read (fd_current);
    
    exit:
    	if (close (fd_current)) {
    
    			 "I/O error on %s: %s\n",
    			 DEVNAME (dev_current), strerror (errno));
    		return -1;
    
    	return rc;
    
    }
    
    /*
     * s1 is either a simple 'name', or a 'name=value' pair.
     * s2 is a 'name=value' pair.
     * If the names match, return the value of s2, else NULL.
     */
    
    
    static char *envmatch (char * s1, char * s2)
    
    	if (s1 == NULL || s2 == NULL)
    		return NULL;
    
    
    	while (*s1 == *s2++)
    		if (*s1++ == '=')
    
    			return s2;
    
    	if (*s1 == '\0' && *(s2 - 1) == '=')
    
    		return s2;
    	return NULL;
    
    }
    
    /*
     * Prevent confusion if running from erased flash memory
     */
    
    int fw_env_open(void)
    
    	int crc0, crc0_ok;
    
    	unsigned char flag0;
    
    	unsigned char flag1;
    
    	void *addr1;
    
    	struct env_image_single *single;
    	struct env_image_redundant *redundant;
    
    	if (parse_config ())		/* should fill envdevices */
    
    		return -1;
    
    	addr0 = calloc(1, CUR_ENVSIZE);
    
    	if (addr0 == NULL) {
    
    			"Not enough memory for environment (%ld bytes)\n",
    
    		return -1;
    
    	/* read environment from FLASH to local buffer */
    
    	environment.image = addr0;
    
    	if (HaveRedundEnv) {
    		redundant = addr0;
    		environment.crc		= &redundant->crc;
    		environment.flags	= &redundant->flags;
    		environment.data	= redundant->data;
    	} else {
    		single = addr0;
    		environment.crc		= &single->crc;
    		environment.flags	= NULL;
    		environment.data	= single->data;
    
    	dev_current = 0;
    	if (flash_io (O_RDONLY))
    		return -1;
    
    	crc0 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE);
    	crc0_ok = (crc0 == *environment.crc);
    
    		if (!crc0_ok) {
    
    			fprintf (stderr,
    				"Warning: Bad CRC, using default environment\n");
    
    			memcpy(environment.data, default_environment, sizeof default_environment);
    
    		flag0 = *environment.flags;
    
    		dev_current = 1;
    
    		addr1 = calloc(1, CUR_ENVSIZE);
    
    		if (addr1 == NULL) {
    
    				"Not enough memory for environment (%ld bytes)\n",
    
    			return -1;
    
    		redundant = addr1;
    
    		/*
    		 * have to set environment.image for flash_read(), careful -
    		 * other pointers in environment still point inside addr0
    		 */
    		environment.image = addr1;
    		if (flash_io (O_RDONLY))
    			return -1;
    
    		/* Check flag scheme compatibility */
    		if (DEVTYPE(dev_current) == MTD_NORFLASH &&
    		    DEVTYPE(!dev_current) == MTD_NORFLASH) {
    			environment.flag_scheme = FLAG_BOOLEAN;
    		} else if (DEVTYPE(dev_current) == MTD_NANDFLASH &&
    			   DEVTYPE(!dev_current) == MTD_NANDFLASH) {
    			environment.flag_scheme = FLAG_INCREMENTAL;
    
    		} else if (DEVTYPE(dev_current) == MTD_DATAFLASH &&
    			   DEVTYPE(!dev_current) == MTD_DATAFLASH) {
    			environment.flag_scheme = FLAG_BOOLEAN;
    
    		} else if (DEVTYPE(dev_current) == MTD_UBIVOLUME &&
    			   DEVTYPE(!dev_current) == MTD_UBIVOLUME) {
    			environment.flag_scheme = FLAG_INCREMENTAL;
    
    		} else if (DEVTYPE(dev_current) == MTD_ABSENT &&
    			   DEVTYPE(!dev_current) == MTD_ABSENT) {
    			environment.flag_scheme = FLAG_INCREMENTAL;
    
    		} else {
    			fprintf (stderr, "Incompatible flash types!\n");
    			return -1;
    
    		crc1 = crc32 (0, (uint8_t *) redundant->data, ENV_SIZE);
    		crc1_ok = (crc1 == redundant->crc);
    		flag1 = redundant->flags;
    
    		if (crc0_ok && !crc1_ok) {
    			dev_current = 0;
    		} else if (!crc0_ok && crc1_ok) {
    			dev_current = 1;
    		} else if (!crc0_ok && !crc1_ok) {
    
    			fprintf (stderr,
    				"Warning: Bad CRC, using default environment\n");
    
    			memcpy (environment.data, default_environment,
    				sizeof default_environment);
    			dev_current = 0;
    		} else {
    			switch (environment.flag_scheme) {
    			case FLAG_BOOLEAN:
    				if (flag0 == active_flag &&
    				    flag1 == obsolete_flag) {
    					dev_current = 0;
    				} else if (flag0 == obsolete_flag &&
    					   flag1 == active_flag) {
    					dev_current = 1;
    				} else if (flag0 == flag1) {
    					dev_current = 0;
    				} else if (flag0 == 0xFF) {
    					dev_current = 0;
    				} else if (flag1 == 0xFF) {
    					dev_current = 1;
    				} else {
    					dev_current = 0;
    				}
    				break;
    			case FLAG_INCREMENTAL:
    
    				if (flag0 == 255 && flag1 == 0)
    
    					dev_current = 1;
    				else if ((flag1 == 255 && flag0 == 0) ||
    
    					 flag0 >= flag1)
    
    					dev_current = 0;
    
    				else /* flag1 > flag0 */
    					dev_current = 1;
    
    				break;
    			default:
    				fprintf (stderr, "Unknown flag scheme %u \n",
    					 environment.flag_scheme);
    				return -1;
    			}
    		}
    
    		/*
    		 * If we are reading, we don't need the flag and the CRC any
    		 * more, if we are writing, we will re-calculate CRC and update
    		 * flags before writing out
    		 */
    		if (dev_current) {
    			environment.image	= addr1;
    			environment.crc		= &redundant->crc;
    			environment.flags	= &redundant->flags;
    			environment.data	= redundant->data;
    			free (addr0);
    		} else {
    			environment.image	= addr0;
    			/* Other pointers are already set */
    
    			free (addr1);
    
    #ifdef DEBUG
    		fprintf(stderr, "Selected env in %s\n", DEVNAME(dev_current));
    #endif
    
    	return 0;
    
    static int parse_config ()
    
    #if defined(CONFIG_FILE)
    	/* Fills in DEVNAME(), ENVSIZE(), DEVESIZE(). Or don't. */
    
    	if (get_config (CONFIG_FILE)) {
    
    			"Cannot parse config file: %s\n", strerror (errno));
    
    		return -1;
    
    	strcpy (DEVNAME (0), DEVICE1_NAME);
    	DEVOFFSET (0) = DEVICE1_OFFSET;
    	ENVSIZE (0) = ENV1_SIZE;
    
    	/* Default values are: erase-size=env-size, #sectors=1 */
    	DEVESIZE (0) = ENVSIZE (0);
    	ENVSECTORS (0) = 1;
    #ifdef DEVICE1_ESIZE
    
    	DEVESIZE (0) = DEVICE1_ESIZE;
    
    #endif
    #ifdef DEVICE1_ENVSECTORS
    
    	ENVSECTORS (0) = DEVICE1_ENVSECTORS;
    
    	strcpy (DEVNAME (1), DEVICE2_NAME);
    	DEVOFFSET (1) = DEVICE2_OFFSET;
    	ENVSIZE (1) = ENV2_SIZE;
    
    	/* Default values are: erase-size=env-size, #sectors=1 */
    	DEVESIZE (1) = ENVSIZE (1);
    	ENVSECTORS (1) = 1;
    #ifdef DEVICE2_ESIZE
    
    	DEVESIZE (1) = DEVICE2_ESIZE;
    
    #endif
    #ifdef DEVICE2_ENVSECTORS
    
    	ENVSECTORS (1) = DEVICE2_ENVSECTORS;
    
    	if (stat (DEVNAME (0), &st)) {
    		fprintf (stderr,
    			"Cannot access MTD device %s: %s\n",
    			DEVNAME (0), strerror (errno));
    
    		return -1;
    
    
    	if (HaveRedundEnv && stat (DEVNAME (1), &st)) {
    		fprintf (stderr,
    			"Cannot access MTD device %s: %s\n",
    
    			DEVNAME (1), strerror (errno));
    
    		return -1;
    
    
    #if defined(CONFIG_FILE)
    static int get_config (char *fname)
    {
    	FILE *fp;
    	int i = 0;
    	int rc;
    	char dump[128];
    
    
    	fp = fopen (fname, "r");
    	if (fp == NULL)
    		return -1;
    
    	while (i < 2 && fgets (dump, sizeof (dump), fp)) {
    
    		/* Skip incomplete conversions and comment strings */
    
    		if (dump[0] == '#')
    
    
    		rc = sscanf (dump, "%s %lx %lx %lx %lx",
    			     DEVNAME (i),
    			     &DEVOFFSET (i),
    			     &ENVSIZE (i),
    			     &DEVESIZE (i),
    			     &ENVSECTORS (i));
    
    
    		if (rc < 4)
    			/* Assume the erase size is the same as the env-size */
    			DEVESIZE(i) = ENVSIZE(i);
    
    
    		if (rc < 5)
    			/* Default - 1 sector */
    			ENVSECTORS (i) = 1;
    
    	if (!i) {			/* No valid entries found */
    
    		return -1;