diff options
Diffstat (limited to 'ubi-utils/src/libmtd.c')
| -rw-r--r-- | ubi-utils/src/libmtd.c | 103 | 
1 files changed, 86 insertions, 17 deletions
| diff --git a/ubi-utils/src/libmtd.c b/ubi-utils/src/libmtd.c index b050bea..4f1ef41 100644 --- a/ubi-utils/src/libmtd.c +++ b/ubi-utils/src/libmtd.c @@ -472,9 +472,88 @@ static int dev_node2num(struct libmtd *lib, const char *node, int *dev_num)  	return -1;  } +/** + * sysfs_is_supported - check whether the MTD sub-system supports MTD. + * @lib: MTD library descriptor + * + * The Linux kernel MTD subsystem gained MTD support starting from kernel + * 2.6.30 and libmtd tries to use sysfs interface if possible, because the NAND + * sub-page size is available there (and not available at all in pre-sysfs + * kernels). + * + * Very old kernels did not have "/sys/class/mtd" directory. Not very old + * kernels (e.g., 2.6.29) did have "/sys/class/mtd/mtdX" directories, by there + * were no files there, e.g., the "name" file was not present. So all we can do + * is to check for a "/sys/class/mtd/mtdX/name" file. But this is not a + * reliable check, because if this is a new system with no MTD devices - we'll + * treat it as a pre-sysfs system. + */ +static int sysfs_is_supported(struct libmtd *lib) +{ +	int fd, num = -1; +	DIR *sysfs_mtd; +	char file[strlen(lib->mtd_name) + 10]; + +	sysfs_mtd = opendir(lib->sysfs_mtd); +	if (!sysfs_mtd) { +		if (errno == ENOENT) { +			errno = 0; +			return 0; +		} +		return sys_errmsg("cannot open \"%s\"", lib->sysfs_mtd); +	} + +	/* +	 * First of all find an "mtdX" directory. This is needed because there +	 * may be, for example, mtd1 but no mtd0. +	 */ +	while (1) { +		int ret, dev_num; +		char tmp_buf[256]; +		struct dirent *dirent; + +		dirent = readdir(sysfs_mtd); +		if (!dirent) +			break; + +		if (strlen(dirent->d_name) >= 255) { +			errmsg("invalid entry in %s: \"%s\"", +			       lib->sysfs_mtd, dirent->d_name); +			errno = EINVAL; +			closedir(sysfs_mtd); +			return -1; +		} + +		ret = sscanf(dirent->d_name, MTD_NAME_PATT"%s", +			     &dev_num, tmp_buf); +		if (ret == 1) { +			num = dev_num; +			break; +		} +	} + +	if (closedir(sysfs_mtd)) +		return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_mtd); + +	if (num == -1) +		/* No mtd device, treat this as pre-sysfs system */ +		return 0; + +	sprintf(file, lib->mtd_name, num); +	fd = open(file, O_RDONLY); +	if (fd == -1) +		return 0; + +	if (close(fd)) { +		sys_errmsg("close failed on \"%s\"", file); +		return -1; +	} + +	return 1; +} +  libmtd_t libmtd_open(void)  { -	int fd;  	struct libmtd *lib;  	lib = calloc(1, sizeof(struct libmtd)); @@ -489,28 +568,18 @@ libmtd_t libmtd_open(void)  	if (!lib->mtd)  		goto out_error; -	/* Make sure MTD is recent enough and supports sysfs */ -	fd = open(lib->sysfs_mtd, O_RDONLY); -	if (fd == -1) { +	lib->mtd_name = mkpath(lib->mtd, MTD_NAME); +	if (!lib->mtd_name) +		goto out_error; + +	if (!sysfs_is_supported(lib)) {  		free(lib->mtd);  		free(lib->sysfs_mtd); -		if (errno != ENOENT || legacy_libmtd_open()) { -			free(lib); -			return NULL; -		} +		free(lib->mtd_name);  		lib->mtd_name = lib->mtd = lib->sysfs_mtd = NULL;  		return lib;  	} -	if (close(fd)) { -		sys_errmsg("close failed on \"%s\"", lib->sysfs_mtd); -		goto out_error; -	} - -	lib->mtd_name = mkpath(lib->mtd, MTD_NAME); -	if (!lib->mtd_name) -		goto out_error; -  	lib->mtd_dev = mkpath(lib->mtd, MTD_DEV);  	if (!lib->mtd_dev)  		goto out_error; | 
