summaryrefslogtreecommitdiffstats
path: root/src/disk.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/disk.c')
-rw-r--r--src/disk.c350
1 files changed, 295 insertions, 55 deletions
diff --git a/src/disk.c b/src/disk.c
index eb63211..6bdd974 100644
--- a/src/disk.c
+++ b/src/disk.c
@@ -18,13 +18,20 @@
#include <fcntl.h>
#include <libgen.h>
+#include <unistd.h>
+#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include <sys/ioctl.h>
#include <sys/statvfs.h>
+#ifdef __linux__
+#include <sys/sysmacros.h>
+#include <sys/ioctl.h>
#include <linux/fs.h>
+#include <dirent.h>
+#include <errno.h>
+#endif
#include "disk.h"
#include "global.h"
@@ -33,94 +40,186 @@
#include "usb-device.h"
#include "printf-utils.h"
-static char global_buf[1 << 22]; /* 4MB */
+static char global_buf[1UL << 22]; /* 4MB */
-int disk_init(struct usb_device_info * dev) {
+int disk_open_dev(int maj, int min, int partition, int readonly) {
- ERROR("RAW mode is not implemented yet");
- (void)dev;
- return -1;
+#ifdef __linux__
-}
+ int fd;
+ struct stat st;
+ DIR * dir;
+ struct dirent * dirent;
+ int found;
+ size_t len;
+ char blkdev[1024];
+
+ dir = opendir("/dev/");
+ if ( ! dir ) {
+ ERROR_INFO("Cannot open '/dev/' directory");
+ return -1;
+ }
-enum device disk_get_device(struct usb_device_info * dev) {
+ found = 0;
- ERROR("Not implemented yet");
- (void)dev;
- return DEVICE_UNKNOWN;
+ while ( ( dirent = readdir(dir) ) ) {
-}
+ if ( strncmp(dirent->d_name, ".", sizeof(".")) == 0 || strncmp(dirent->d_name, "..", sizeof("..")) == 0 )
+ continue;
-int disk_flash_raw(const char * blkdev, const char * file) {
+ if ( snprintf(blkdev, sizeof(blkdev), "/dev/%s", dirent->d_name) <= 0 )
+ continue;
- ERROR("Not implemented yet");
- (void)blkdev;
- (void)file;
- return -1;
+ if ( stat(blkdev, &st) != 0 )
+ continue;
-}
+ if ( ! S_ISBLK(st.st_mode) )
+ continue;
-int disk_flash_image(struct usb_device_info * dev, struct image * image) {
+ if ( makedev(maj, min) != st.st_rdev )
+ continue;
+
+ found = 1;
+ break;
+
+ }
+
+ closedir(dir);
+
+ if ( ! found ) {
+ ERROR("Cannot find block device with id %d:%d", maj, min);
+ return -1;
+ }
+
+ printf("Found block device %s with id %d:%d\n", blkdev, maj, min);
+
+ if ( partition == -1 ) {
+
+ /* Check if block device does not have partitions */
+
+ len = strlen(blkdev);
+ if ( sizeof(blkdev) <= len+2 ) {
+ ERROR("Block device name is too long");
+ return -1;
+ }
+
+ memcpy(blkdev+len, "p1", 3);
+ if ( stat(blkdev, &st) == 0 ) {
+ ERROR("Block device has partitions");
+ return -1;
+ }
+
+ memcpy(blkdev+len, "1", 2);
+ if ( stat(blkdev, &st) == 0 ) {
+ ERROR("Block device has partitions");
+ return -1;
+ }
+
+ blkdev[len] = 0;
+
+ } else if ( partition > 0 ) {
+
+ /* Select partition */
+
+ len = strlen(blkdev);
+ if ( sizeof(blkdev) <= len+2 ) {
+ ERROR("Block device name is too long");
+ return -1;
+ }
+
+ memcpy(blkdev+len, "p1", 3);
+ if ( stat(blkdev, &st) != 0 || ! S_ISBLK(st.st_mode) ) {
+ memcpy(blkdev+len, "1", 2);
+ if ( stat(blkdev, &st) != 0 || ! S_ISBLK(st.st_mode) ) {
+ blkdev[len] = 0;
+ fd = open(blkdev, O_RDONLY);
+ if ( fd < 0 ) {
+ if ( errno != ENOMEDIUM ) {
+ ERROR_INFO("Cannot open block device %s", blkdev);
+ return -1;
+ }
+ } else {
+ close(fd);
+ ERROR("Block device does not have partitions");
+ return -1;
+ }
+ }
+ }
+
+ printf("Found block device %s for partition %d\n", blkdev, partition);
+
+ }
+
+ fd = open(blkdev, (readonly ? O_RDONLY : O_RDWR) | O_EXCL);
+
+ if ( fd < 0 ) {
+ if ( errno != ENOMEDIUM )
+ ERROR_INFO("Cannot open block device %s", blkdev);
+ return -1;
+ }
+
+ return fd;
+
+#else
ERROR("Not implemented yet");
- (void)dev;
- (void)image;
+ (void)min;
+ (void)maj;
+ (void)partition;
+ (void)readonly;
return -1;
+#endif
+
}
-int disk_dump_raw(const char * blkdev, const char * file) {
+int disk_dump_dev(int fd, const char * file) {
- int fd1, fd2;
+ int fd2;
int ret;
char * path;
uint64_t blksize;
- size_t need, readed;
+ size_t need, sent;
ssize_t size;
- struct stat st;
struct statvfs buf;
- printf("Dump block device %s to file %s...\n", blkdev, file);
+ printf("Dump block device to file %s...\n", file);
- if ( stat(blkdev, &st) != 0 ) {
- ERROR_INFO("Cannot stat block device %s", blkdev);
- return -1;
- }
+#ifdef __linux__
- if ( ! S_ISBLK(st.st_mode) ) {
- ERROR("Invalid block device %s", blkdev);
+ if ( ioctl(fd, BLKGETSIZE64, &blksize) != 0 ) {
+ ERROR_INFO("Cannot get size of block device");
return -1;
}
- fd1 = open(blkdev, O_RDONLY);
+#else
- if ( fd1 < 0 ) {
- ERROR_INFO("Cannot open block device %s", blkdev);
+ blksize = lseek(fd, 0, SEEK_END);
+ if ( blksize == (off_t)-1 ) {
+ ERROR_INFO("Cannot get size of block device");
return -1;
}
- if ( ioctl(fd1, BLKGETSIZE64, &blksize) != 0 ) {
- ERROR_INFO("Cannot get size of block device %s", blkdev);
- close(fd1);
+ if ( lseek(fd, 0, SEEK_SET) == (off_t)-1 ) {
+ ERROR_INFO("Cannot seek to begin of block device");
return -1;
}
+#endif
+
if ( blksize > ULLONG_MAX ) {
- ERROR("Block device %s is too big", blkdev);
- close(fd1);
+ ERROR("Block device is too big");
return -1;
}
if ( blksize == 0 ) {
- ERROR("Block device %s has zero size", blkdev);
- close(fd1);
+ ERROR("Block device has zero size");
return -1;
}
path = strdup(file);
if ( ! path ) {
ALLOC_ERROR();
- close(fd1);
return -1;
}
@@ -130,7 +229,6 @@ int disk_dump_raw(const char * blkdev, const char * file) {
if ( ret == 0 && buf.f_bsize * buf.f_bfree < blksize ) {
ERROR("Not enough free space (have: %llu, need: %llu)", (unsigned long long int)(buf.f_bsize) * buf.f_bfree, (unsigned long long int)blksize);
- close(fd1);
return -1;
}
@@ -138,46 +236,188 @@ int disk_dump_raw(const char * blkdev, const char * file) {
if ( fd2 < 0 ) {
ERROR_INFO("Cannot create file %s", file);
- close(fd1);
return -1;
}
- readed = 0;
+ sent = 0;
printf_progressbar(0, blksize);
- while ( readed < blksize ) {
- need = blksize - readed;
+ while ( sent < blksize ) {
+ need = blksize - sent;
if ( need > sizeof(global_buf) )
need = sizeof(global_buf);
- size = read(fd1, global_buf, need);
+ size = read(fd, global_buf, need);
if ( size == 0 )
break;
if ( write(fd2, global_buf, size) != size ) {
PRINTF_ERROR("Dumping image failed");
- close(fd1);
close(fd2);
return -1;
}
- readed += size;
- printf_progressbar(readed, blksize);
+ sent += size;
+ printf_progressbar(sent, blksize);
}
- close(fd1);
close(fd2);
return 0;
}
-int disk_dump_image(struct usb_device_info * dev, enum image_type image, const char * file) {
+int disk_flash_dev(int fd, const char * file) {
+
+ ERROR("Not implemented yet");
+ (void)fd;
+ (void)file;
+ return -1;
+
+}
+
+int disk_init(struct usb_device_info * dev) {
+
+#ifdef __linux__
+
+ int fd;
+ int maj1;
+ int maj2;
+ int min1;
+ int min2;
+
+ maj1 = -1;
+ maj2 = -1;
+ min1 = -1;
+ min2 = -1;
+
+ FILE * f;
+ DIR * dir;
+ struct dirent * dirent;
+ char buf[1024];
+ unsigned int devnum;
+ unsigned int busnum;
+
+ struct usb_device * device;
+
+ device = usb_device(dev->udev);
+ if ( ! device || ! device->bus ) {
+ ERROR_INFO("Cannot read usb devnum and busnum");
+ return -1;
+ }
+
+ dir = opendir("/sys/dev/block/");
+ if ( ! dir ) {
+ ERROR_INFO("Cannot open '/sys/dev/block/' directory");
+ return -1;
+ }
+
+ while ( ( dirent = readdir(dir) ) ) {
+
+ if ( strncmp(dirent->d_name, ".", sizeof(".")) == 0 || strncmp(dirent->d_name, "..", sizeof("..")) == 0 )
+ continue;
+
+ if ( snprintf(buf, sizeof(buf), "/sys/dev/block/%s/device/../../../../busnum", dirent->d_name) <= 0 )
+ continue;
+
+ f = fopen(buf, "r");
+ if ( ! f )
+ continue;
+
+ if ( fscanf(f, "%u", &busnum) != 1 ) {
+ fclose(f);
+ continue;
+ }
+
+ fclose(f);
+
+ if ( snprintf(buf, sizeof(buf), "/sys/dev/block/%s/device/../../../../devnum", dirent->d_name) <= 0 )
+ continue;
+
+ f = fopen(buf, "r");
+ if ( ! f )
+ continue;
+
+ if ( fscanf(f, "%u", &devnum) != 1 ) {
+ fclose(f);
+ continue;
+ }
+
+ fclose(f);
+
+ if ( devnum != device->devnum || device->bus->location != busnum )
+ continue;
+
+ if ( sscanf(dirent->d_name, "%d:%d", &maj2, &min2) != 2 ) {
+ maj2 = -1;
+ min2 = -1;
+ continue;
+ }
+
+ if ( maj1 != -1 && min1 != -1 && maj2 != -1 && min2 != -1 )
+ break;
+
+ maj1 = maj2;
+ min1 = min2;
+ maj2 = -1;
+ min2 = -1;
+
+ }
+
+ closedir(dir);
+
+ if ( maj1 == -1 || min1 == -1 ) {
+ ERROR("Cannot find id for mmc block disk device");
+ return -1;
+ }
+
+ /* TODO: change 1 to 0 when disk_flash_dev will be implemented */
+
+ /* RX-51 and RM-680 export MyDocs in first usb device and just first partion, so host system see whole device without MBR table */
+ if ( dev->device == DEVICE_RX_51 || dev->device == DEVICE_RM_680 )
+ fd = disk_open_dev(maj1, min1, -1, 1);
+ /* Other devices can export SD card as first partition and export whole mmc device, so host system will see MBR table */
+ else if ( maj2 != -1 && min2 != -1 )
+ fd = disk_open_dev(maj2, min2, 1, 1);
+ else
+ fd = disk_open_dev(maj1, min1, 1, 1);
+
+ if ( fd < 0 && errno != ENOMEDIUM )
+ return -1;
+
+ dev->data = fd;
+ return 0;
+
+#else
+
+ ERROR("Not implemented yet");
+ (void)dev;
+ return -1;
+
+#endif
+
+}
+
+enum device disk_get_device(struct usb_device_info * dev) {
+
+ return dev->device;
+
+}
+
+int disk_flash_image(struct usb_device_info * dev, struct image * image) {
ERROR("Not implemented yet");
(void)dev;
(void)image;
- (void)file;
return -1;
}
+int disk_dump_image(struct usb_device_info * dev, enum image_type image, const char * file) {
+
+ if ( image != IMAGE_MMC )
+ ERROR_RETURN("Only mmc images are supported", -1);
+
+ return disk_dump_dev(dev->data, file);
+
+}
+
int disk_check_badblocks(struct usb_device_info * dev, const char * device) {
ERROR("Not implemented yet");