📄 libubi.c
字号:
/* * Copyright (c) International Business Machines Corp., 2006 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Author: Artem Bityutskiy * * UBI (Unsorted Block Images) library. */#include <stdlib.h>#include <stdio.h>#include <string.h>#include <fcntl.h>#include <sys/stat.h>#include <sys/types.h>#include <dirent.h>#include <unistd.h>#include <sys/ioctl.h>#include <limits.h>#include "libubi.h"#include "libubi_int.h"#include "common.h"#define PROGRAM_NAME "libubi"/** * mkpath - compose full path from 2 given components. * @path: the first component * @name: the second component * * This function returns the resulting path in case of success and %NULL in * case of failure. */static char *mkpath(const char *path, const char *name){ char *n; int len1 = strlen(path); int len2 = strlen(name); n = malloc(len1 + len2 + 2); if (!n) { sys_errmsg("cannot allocate %d bytes", len1 + len2 + 2); return NULL; } memcpy(n, path, len1); if (n[len1 - 1] != '/') n[len1++] = '/'; memcpy(n + len1, name, len2 + 1); return n;}/** * read_positive_ll - read a positive 'long long' value from a file. * @file: the file to read from * @value: the result is stored here * * This function reads file @file and interprets its contents as a positive * 'long long' integer. If this is not true, it fails with %EINVAL error code. * Returns %0 in case of success and %-1 in case of failure. */static int read_positive_ll(const char *file, long long *value){ int fd, rd; char buf[50]; fd = open(file, O_RDONLY); if (fd == -1) return -1; rd = read(fd, buf, 50); if (rd == -1) { sys_errmsg("cannot read \"%s\"", file); goto out_error; } if (rd == 50) { errmsg("contents of \"%s\" is too long", file); errno = EINVAL; goto out_error; } if (sscanf(buf, "%lld\n", value) != 1) { /* This must be a UBI bug */ errmsg("cannot read integer from \"%s\"\n", file); errno = EINVAL; goto out_error; } if (*value < 0) { errmsg("negative value %lld in \"%s\"", *value, file); errno = EINVAL; goto out_error; } if (close(fd)) return sys_errmsg("close failed on \"%s\"", file); return 0;out_error: close(fd); return -1;}/** * read_positive_int - read a positive 'int' value from a file. * @file: the file to read from * @value: the result is stored here * * This function is the same as 'read_positive_ll()', but it reads an 'int' * value, not 'long long'. */static int read_positive_int(const char *file, int *value){ long long res; if (read_positive_ll(file, &res)) return -1; /* Make sure the value is not too big */ if (res > INT_MAX) { errmsg("value %lld read from file \"%s\" is out of range", res, file); errno = EINVAL; return -1; } *value = res; return 0;}/** * read_data - read data from a file. * @file: the file to read from * @buf: the buffer to read to * @buf_len: buffer length * * This function returns number of read bytes in case of success and %-1 in * case of failure. Note, if the file contains more then @buf_len bytes of * date, this function fails with %EINVAL error code. */static int read_data(const char *file, void *buf, int buf_len){ int fd, rd, tmp, tmp1; fd = open(file, O_RDONLY); if (fd == -1) return -1; rd = read(fd, buf, buf_len); if (rd == -1) { sys_errmsg("cannot read \"%s\"", file); goto out_error; } /* Make sure all data is read */ tmp1 = read(fd, &tmp, 1); if (tmp1 == 1) { sys_errmsg("cannot read \"%s\"", file); goto out_error; } if (tmp1) { errmsg("file \"%s\" contains too much data (> %d bytes)", file, buf_len); errno = EINVAL; goto out_error; } if (close(fd)) { sys_errmsg("close failed on \"%s\"", file); return -1; } return rd;out_error: close(fd); return -1;}/** * read_major - read major and minor numbers from a file. * @file: name of the file to read from * @major: major number is returned here * @minor: minor number is returned here * * This function returns % in case of succes, and %-1 in case of failure. */static int read_major(const char *file, int *major, int *minor){ int ret; char buf[50]; ret = read_data(file, buf, 50); if (ret < 0) return ret; ret = sscanf(buf, "%d:%d\n", major, minor); if (ret != 2) { errno = EINVAL; return errmsg("\"%s\" does not have major:minor format", file); } if (*major < 0 || *minor < 0) { errno = EINVAL; return errmsg("bad major:minor %d:%d in \"%s\"", *major, *minor, file); } return 0;}/** * dev_read_int - read a positive 'int' value from an UBI device sysfs file. * @patt: file pattern to read from * @dev_num: UBI device number * @value: the result is stored here * * This function returns %0 in case of success and %-1 in case of failure. */static int dev_read_int(const char *patt, int dev_num, int *value){ char file[strlen(patt) + 50]; sprintf(file, patt, dev_num); return read_positive_int(file, value);}/** * vol_read_int - read a positive 'int' value from an UBI volume sysfs file. * @patt: file pattern to read from * @dev_num: UBI device number * @vol_id: volume ID * @value: the result is stored here * * This function returns %0 in case of success and %-1 in case of failure. */static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value){ char file[strlen(patt) + 100]; sprintf(file, patt, dev_num, vol_id); return read_positive_int(file, value);}/** * dev_read_ll - read a positive 'long long' value from an UBI device sysfs file. * @patt: file pattern to read from * @dev_num: UBI device number * @value: the result is stored here * * This function returns %0 in case of success and %-1 in case of failure. */static int dev_read_ll(const char *patt, int dev_num, long long *value){ char file[strlen(patt) + 50]; sprintf(file, patt, dev_num); return read_positive_ll(file, value);}/** * vol_read_ll - read a positive 'long long' value from an UBI volume sysfs file. * @patt: file pattern to read from * @dev_num: UBI device number * @vol_id: volume ID * @value: the result is stored here * * This function returns %0 in case of success and %-1 in case of failure. */static int vol_read_ll(const char *patt, int dev_num, int vol_id, long long *value){ char file[strlen(patt) + 100]; sprintf(file, patt, dev_num, vol_id); return read_positive_ll(file, value);}/** * vol_read_data - read data from an UBI volume's sysfs file. * @patt: file pattern to read from * @dev_num: UBI device number * @vol_id: volume ID * @buf: buffer to read to * @buf_len: buffer length * * This function returns number of read bytes in case of success and %-1 in * case of failure. */static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf, int buf_len){ char file[strlen(patt) + 100]; sprintf(file, patt, dev_num, vol_id); return read_data(file, buf, buf_len);}/** * dev_get_major - get major and minor numbers of an UBI device. * @lib: libubi descriptor * @dev_num: UBI device number * @major: major number is returned here * @minor: minor number is returned here * * This function returns zero in case of succes and %-1 in case of failure. */static int dev_get_major(struct libubi *lib, int dev_num, int *major, int *minor){ char file[strlen(lib->dev_dev) + 50]; sprintf(file, lib->dev_dev, dev_num); return read_major(file, major, minor);}/** * vol_get_major - get major and minor numbers of an UBI volume. * @lib: libubi descriptor * @dev_num: UBI device number * @vol_id: volume ID * @major: major number is returned here * @minor: minor number is returned here * * This function returns zero in case of succes and %-1 in case of failure. */static int vol_get_major(struct libubi *lib, int dev_num, int vol_id, int *major, int *minor){ char file[strlen(lib->vol_dev) + 100]; sprintf(file, lib->vol_dev, dev_num, vol_id); return read_major(file, major, minor);}/** * vol_node2nums - find UBI device number and volume ID by volume device node * file. * @lib: UBI library descriptor * @node: UBI character device node name * @dev_num: UBI device number is returned here * @vol_id: volume ID is returned hers * * This function returns zero in case of succes and %-1 in case of failure. */static int vol_node2nums(struct libubi *lib, const char *node, int *dev_num, int *vol_id){ struct stat st; struct ubi_info info; int i, fd, major, minor; char file[strlen(lib->ubi_vol) + 100]; if (stat(node, &st)) return -1; if (!S_ISCHR(st.st_mode)) { errno = EINVAL; return errmsg("\"%s\" is not a character device", node); } major = major(st.st_rdev); minor = minor(st.st_rdev); if (minor == 0) { errno = EINVAL; return errmsg("\"%s\" is not a volume character device", node); } if (ubi_get_info((libubi_t *)lib, &info)) return -1; for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) { int major1, minor1, ret; ret = dev_get_major(lib, i, &major1, &minor1); if (ret) { if (errno == ENOENT) continue; return -1; } if (major1 == major) break; } if (i > info.highest_dev_num) { errno = ENODEV; return -1; } /* Make sure this UBI volume exists */ sprintf(file, lib->ubi_vol, i, minor - 1); fd = open(file, O_RDONLY); if (fd == -1) { errno = ENODEV; return -1; } *dev_num = i; *vol_id = minor - 1; errno = 0; return 0;}/** * dev_node2num - find UBI device number by its character device node. * @lib: UBI library descriptor * @node: UBI character device node name * * This function returns positive UBI device number in case of success and %-1 * in case of failure. */static int dev_node2num(struct libubi *lib, const char *node, int *dev_num){ struct stat st; struct ubi_info info; int i, major, minor; if (stat(node, &st)) return -1; if (!S_ISCHR(st.st_mode)) { errno = EINVAL; return errmsg("\"%s\" is not a character device", node); } major = major(st.st_rdev); minor = minor(st.st_rdev); if (minor != 0) { errno = EINVAL; return errmsg("\"%s\" is not an UBI character device", node); } if (ubi_get_info((libubi_t *)lib, &info)) return -1; for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) { int major1, minor1, ret; ret = dev_get_major(lib, i, &major1, &minor1); if (ret) { if (errno == ENOENT) continue; return -1; } if (major1 == major) { if (minor1 != 0) { errmsg("UBI character device minor number is " "%d, but must be 0", minor1); errno = EINVAL; return -1; } errno = 0; *dev_num = i; return 0; } } errno = ENODEV; return -1;}int mtd_num2ubi_dev(libubi_t desc, int mtd_num, int *dev_num){ struct ubi_info info; int i, ret, mtd_num1; struct libubi *lib = desc; if (ubi_get_info(desc, &info)) return -1; for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) { ret = dev_read_int(lib->dev_mtd_num, i, &mtd_num1); if (ret) { if (errno == ENOENT) continue; return -1; } if (mtd_num1 == mtd_num) { errno = 0; *dev_num = i; return 0; } } errno = 0; return -1;}libubi_t libubi_open(int required){ int fd, version; struct libubi *lib; lib = calloc(1, sizeof(struct libubi)); if (!lib) return NULL; /* TODO: this must be discovered instead */ lib->sysfs = strdup("/sys"); if (!lib->sysfs) goto out_error; lib->sysfs_ctrl = mkpath(lib->sysfs, SYSFS_CTRL); if (!lib->sysfs_ctrl) goto out_error; lib->ctrl_dev = mkpath(lib->sysfs_ctrl, CTRL_DEV); if (!lib->ctrl_dev) goto out_error; lib->sysfs_ubi = mkpath(lib->sysfs, SYSFS_UBI); if (!lib->sysfs_ubi) goto out_error; /* Make sure UBI is present */ fd = open(lib->sysfs_ubi, O_RDONLY); if (fd == -1) { if (required) errmsg("cannot open \"%s\", UBI does not seem to " "exist in system", lib->sysfs_ubi); goto out_error; } if (close(fd)) { sys_errmsg("close failed on \"%s\"", lib->sysfs_ubi); goto out_error; } lib->ubi_dev = mkpath(lib->sysfs_ubi, UBI_DEV_NAME_PATT); if (!lib->ubi_dev) goto out_error; lib->ubi_version = mkpath(lib->sysfs_ubi, UBI_VER); if (!lib->ubi_version) goto out_error; lib->dev_dev = mkpath(lib->ubi_dev, DEV_DEV); if (!lib->dev_dev) goto out_error; lib->dev_avail_ebs = mkpath(lib->ubi_dev, DEV_AVAIL_EBS); if (!lib->dev_avail_ebs) goto out_error; lib->dev_total_ebs = mkpath(lib->ubi_dev, DEV_TOTAL_EBS); if (!lib->dev_total_ebs) goto out_error; lib->dev_bad_count = mkpath(lib->ubi_dev, DEV_BAD_COUNT); if (!lib->dev_bad_count) goto out_error; lib->dev_eb_size = mkpath(lib->ubi_dev, DEV_EB_SIZE); if (!lib->dev_eb_size) goto out_error;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -