LD_PRELOAD: add dup2 support so we can use it with dd
This commit is contained in:
2
README
2
README
@@ -94,6 +94,8 @@ Change: 1970-01-01 10:00:00.000000000 +1000
|
|||||||
The cat command, which allows you to read/dump a iSCSI LUN to a file :
|
The cat command, which allows you to read/dump a iSCSI LUN to a file :
|
||||||
$ LD_PRELOAD=./bin/ld_iscsi.so cat iscsi://127.0.0.1:3262/iqn.ronnie.test/2 >copy_of_iscsi_lun
|
$ LD_PRELOAD=./bin/ld_iscsi.so cat iscsi://127.0.0.1:3262/iqn.ronnie.test/2 >copy_of_iscsi_lun
|
||||||
|
|
||||||
|
Or using dd even :
|
||||||
|
LD_PRELOAD=./bin/ld_iscsi.so strace -o x -f dd if=iscsi://127.0.0.1:3262/iqn.ronnie.test/2 of=copy_of_LUN bs=10M count=1 bs=1M count=10
|
||||||
|
|
||||||
The LD_PRELOAD hack is incomplete and needs more functions to be intercepted before becomming fully functional. Patches welcome!
|
The LD_PRELOAD hack is incomplete and needs more functions to be intercepted before becomming fully functional. Patches welcome!
|
||||||
|
|
||||||
|
|||||||
214
src/ld_iscsi.c
214
src/ld_iscsi.c
@@ -9,17 +9,20 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "iscsi.h"
|
#include "iscsi.h"
|
||||||
|
#include "iscsi-private.h"
|
||||||
#include "scsi-lowlevel.h"
|
#include "scsi-lowlevel.h"
|
||||||
|
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
#define ISCSI_FD_MASK 0x7fffff00
|
|
||||||
#define ISCSI_FD_NUM 0x000000ff
|
|
||||||
|
|
||||||
static char *initiator = "iqn.2011-02.ronnie:ld_iscsi";
|
static char *initiator = "iqn.2011-02.ronnie:ld_iscsi";
|
||||||
|
|
||||||
|
#define ISCSI_MAX_FD 255
|
||||||
|
|
||||||
struct iscsi_fd_list {
|
struct iscsi_fd_list {
|
||||||
|
int is_iscsi;
|
||||||
|
int dup2fd;
|
||||||
|
int in_flight;
|
||||||
struct iscsi_context *iscsi;
|
struct iscsi_context *iscsi;
|
||||||
int lun;
|
int lun;
|
||||||
uint32_t block_size;
|
uint32_t block_size;
|
||||||
@@ -27,77 +30,62 @@ struct iscsi_fd_list {
|
|||||||
off_t offset;
|
off_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct iscsi_fd_list iscsi_fd_list[ISCSI_FD_NUM];
|
static struct iscsi_fd_list iscsi_fd_list[ISCSI_MAX_FD];
|
||||||
|
|
||||||
int (*real_open)(__const char *path, int flags, mode_t mode);
|
int (*real_open)(__const char *path, int flags, mode_t mode);
|
||||||
|
|
||||||
int open(const char *path, int flags, mode_t mode)
|
int open(const char *path, int flags, mode_t mode)
|
||||||
{
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
if (!strncmp(path, "iscsi:", 6)) {
|
if (!strncmp(path, "iscsi:", 6)) {
|
||||||
|
struct iscsi_context *iscsi;
|
||||||
struct iscsi_url *iscsi_url;
|
struct iscsi_url *iscsi_url;
|
||||||
struct scsi_task *task;
|
struct scsi_task *task;
|
||||||
struct scsi_readcapacity10 *rc10;
|
struct scsi_readcapacity10 *rc10;
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < ISCSI_FD_NUM; i++) {
|
iscsi = iscsi_create_context(initiator);
|
||||||
if (iscsi_fd_list[i].iscsi == NULL) {
|
if (iscsi == NULL) {
|
||||||
iscsi_fd_list[i].iscsi = iscsi_create_context(initiator);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == ISCSI_FD_NUM) {
|
|
||||||
fprintf(stderr, "ld-iscsi: Failed to create context\n");
|
fprintf(stderr, "ld-iscsi: Failed to create context\n");
|
||||||
errno = ENFILE;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iscsi_fd_list[i].iscsi == NULL) {
|
|
||||||
fprintf(stderr, "ld-iscsi: Failed to create context\n");
|
|
||||||
iscsi_fd_list[i].iscsi = NULL;
|
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
iscsi_url = iscsi_parse_full_url(iscsi_fd_list[i].iscsi, path);
|
iscsi_url = iscsi_parse_full_url(iscsi, path);
|
||||||
if (iscsi_url == NULL) {
|
if (iscsi_url == NULL) {
|
||||||
fprintf(stderr, "ld-iscsi: Failed to parse URL: %s\n",
|
fprintf(stderr, "ld-iscsi: Failed to parse URL: %s\n",
|
||||||
iscsi_get_error(iscsi_fd_list[i].iscsi));
|
iscsi_get_error(iscsi));
|
||||||
iscsi_destroy_context(iscsi_fd_list[i].iscsi);
|
iscsi_destroy_context(iscsi);
|
||||||
iscsi_fd_list[i].iscsi = NULL;
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
iscsi_set_targetname(iscsi_fd_list[i].iscsi, iscsi_url->target);
|
iscsi_set_targetname(iscsi, iscsi_url->target);
|
||||||
iscsi_set_session_type(iscsi_fd_list[i].iscsi, ISCSI_SESSION_NORMAL);
|
iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL);
|
||||||
iscsi_set_header_digest(iscsi_fd_list[i].iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
|
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
|
||||||
|
|
||||||
if (iscsi_url->user != NULL) {
|
if (iscsi_url->user != NULL) {
|
||||||
if (iscsi_set_initiator_username_pwd(iscsi_fd_list[i].iscsi, iscsi_url->user, iscsi_url->passwd) != 0) {
|
if (iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, iscsi_url->passwd) != 0) {
|
||||||
fprintf(stderr, "Failed to set initiator username and password\n");
|
fprintf(stderr, "Failed to set initiator username and password\n");
|
||||||
iscsi_destroy_context(iscsi_fd_list[i].iscsi);
|
iscsi_destroy_context(iscsi);
|
||||||
iscsi_fd_list[i].iscsi = NULL;
|
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iscsi_full_connect_sync(iscsi_fd_list[i].iscsi, iscsi_url->portal, iscsi_url->lun) != 0) {
|
if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) {
|
||||||
fprintf(stderr, "ld-iscsi: Login Failed. %s\n", iscsi_get_error(iscsi_fd_list[i].iscsi));
|
fprintf(stderr, "ld-iscsi: Login Failed. %s\n", iscsi_get_error(iscsi));
|
||||||
iscsi_destroy_url(iscsi_url);
|
iscsi_destroy_url(iscsi_url);
|
||||||
iscsi_destroy_context(iscsi_fd_list[i].iscsi);
|
iscsi_destroy_context(iscsi);
|
||||||
iscsi_fd_list[i].iscsi = NULL;
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
task = iscsi_readcapacity10_sync(iscsi_fd_list[i].iscsi, iscsi_url->lun, 0, 0);
|
task = iscsi_readcapacity10_sync(iscsi, iscsi_url->lun, 0, 0);
|
||||||
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
||||||
fprintf(stderr, "ld-iscsi: failed to send readcapacity command\n");
|
fprintf(stderr, "ld-iscsi: failed to send readcapacity command\n");
|
||||||
iscsi_destroy_url(iscsi_url);
|
iscsi_destroy_url(iscsi_url);
|
||||||
iscsi_destroy_context(iscsi_fd_list[i].iscsi);
|
iscsi_destroy_context(iscsi);
|
||||||
iscsi_fd_list[i].iscsi = NULL;
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -107,61 +95,109 @@ int open(const char *path, int flags, mode_t mode)
|
|||||||
fprintf(stderr, "ld-iscsi: failed to unmarshall readcapacity10 data\n");
|
fprintf(stderr, "ld-iscsi: failed to unmarshall readcapacity10 data\n");
|
||||||
scsi_free_scsi_task(task);
|
scsi_free_scsi_task(task);
|
||||||
iscsi_destroy_url(iscsi_url);
|
iscsi_destroy_url(iscsi_url);
|
||||||
iscsi_destroy_context(iscsi_fd_list[i].iscsi);
|
iscsi_destroy_context(iscsi);
|
||||||
iscsi_fd_list[i].iscsi = NULL;
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
iscsi_fd_list[i].block_size = rc10->block_size;
|
fd = iscsi_get_fd(iscsi);
|
||||||
iscsi_fd_list[i].num_blocks = rc10->lba;
|
if (fd >= ISCSI_MAX_FD) {
|
||||||
iscsi_fd_list[i].offset = 0;
|
fprintf(stderr, "ld-iscsi: Too many files open\n");
|
||||||
iscsi_fd_list[i].lun = iscsi_url->lun;
|
iscsi_destroy_url(iscsi_url);
|
||||||
|
iscsi_destroy_context(iscsi);
|
||||||
|
errno = ENFILE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iscsi_fd_list[fd].is_iscsi = 1;
|
||||||
|
iscsi_fd_list[fd].dup2fd = -1;
|
||||||
|
iscsi_fd_list[fd].iscsi = iscsi;
|
||||||
|
iscsi_fd_list[fd].block_size = rc10->block_size;
|
||||||
|
iscsi_fd_list[fd].num_blocks = rc10->lba;
|
||||||
|
iscsi_fd_list[fd].offset = 0;
|
||||||
|
iscsi_fd_list[fd].lun = iscsi_url->lun;
|
||||||
|
|
||||||
scsi_free_scsi_task(task);
|
scsi_free_scsi_task(task);
|
||||||
iscsi_destroy_url(iscsi_url);
|
iscsi_destroy_url(iscsi_url);
|
||||||
|
|
||||||
return ISCSI_FD_MASK | i;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
return(real_open(path, flags, mode));
|
return real_open(path, flags, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
int (*real_close)(int fd);
|
int (*real_close)(int fd);
|
||||||
|
|
||||||
int close(int fd)
|
int close(int fd)
|
||||||
{
|
{
|
||||||
if ((fd & ISCSI_FD_MASK) == ISCSI_FD_MASK) {
|
if (iscsi_fd_list[fd].is_iscsi == 1) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
i = fd & ISCSI_FD_NUM;
|
if (iscsi_fd_list[fd].dup2fd >= 0) {
|
||||||
|
iscsi_fd_list[fd].is_iscsi = 0;
|
||||||
|
iscsi_fd_list[fd].dup2fd = -1;
|
||||||
|
real_close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
iscsi_destroy_context(iscsi_fd_list[i].iscsi);
|
/* are there any FDs dup2ed onto this ? */
|
||||||
iscsi_fd_list[i].iscsi = NULL;
|
for(i = 0; i < ISCSI_MAX_FD; i++) {
|
||||||
|
if (iscsi_fd_list[i].dup2fd == fd) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i < ISCSI_MAX_FD) {
|
||||||
|
int j;
|
||||||
|
|
||||||
|
/* yes there are DUPs onto fd, make i the new real device and repoint all other
|
||||||
|
* duplicates
|
||||||
|
*/
|
||||||
|
memcpy(&iscsi_fd_list[i], &iscsi_fd_list[fd], sizeof(struct iscsi_fd_list));
|
||||||
|
iscsi_fd_list[i].dup2fd = -1;
|
||||||
|
|
||||||
|
memset(&iscsi_fd_list[fd], 0, sizeof(struct iscsi_fd_list));
|
||||||
|
iscsi_fd_list[fd].dup2fd = -1;
|
||||||
|
|
||||||
|
iscsi_fd_list[i].iscsi->fd = i;
|
||||||
|
real_close(fd);
|
||||||
|
|
||||||
|
for(j = 0; j < ISCSI_MAX_FD; j++) {
|
||||||
|
if (j != i && iscsi_fd_list[j].dup2fd == fd) {
|
||||||
|
iscsi_fd_list[j].dup2fd = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
iscsi_fd_list[fd].is_iscsi = 0;
|
||||||
|
iscsi_fd_list[fd].dup2fd = -1;
|
||||||
|
iscsi_destroy_context(iscsi_fd_list[fd].iscsi);
|
||||||
|
iscsi_fd_list[fd].iscsi = NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return(real_close(fd));
|
return real_close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int (*real_fxstat)(int ver, int fd, struct stat *buf);
|
int (*real_fxstat)(int ver, int fd, struct stat *buf);
|
||||||
|
|
||||||
int __fxstat(int ver, int fd, struct stat *buf)
|
int __fxstat(int ver, int fd, struct stat *buf)
|
||||||
{
|
{
|
||||||
if ((fd & ISCSI_FD_MASK) == ISCSI_FD_MASK) {
|
if (iscsi_fd_list[fd].is_iscsi == 1) {
|
||||||
int i;
|
if (iscsi_fd_list[fd].dup2fd >= 0) {
|
||||||
|
return __fxstat(ver, iscsi_fd_list[fd].dup2fd, buf);
|
||||||
i = fd & ISCSI_FD_NUM;
|
}
|
||||||
|
|
||||||
memset(buf, 0, sizeof(struct stat));
|
memset(buf, 0, sizeof(struct stat));
|
||||||
buf->st_mode = S_IRUSR | S_IRGRP | S_IROTH | S_IFREG;
|
buf->st_mode = S_IRUSR | S_IRGRP | S_IROTH | S_IFREG;
|
||||||
buf->st_size = iscsi_fd_list[i].num_blocks * iscsi_fd_list[i].block_size;
|
buf->st_size = iscsi_fd_list[fd].num_blocks * iscsi_fd_list[fd].block_size;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return(real_fxstat(ver, fd, buf));
|
return real_fxstat(ver, fd, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -182,7 +218,7 @@ int __lxstat(int ver, const char *path, struct stat *buf)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return(real_lxstat(ver, path, buf));
|
return real_lxstat(ver, path, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
int (*real_xstat)(int ver, __const char *path, struct stat *buf);
|
int (*real_xstat)(int ver, __const char *path, struct stat *buf);
|
||||||
@@ -196,37 +232,73 @@ ssize_t (*real_read)(int fd, void *buf, size_t count);
|
|||||||
|
|
||||||
ssize_t read(int fd, void *buf, size_t count)
|
ssize_t read(int fd, void *buf, size_t count)
|
||||||
{
|
{
|
||||||
if ((fd & ISCSI_FD_MASK) == ISCSI_FD_MASK) {
|
if ((iscsi_fd_list[fd].is_iscsi == 1) && (iscsi_fd_list[fd].in_flight == 0)) {
|
||||||
int i;
|
|
||||||
uint64_t offset;
|
uint64_t offset;
|
||||||
uint32_t num_blocks;
|
uint32_t num_blocks;
|
||||||
struct scsi_task *task;
|
struct scsi_task *task;
|
||||||
|
|
||||||
i = fd & ISCSI_FD_NUM;
|
if (iscsi_fd_list[fd].dup2fd >= 0) {
|
||||||
|
return read(iscsi_fd_list[fd].dup2fd, buf, count);
|
||||||
|
}
|
||||||
|
offset = iscsi_fd_list[fd].offset / iscsi_fd_list[fd].block_size * iscsi_fd_list[fd].block_size;
|
||||||
|
num_blocks = (iscsi_fd_list[fd].offset - offset + count + iscsi_fd_list[fd].block_size - 1) / iscsi_fd_list[fd].block_size;
|
||||||
|
|
||||||
offset = iscsi_fd_list[i].offset / iscsi_fd_list[i].block_size * iscsi_fd_list[i].block_size;
|
iscsi_fd_list[fd].in_flight = 1;
|
||||||
num_blocks = (iscsi_fd_list[i].offset - offset + count + iscsi_fd_list[i].block_size - 1) / iscsi_fd_list[i].block_size;
|
task = iscsi_read10_sync(iscsi_fd_list[fd].iscsi, iscsi_fd_list[fd].lun, offset / iscsi_fd_list[fd].block_size, num_blocks * iscsi_fd_list[fd].block_size, iscsi_fd_list[fd].block_size);
|
||||||
|
iscsi_fd_list[fd].in_flight = 0;
|
||||||
|
|
||||||
task = iscsi_read10_sync(iscsi_fd_list[i].iscsi, iscsi_fd_list[i].lun, offset / iscsi_fd_list[i].block_size, num_blocks * iscsi_fd_list[i].block_size, iscsi_fd_list[i].block_size);
|
|
||||||
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
||||||
fprintf(stderr, "ld-iscsi: failed to send read10 command\n");
|
fprintf(stderr, "ld-iscsi: failed to send read10 command\n");
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(buf, &task->datain.data[iscsi_fd_list[i].offset - offset], count);
|
memcpy(buf, &task->datain.data[iscsi_fd_list[fd].offset - offset], count);
|
||||||
iscsi_fd_list[i].offset += count;
|
iscsi_fd_list[fd].offset += count;
|
||||||
|
|
||||||
scsi_free_scsi_task(task);
|
scsi_free_scsi_task(task);
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
return(real_read(fd, buf, count));
|
return real_read(fd, buf, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int (*real_dup2)(int oldfd, int newfd);
|
||||||
|
|
||||||
|
int dup2(int oldfd, int newfd)
|
||||||
|
{
|
||||||
|
close(newfd);
|
||||||
|
|
||||||
|
if (iscsi_fd_list[oldfd].is_iscsi == 1) {
|
||||||
|
int ret;
|
||||||
|
if (iscsi_fd_list[oldfd].dup2fd >= 0) {
|
||||||
|
return dup2(iscsi_fd_list[oldfd].dup2fd, newfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = real_dup2(oldfd, newfd);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
iscsi_fd_list[newfd].is_iscsi = 1;
|
||||||
|
iscsi_fd_list[newfd].dup2fd = oldfd;
|
||||||
|
|
||||||
|
return newfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
return real_dup2(oldfd, newfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void _init(void)
|
void _init(void)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < ISCSI_MAX_FD; i++) {
|
||||||
|
iscsi_fd_list[i].dup2fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
real_open = dlsym(RTLD_NEXT, "open");
|
real_open = dlsym(RTLD_NEXT, "open");
|
||||||
if (real_open == NULL) {
|
if (real_open == NULL) {
|
||||||
fprintf(stderr, "ld_iscsi: Failed to dlsym(open)\n");
|
fprintf(stderr, "ld_iscsi: Failed to dlsym(open)\n");
|
||||||
@@ -261,4 +333,10 @@ void _init(void)
|
|||||||
fprintf(stderr, "ld_iscsi: Failed to dlsym(read)\n");
|
fprintf(stderr, "ld_iscsi: Failed to dlsym(read)\n");
|
||||||
exit(10);
|
exit(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
real_dup2 = dlsym(RTLD_NEXT, "dup2");
|
||||||
|
if (real_dup2 == NULL) {
|
||||||
|
fprintf(stderr, "ld_iscsi: Failed to dlsym(dup2)\n");
|
||||||
|
exit(10);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user