225 lines
5.3 KiB
C
225 lines
5.3 KiB
C
/*
|
|
* Copyright (C) 2017 David Oberhollenzer - sigma star gmbh
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 as published by
|
|
* the Free Software Foundation.
|
|
*
|
|
* 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; see the file COPYING. If not, write to the Free Software
|
|
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA.
|
|
*
|
|
* Author: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
|
|
*/
|
|
#include "lsmtd.h"
|
|
|
|
struct ubi_node *ubi_dev;
|
|
int num_ubi_devices;
|
|
|
|
struct mtd_node *mtd_dev;
|
|
int num_mtd_devices;
|
|
|
|
static int compare_mtd(const void *l, const void *r)
|
|
{
|
|
const struct mtd_node *a = l, *b = r;
|
|
|
|
switch (sort_by->type) {
|
|
case COL_DEVNAME:
|
|
return a->info.mtd_num - b->info.mtd_num;
|
|
case COL_DEVNUM:
|
|
if (a->info.major == b->info.major)
|
|
return a->info.minor - b->info.minor;
|
|
return a->info.major - b->info.major;
|
|
case COL_TYPE:
|
|
return strcmp(a->info.type_str, b->info.type_str);
|
|
case COL_NAME:
|
|
return strcmp(a->info.name, b->info.name);
|
|
case COL_SIZE:
|
|
if (a->info.size < b->info.size)
|
|
return -1;
|
|
if (a->info.size > b->info.size)
|
|
return 1;
|
|
return 0;
|
|
case COL_EBSIZE:
|
|
return a->info.eb_size - b->info.eb_size;
|
|
case COL_EBCOUNT:
|
|
return a->info.eb_cnt - b->info.eb_cnt;
|
|
case COL_MINIO:
|
|
return a->info.min_io_size - b->info.min_io_size;
|
|
case COL_SUBSIZE:
|
|
return a->info.subpage_size - b->info.subpage_size;
|
|
case COL_OOBSIZE:
|
|
return a->info.oob_size - b->info.oob_size;
|
|
case COL_RO:
|
|
return !a->info.writable - !b->info.writable;
|
|
case COL_BB:
|
|
return a->info.bb_allowed - b->info.bb_allowed;
|
|
case COL_REGION:
|
|
return a->info.region_cnt - b->info.region_cnt;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int compare_ubi_vol(const void *l, const void *r)
|
|
{
|
|
const struct ubi_vol_info *a = l, *b = r;
|
|
long long all, bll;
|
|
|
|
switch (sort_by->type) {
|
|
case COL_DEVNAME:
|
|
if (a->dev_num == b->dev_num)
|
|
return a->vol_id - b->vol_id;
|
|
return a->dev_num - b->dev_num;
|
|
case COL_DEVNUM:
|
|
if (a->major == b->major)
|
|
return a->minor - b->minor;
|
|
return a->major - b->major;
|
|
case COL_TYPE:
|
|
if (a->type == b->type)
|
|
return 0;
|
|
return a->type == UBI_DYNAMIC_VOLUME ? 1 : -1;
|
|
case COL_NAME:
|
|
return strcmp(a->name, b->name);
|
|
case COL_SIZE:
|
|
all = a->rsvd_bytes;
|
|
bll = b->rsvd_bytes;
|
|
goto out_ll;
|
|
case COL_EBSIZE:
|
|
return a->leb_size - b->leb_size;
|
|
case COL_EBCOUNT:
|
|
return a->rsvd_lebs - b->rsvd_lebs;
|
|
case COL_FREE:
|
|
case COL_FREE_LEB:
|
|
all = (a->rsvd_bytes - a->data_bytes);
|
|
bll = (b->rsvd_bytes - b->data_bytes);
|
|
goto out_ll;
|
|
case COL_CORRUPTED:
|
|
return a->corrupted - b->corrupted;
|
|
}
|
|
return 0;
|
|
out_ll:
|
|
return (all < bll) ? -1 : ((all > bll) ? 1 : 0);
|
|
}
|
|
|
|
static int scan_ubi_device(libubi_t lib_ubi, struct ubi_node *dev)
|
|
{
|
|
int lo = dev->info.lowest_vol_id, hi = dev->info.highest_vol_id;
|
|
int i, idx = 0, dev_num = dev->info.dev_num;
|
|
struct ubi_vol_info vol_info;
|
|
|
|
if (!dev->info.vol_count)
|
|
return 0;
|
|
|
|
dev->vol_info = xcalloc(dev->info.vol_count, sizeof(dev->vol_info[0]));
|
|
|
|
for (i = lo; i <= hi; ++i) {
|
|
if (ubi_get_vol_info1(lib_ubi, dev_num, i, &vol_info)) {
|
|
if (errno == ENOENT)
|
|
continue;
|
|
perror("ubi_get_vol_info1");
|
|
return -1;
|
|
}
|
|
|
|
dev->vol_info[idx++] = vol_info;
|
|
}
|
|
|
|
if (sort_by)
|
|
qsort(dev->vol_info, idx, sizeof(vol_info), compare_ubi_vol);
|
|
return 0;
|
|
}
|
|
|
|
int scan_ubi(libubi_t lib_ubi)
|
|
{
|
|
struct ubi_dev_info dev_info;
|
|
struct ubi_info info;
|
|
int i, j;
|
|
|
|
if (ubi_get_info(lib_ubi, &info))
|
|
return -1;
|
|
|
|
if (!info.dev_count)
|
|
return 0;
|
|
|
|
ubi_dev = xcalloc(info.dev_count, sizeof(ubi_dev[0]));
|
|
|
|
for (i = info.lowest_dev_num; i <= info.highest_dev_num; ++i) {
|
|
if (!ubi_dev_present(lib_ubi, i))
|
|
continue;
|
|
|
|
if (ubi_get_dev_info1(lib_ubi, i, &dev_info)) {
|
|
perror("ubi_get_dev_info1");
|
|
return -1;
|
|
}
|
|
|
|
for (j = 0; j < num_mtd_devices; ++j) {
|
|
if (mtd_dev[j].info.mtd_num == dev_info.mtd_num)
|
|
break;
|
|
}
|
|
|
|
if (j == num_mtd_devices) {
|
|
fprintf(stderr, "Cannot find mtd device %d refered to "
|
|
"by ubi device %d\n", dev_info.mtd_num,
|
|
dev_info.dev_num);
|
|
return -1;
|
|
}
|
|
|
|
ubi_dev[num_ubi_devices].info = dev_info;
|
|
mtd_dev[j].ubi = ubi_dev + num_ubi_devices;
|
|
|
|
if (scan_ubi_device(lib_ubi, ubi_dev + num_ubi_devices))
|
|
return -1;
|
|
|
|
++num_ubi_devices;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int scan_mtd(libmtd_t lib_mtd)
|
|
{
|
|
struct mtd_dev_info dev_info;
|
|
struct mtd_info info;
|
|
int i, idx = 0;
|
|
|
|
if (mtd_get_info(lib_mtd, &info))
|
|
return -1;
|
|
|
|
if (!info.mtd_dev_cnt)
|
|
return 0;
|
|
|
|
mtd_dev = xcalloc(info.mtd_dev_cnt, sizeof(mtd_dev[0]));
|
|
|
|
for (i = info.lowest_mtd_num; i <= info.highest_mtd_num; ++i) {
|
|
if (!mtd_dev_present(lib_mtd, i))
|
|
continue;
|
|
|
|
if (mtd_get_dev_info1(lib_mtd, i, &dev_info)) {
|
|
perror("mtd_get_dev_info1");
|
|
return -1;
|
|
}
|
|
|
|
memcpy(&(mtd_dev[idx++].info), &dev_info, sizeof(dev_info));
|
|
}
|
|
|
|
num_mtd_devices = idx;
|
|
|
|
if (sort_by)
|
|
qsort(mtd_dev, num_mtd_devices, sizeof(*mtd_dev), compare_mtd);
|
|
return 0;
|
|
}
|
|
|
|
void scan_free(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < num_ubi_devices; ++i)
|
|
free(ubi_dev[i].vol_info);
|
|
|
|
free(ubi_dev);
|
|
free(mtd_dev);
|
|
}
|