aboutsummaryrefslogtreecommitdiff
path: root/archive/sgs_dd.c
diff options
context:
space:
mode:
Diffstat (limited to 'archive/sgs_dd.c')
-rw-r--r--archive/sgs_dd.c893
1 files changed, 0 insertions, 893 deletions
diff --git a/archive/sgs_dd.c b/archive/sgs_dd.c
deleted file mode 100644
index fa34d7b1..00000000
--- a/archive/sgs_dd.c
+++ /dev/null
@@ -1,893 +0,0 @@
-/* We need F_SETSIG, (signal redirect), so following define */
-#define _GNU_SOURCE 1
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-#include <poll.h>
-#include <signal.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include "sg_lib.h"
-#include "sg_linux_inc.h"
-
-/* Test code for the extensions to the Linux OS SCSI generic ("sg")
- device driver.
-* Copyright (C) 1999 D. Gilbert and P. Allworth
-* 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, or (at your option)
-* any later version.
-
- This program is a specialization of the Unix "dd" command in which
- one or both of the given files is a scsi generic device. A block size
- ('bs') is assumed to be 512 if not given. This program complains if
- 'ibs' or 'obs' are given with some other value than 'bs'.
- If 'if' is not given or 'if=-' then stdin is assumed. If 'of' is
- not given of 'of=-' then stdout assumed. The multipliers "c, b, k, m"
- are recognized on numeric arguments.
-
- A non-standard argument "bpt" (blocks per transfer) is added to control
- the maximum number of blocks in each transfer. The default value is 128.
- For example if "bs=512" and "bpt=32" then a maximum of 32 blocks (16KB
- in this case) are transferred to or from the sg device in a single SCSI
- command.
-
- BEWARE: If the 'of' file is a 'sg' device (eg a disk) then it _will_
- be written to, potentially destroying its previous contents.
-
- This version should compile with Linux sg drivers with version numbers
- >= 30000 . Also this version tries to use real time signals.
-
- Version 3.99 20020126
-
-
-6 byte commands [READ: 0x08, WRITE: 0x0a]:
-[cmd ][had|lu][midAdd][lowAdd][count ][flags ]
-10 byte commands [EREAD: 0x28, EWRITE: 0x2a, READ_CAPACITY 0x25]:
-[cmd ][ |lu][hiAddr][hmAddr][lmAddr][lowAdd][ ][hiCnt ][lowCnt][flags ]
-12 byte commands [LREAD: 0xd8, LWRITE: 0xda]:
-[cmd ][ |lu][hiAddr][hmAddr][lmAddr][lowAdd][hiCnt ][hmCnt ][lmCnt ][lowCnt]
- ... [ ][flags ]
-*/
-
-#define DEF_BLOCK_SIZE 512
-#define DEF_BLOCKS_PER_TRANSFER 128
-
-/* #define SG_DEBUG */
-
-#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
-#define DEF_TIMEOUT 40000 /* 40,000 millisecs == 40 seconds */
-#define S_RW_LEN 10 /* Use SCSI READ(10) and WRITE(10) */
-#define SGQ_MAX_RD_AHEAD 4
-#define SGQ_MAX_WR_AHEAD 4
-#define SGQ_NUM_ELEMS (SGQ_MAX_RD_AHEAD+ SGQ_MAX_WR_AHEAD + 1)
-
-#define SGQ_FREE 0
-#define SGQ_IO_STARTED 1
-#define SGQ_IO_FINISHED 2
-#define SGQ_IO_ERR 3
-#define SGQ_IO_WAIT 4
-
-#define SGQ_CAN_DO_NOTHING 0 /* only temporarily in use */
-#define SGQ_CAN_READ 1
-#define SGQ_CAN_WRITE 2
-#define SGQ_TIMEOUT 4
-
-
-#define STR_SZ 1024
-#define INOUTF_SZ 512
-#define EBUFF_SZ 512
-
-
-typedef struct request_element
-{
- struct request_element * nextp;
- int state;
- int wr;
- int blk;
- int num_blks;
- unsigned char * buffp;
- sg_io_hdr_t io_hdr;
- unsigned char cmd[S_RW_LEN];
- unsigned char sb[SENSE_BUFF_LEN];
- int result;
- int stop_after_wr;
-} Rq_elem;
-
-typedef struct request_collection
-{
- int infd;
- int in_is_sg;
- int in_blk; /* most recent read */
- int in_count; /* most recent read */
- int in_done_count; /* count of completed in blocks */
- int in_partial;
- int outfd;
- int out_is_sg;
- int lowest_seek;
- int out_blk; /* most recent write */
- int out_count; /* most recent write */
- int out_done_count; /* count of completed out blocks */
- int out_partial;
- int bs;
- int bpt;
- int dio;
- int dio_incomplete;
- int sum_of_resids;
- int debug;
- sigset_t blocked_sigs;
- int sigs_waiting;
- Rq_elem * rd_posp;
- Rq_elem * wr_posp;
- Rq_elem elem[SGQ_NUM_ELEMS];
-} Rq_coll;
-
-
-void usage()
-{
- printf("Usage: "
- "sgs_dd [if=<infile>] [skip=<n>] [of=<ofile>] [seek=<n>]\n"
- " [bs=<num>] [bpt=<num>] [count=<n>]"
- " [dio=<n>] [deb=<n>]\n"
- " either 'if' or 'of' must be a scsi generic device\n"
- " 'bpt' is blocks_per_transfer (default is 128)\n"
- " 'dio' is direct IO, 1->attempt, 0->indirect IO (def)\n"
- " 'deb' is debug, 1->output some, 0->no debug (def)\n");
-}
-
-/* Return of 0 -> success, -1 -> failure, 2 -> try again */
-int read_capacity(int sg_fd, int * num_sect, int * sect_sz)
-{
- int res;
- unsigned char rcCmdBlk [10] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char rcBuff[64];
- unsigned char sense_b[64];
- sg_io_hdr_t io_hdr;
-
- memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
- io_hdr.interface_id = 'S';
- io_hdr.cmd_len = sizeof(rcCmdBlk);
- io_hdr.mx_sb_len = sizeof(sense_b);
- io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
- io_hdr.dxfer_len = sizeof(rcBuff);
- io_hdr.dxferp = rcBuff;
- io_hdr.cmdp = rcCmdBlk;
- io_hdr.sbp = sense_b;
- io_hdr.timeout = DEF_TIMEOUT;
-
- if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
- perror("read_capacity (SG_IO) error");
- return -1;
- }
- res = sg_err_category3(&io_hdr);
- if (SG_LIB_CAT_UNIT_ATTENTION == res)
- return 2; /* probably have another go ... */
- else if (SG_LIB_CAT_CLEAN != res) {
- sg_chk_n_print3("read capacity", &io_hdr);
- return -1;
- }
- *num_sect = 1 + ((rcBuff[0] << 24) | (rcBuff[1] << 16) |
- (rcBuff[2] << 8) | rcBuff[3]);
- *sect_sz = (rcBuff[4] << 24) | (rcBuff[5] << 16) |
- (rcBuff[6] << 8) | rcBuff[7];
-#ifdef SG_DEBUG
- printf("number of sectors=%d, sector size=%d\n", *num_sect, *sect_sz);
-#endif
- return 0;
-}
-
-/* -ve -> unrecoverable error, 0 -> successful, 1 -> recoverable (ENOMEM) */
-int sg_start_io(Rq_coll * clp, Rq_elem * rep)
-{
- sg_io_hdr_t * hp = &rep->io_hdr;
- int res;
-
- memset(rep->cmd, 0, sizeof(rep->cmd));
- rep->cmd[0] = rep->wr ? 0x2a : 0x28;
- rep->cmd[2] = (unsigned char)((rep->blk >> 24) & 0xFF);
- rep->cmd[3] = (unsigned char)((rep->blk >> 16) & 0xFF);
- rep->cmd[4] = (unsigned char)((rep->blk >> 8) & 0xFF);
- rep->cmd[5] = (unsigned char)(rep->blk & 0xFF);
- rep->cmd[7] = (unsigned char)((rep->num_blks >> 8) & 0xff);
- rep->cmd[8] = (unsigned char)(rep->num_blks & 0xff);
- memset(hp, 0, sizeof(sg_io_hdr_t));
- hp->interface_id = 'S';
- hp->cmd_len = sizeof(rep->cmd);
- hp->cmdp = rep->cmd;
- hp->dxfer_direction = rep->wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV;
- hp->dxfer_len = clp->bs * rep->num_blks;
- hp->dxferp = rep->buffp;
- hp->mx_sb_len = sizeof(rep->sb);
- hp->sbp = rep->sb;
- hp->timeout = DEF_TIMEOUT;
- hp->usr_ptr = rep;
- hp->pack_id = rep->blk;
- if (clp->dio)
- hp->flags |= SG_FLAG_DIRECT_IO;
-#ifdef SG_DEBUG
- printf("sg_start_io: SCSI %s, blk=%d num_blks=%d\n",
- rep->wr ? "WRITE" : "READ", rep->blk, rep->num_blks);
- sg_print_command(hp->cmdp);
- printf("dir=%d, len=%d, dxfrp=%p, cmd_len=%d\n", hp->dxfer_direction,
- hp->dxfer_len, hp->dxferp, hp->cmd_len);
-#endif
-
- while (((res = write(rep->wr ? clp->outfd : clp->infd, hp,
- sizeof(sg_io_hdr_t))) < 0) && (EINTR == errno))
- ;
- if (res < 0) {
- if (ENOMEM == errno)
- return 1;
- if ((EDOM == errno) || (EAGAIN == errno)) {
- rep->state = SGQ_IO_WAIT; /* busy so wait */
- return 0;
- }
- perror("starting io on sg device, error");
- rep->state = SGQ_IO_ERR;
- return res;
- }
- rep->state = SGQ_IO_STARTED;
- clp->sigs_waiting++;
- return 0;
-}
-
-/* -1 -> unrecoverable error, 0 -> successful, 1 -> try again */
-int sg_finish_io(Rq_coll * clp, int wr, Rq_elem ** repp)
-{
- int res;
- sg_io_hdr_t io_hdr;
- sg_io_hdr_t * hp;
- Rq_elem * rep;
-
- memset(&io_hdr, 0 , sizeof(sg_io_hdr_t));
- while (((res = read(wr ? clp->outfd : clp->infd, &io_hdr,
- sizeof(sg_io_hdr_t))) < 0) && (EINTR == errno))
- ;
- rep = (Rq_elem *)io_hdr.usr_ptr;
- if (res < 0) {
- perror("finishing io on sg device, error");
- rep->state = SGQ_IO_ERR;
- return -1;
- }
- if (! (rep && (SGQ_IO_STARTED == rep->state))) {
- printf("sg_finish_io: bad usr_ptr\n");
- rep->state = SGQ_IO_ERR;
- return -1;
- }
- memcpy(&rep->io_hdr, &io_hdr, sizeof(sg_io_hdr_t));
- hp = &rep->io_hdr;
- if (repp)
- *repp = rep;
-
- switch (sg_err_category3(hp)) {
- case SG_LIB_CAT_CLEAN:
- break;
- case SG_LIB_CAT_RECOVERED:
- printf("Recovered error on block=%d, num=%d\n",
- rep->blk, rep->num_blks);
- break;
- case SG_LIB_CAT_UNIT_ATTENTION:
- return 1;
- default:
- sg_chk_n_print3(rep->wr ? "writing": "reading", hp);
- rep->state = SGQ_IO_ERR;
- return -1;
- }
- if (clp->dio &&
- ((hp->info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO))
- ++clp->dio_incomplete; /* count dios done as indirect IO */
- clp->sum_of_resids += hp->resid;
- rep->state = SGQ_IO_FINISHED;
-#ifdef SG_DEBUG
- printf("sg_finish_io: %s ", wr ? "writing" : "reading");
- printf(" SGQ_IO_FINISHED elem idx=%d\n", rep - clp->elem);
-#endif
- return 0;
-}
-
-int sz_reserve(int fd, int bs, int bpt)
-{
- int res, t, flags;
-
- res = ioctl(fd, SG_GET_VERSION_NUM, &t);
- if ((res < 0) || (t < 30000)) {
- printf("sgs_dd: sg driver prior to 3.x.y\n");
- return 1;
- }
- res = 0;
- t = bs * bpt;
- res = ioctl(fd, SG_SET_RESERVED_SIZE, &t);
- if (res < 0)
- perror("sgs_dd: SG_SET_RESERVED_SIZE error");
- if (-1 == fcntl(fd, F_SETOWN, getpid())) {
- perror("fcntl(,F_SETOWN,)");
- return 1;
- }
- flags = fcntl(fd, F_GETFL, 0);
- if (-1 == fcntl(fd, F_SETFL, flags | O_ASYNC)) {
- perror("fcntl(,F_SETFL,)");
- return 1;
- }
- fcntl(fd, F_SETSIG, SIGRTMIN + 1);
- return 0;
-}
-
-void init_elems(Rq_coll * clp)
-{
- Rq_elem * rep;
- int k;
-
- clp->wr_posp = &clp->elem[0]; /* making ring buffer */
- clp->rd_posp = clp->wr_posp;
- for (k = 0; k < SGQ_NUM_ELEMS - 1; ++k)
- clp->elem[k].nextp = &clp->elem[k + 1];
- clp->elem[SGQ_NUM_ELEMS - 1].nextp = &clp->elem[0];
- for (k = 0; k < SGQ_NUM_ELEMS; ++k) {
- rep = &clp->elem[k];
- rep->state = SGQ_FREE;
- if (NULL == (rep->buffp = malloc(clp->bpt * clp->bs)))
- printf("out of memory creating user buffers\n");
- }
-}
-
-int start_read(Rq_coll * clp)
-{
- int blocks = (clp->in_count > clp->bpt) ? clp->bpt : clp->in_count;
- Rq_elem * rep = clp->rd_posp;
- int buf_sz, res;
- char ebuff[EBUFF_SZ];
-
-#ifdef SG_DEBUG
- printf("start_read, elem idx=%d\n", rep - clp->elem);
-#endif
- rep->wr = 0;
- rep->blk = clp->in_blk;
- rep->num_blks = blocks;
- clp->in_blk += blocks;
- clp->in_count -= blocks;
- if (clp->in_is_sg) {
- res = sg_start_io(clp, rep);
- if (1 == res) { /* ENOMEM, find what's available+try that */
- if ((res = ioctl(clp->infd, SG_GET_RESERVED_SIZE, &buf_sz)) < 0) {
- perror("RESERVED_SIZE ioctls failed");
- return res;
- }
- clp->bpt = (buf_sz + clp->bs - 1) / clp->bs;
- printf("Reducing blocks per transfer to %d\n", clp->bpt);
- if (clp->bpt < 1)
- return -ENOMEM;
- res = sg_start_io(clp, rep);
- if (1 == res)
- res = -ENOMEM;
- }
- else if (res < 0) {
- printf("sgs_dd inputting from sg failed, blk=%d\n", rep->blk);
- rep->state = SGQ_IO_ERR;
- return res;
- }
- }
- else {
- rep->state = SGQ_IO_STARTED;
- while (((res = read(clp->infd, rep->buffp, blocks * clp->bs)) < 0) &&
- (EINTR == errno))
- ;
- if (res < 0) {
- snprintf(ebuff, EBUFF_SZ, "sgs_dd: reading, in_blk=%d ", rep->blk);
- perror(ebuff);
- rep->state = SGQ_IO_ERR;
- return res;
- }
- if (res < blocks * clp->bs) {
- int o_blocks = blocks;
- rep->stop_after_wr = 1;
- blocks = res / clp->bs;
- if ((res % clp->bs) > 0) {
- blocks++;
- clp->in_partial++;
- }
- /* Reverse out + re-apply blocks on clp */
- clp->in_blk -= o_blocks;
- clp->in_count += o_blocks;
- rep->num_blks = blocks;
- clp->in_blk += blocks;
- clp->in_count -= blocks;
- }
- clp->in_done_count -= blocks;
- rep->state = SGQ_IO_FINISHED;
- }
- clp->rd_posp = rep->nextp;
- return blocks;
-}
-
-int start_write(Rq_coll * clp)
-{
- Rq_elem * rep = clp->wr_posp;
- int res, blocks;
- char ebuff[EBUFF_SZ];
-
- while ((0 != rep->wr) || (SGQ_IO_FINISHED != rep->state)) {
- rep = rep->nextp;
- if (rep == clp->rd_posp)
- return -1;
- }
-#ifdef SG_DEBUG
- printf("start_write, elem idx=%d\n", rep - clp->elem);
-#endif
- rep->wr = 1;
- blocks = rep->num_blks;
- rep->blk = clp->out_blk;
- clp->out_blk += blocks;
- clp->out_count -= blocks;
- if (clp->out_is_sg) {
- res = sg_start_io(clp, rep);
- if (1 == res) /* ENOMEM, give up */
- return -ENOMEM;
- else if (res < 0) {
- printf("sgs_dd output to sg failed, blk=%d\n", rep->blk);
- rep->state = SGQ_IO_ERR;
- return res;
- }
- }
- else {
- rep->state = SGQ_IO_STARTED;
- while (((res = write(clp->outfd, rep->buffp,
- rep->num_blks * clp->bs)) < 0) && (EINTR == errno))
- ;
- if (res < 0) {
- snprintf(ebuff, EBUFF_SZ, "sgs_dd: output, out_blk=%d ", rep->blk);
- perror(ebuff);
- rep->state = SGQ_IO_ERR;
- return res;
- }
- if (res < blocks * clp->bs) {
- blocks = res / clp->bs;
- if ((res % clp->bs) > 0) {
- blocks++;
- clp->out_partial++;
- }
- rep->num_blks = blocks;
- }
- rep->state = SGQ_IO_FINISHED;
- }
- return blocks;
-}
-
-int do_poll(Rq_coll * clp, int fd)
-{
- struct pollfd a_pollfd = {0, POLLIN | POLLOUT, 0};
- siginfo_t info;
-
- a_pollfd.fd = fd;
- if (poll(&a_pollfd, 1, 0) < 0) {
- perror("poll error");
- return 0;
- }
- /* printf("do_poll: revents=0x%x\n", (int)a_pollfd.revents); */
- if (a_pollfd.revents & POLLIN) {
- if (clp->sigs_waiting) {
- while (sigwaitinfo(&clp->blocked_sigs, &info) < 0) {
- if (EINTR != errno) {
- perror("sigwaitinfo"); /* consume signal */
- return -1;
- }
- }
- if ((SIGRTMIN + 1) == info.si_signo)
- clp->sigs_waiting--;
- if (SIGIO == info.si_signo) {
- printf("SIGIO received, continue\n");
- clp->sigs_waiting = 0;
- }
- else
- return -1;
- }
- return 1;
- }
- else
- return 0;
-}
-
-int can_read_write(Rq_coll * clp)
-{
- Rq_elem * rep = NULL;
- int res = 0;
- int reading = 0;
- int writing = 0;
- int writeable = 0;
- int rd_waiting = 0;
- int wr_waiting = 0;
- int sg_finished = 0;
- siginfo_t info;
-
- /* if write completion pending, then complete it + start read */
- if (clp->out_is_sg) {
- while ((res = do_poll(clp, clp->outfd))) {
- if (res < 0)
- return res;
- res = sg_finish_io(clp, 1, &rep);
- if (res < 0)
- return res;
- else if (1 == res) {
- res = sg_start_io(clp, rep);
- if (0 != res)
- return -1; /* give up if any problems with retry */
- }
- else
- sg_finished++;
- }
- while ((rep = clp->wr_posp) && (SGQ_IO_FINISHED == rep->state) &&
- (1 == rep->wr) && (rep != clp->rd_posp)) {
- rep->state = SGQ_FREE;
- clp->out_done_count -= rep->num_blks;
- clp->wr_posp = rep->nextp;
- if (rep->stop_after_wr)
- return -1;
- }
- }
- else if ((rep = clp->wr_posp) && (1 == rep->wr) &&
- (SGQ_IO_FINISHED == rep->state)) {
- rep->state = SGQ_FREE;
- clp->out_done_count -= rep->num_blks;
- clp->wr_posp = rep->nextp;
- if (rep->stop_after_wr)
- return -1;
- }
-
- /* if read completion pending, then complete it + start maybe write */
- if (clp->in_is_sg) {
- while ((res = do_poll(clp, clp->infd))) {
- if (res < 0)
- return res;
- res = sg_finish_io(clp, 0, &rep);
- if (res < 0)
- return res;
- if (1 == res) {
- res = sg_start_io(clp, rep);
- if (0 != res)
- return -1; /* give up if any problems with retry */
- }
- else {
- sg_finished++;
- clp->in_done_count -= rep->num_blks;
- }
- }
- }
-
- for (rep = clp->wr_posp, res = 1;
- rep != clp->rd_posp; rep = rep->nextp) {
- if (SGQ_IO_STARTED == rep->state) {
- if (rep->wr)
- ++writing;
- else {
- res = 0;
- ++reading;
- }
- }
- else if ((0 == rep->wr) && (SGQ_IO_FINISHED == rep->state)) {
- if (res)
- writeable = 1;
- }
- else if (SGQ_IO_WAIT == rep->state) {
- res = 0;
- if (rep->wr)
- ++wr_waiting;
- else
- ++rd_waiting;
- }
- else
- res = 0;
- }
- if (clp->debug) {
- if ((clp->debug >= 9) || wr_waiting || rd_waiting)
- printf("%d/%d (nwb/nrb): read=%d/%d (do/wt) "
- "write=%d/%d (do/wt) writeable=%d sg_fin=%d\n",
- clp->out_blk, clp->in_blk, reading, rd_waiting,
- writing, wr_waiting, writeable, sg_finished);
- fflush(stdout);
- }
- if (writeable && (writing < SGQ_MAX_WR_AHEAD) && (clp->out_count > 0))
- return SGQ_CAN_WRITE;
- if ((reading < SGQ_MAX_RD_AHEAD) && (clp->in_count > 0) &&
- (0 == rd_waiting) && (clp->rd_posp->nextp != clp->wr_posp))
- return SGQ_CAN_READ;
-
- if (clp->out_done_count <= 0)
- return SGQ_CAN_DO_NOTHING;
-
- /* usleep(10000); */ /* hang about for 10 milliseconds */
- if (clp->sigs_waiting) {
- while (sigwaitinfo(&clp->blocked_sigs, &info) < 0) {
- if (EINTR != errno) {
- perror("sigwaitinfo"); /* consume signal */
- return -1;
- }
- }
- if ((SIGRTMIN + 1) != info.si_signo)
- return -1;
- clp->sigs_waiting--;
- }
- /* Now check the _whole_ buffer for pending requests */
- for (rep = clp->rd_posp->nextp; rep != clp->rd_posp; rep = rep->nextp) {
- if (SGQ_IO_WAIT == rep->state) {
- res = sg_start_io(clp, rep);
- if (res < 0)
- return res;
- if (res > 0)
- return -1;
- break;
- }
- }
- return SGQ_CAN_DO_NOTHING;
-}
-
-
-int main(int argc, char * argv[])
-{
- int skip = 0;
- int seek = 0;
- int ibs = 0;
- int obs = 0;
- int count = -1;
- char str[STR_SZ];
- char * key;
- char * buf;
- char inf[INOUTF_SZ];
- char outf[INOUTF_SZ];
- int res, k;
- int in_num_sect = 0;
- int out_num_sect = 0;
- int in_sect_sz, out_sect_sz, crw;
- char ebuff[EBUFF_SZ];
- Rq_coll rcoll;
-
- memset(&rcoll, 0, sizeof(Rq_coll));
- rcoll.bpt = DEF_BLOCKS_PER_TRANSFER;
- inf[0] = '\0';
- outf[0] = '\0';
- if (argc < 2) {
- usage();
- return 1;
- }
-
- for(k = 1; k < argc; k++) {
- if (argv[k]) {
- strncpy(str, argv[k], STR_SZ);
- str[STR_SZ - 1] = '\0';
- }
- else
- continue;
- for(key = str, buf = key; *buf && *buf != '=';)
- buf++;
- if (*buf)
- *buf++ = '\0';
- if (strcmp(key,"if") == 0)
- strncpy(inf, buf, INOUTF_SZ);
- else if (strcmp(key,"of") == 0)
- strncpy(outf, buf, INOUTF_SZ);
- else if (0 == strcmp(key,"ibs"))
- ibs = sg_get_num(buf);
- else if (0 == strcmp(key,"obs"))
- obs = sg_get_num(buf);
- else if (0 == strcmp(key,"bs"))
- rcoll.bs = sg_get_num(buf);
- else if (0 == strcmp(key,"bpt"))
- rcoll.bpt = sg_get_num(buf);
- else if (0 == strcmp(key,"skip"))
- skip = sg_get_num(buf);
- else if (0 == strcmp(key,"seek"))
- seek = sg_get_num(buf);
- else if (0 == strcmp(key,"count"))
- count = sg_get_num(buf);
- else if (0 == strcmp(key,"dio"))
- rcoll.dio = sg_get_num(buf);
- else if (0 == strcmp(key,"deb"))
- rcoll.debug = sg_get_num(buf);
- else {
- printf("Unrecognized argument '%s'\n", key);
- usage();
- return 1;
- }
- }
- if (rcoll.bs <= 0) {
- rcoll.bs = DEF_BLOCK_SIZE;
- printf("Assume default 'bs' (block size) of %d bytes\n", rcoll.bs);
- }
- if ((ibs && (ibs != rcoll.bs)) || (obs && (obs != rcoll.bs))) {
- printf("If 'ibs' or 'obs' given must be same as 'bs'\n");
- usage();
- return 1;
- }
- if ((skip < 0) || (seek < 0)) {
- printf("skip and seek cannot be negative\n");
- return 1;
- }
-#ifdef SG_DEBUG
- printf("sgs_dd: if=%s skip=%d of=%s seek=%d count=%d\n",
- inf, skip, outf, seek, count);
-#endif
- rcoll.infd = STDIN_FILENO;
- rcoll.outfd = STDOUT_FILENO;
- if (inf[0] && ('-' != inf[0])) {
- if ((rcoll.infd = open(inf, O_RDONLY)) < 0) {
- snprintf(ebuff, EBUFF_SZ, "sgs_dd: could not open %s for reading",
- inf);
- perror(ebuff);
- return 1;
- }
- if (ioctl(rcoll.infd, SG_GET_TIMEOUT, 0) < 0) {
- rcoll.in_is_sg = 0;
- if (skip > 0) {
- off_t offset = skip;
-
- offset *= rcoll.bs; /* could overflow here! */
- if (lseek(rcoll.infd, offset, SEEK_SET) < 0) {
- snprintf(ebuff, EBUFF_SZ,
- "sgs_dd: couldn't skip to required position on %s", inf);
- perror(ebuff);
- return 1;
- }
- }
- }
- else { /* looks like sg device so close then re-open it RW */
- close(rcoll.infd);
- if ((rcoll.infd = open(inf, O_RDWR | O_NONBLOCK)) < 0) {
- printf("If %s is a sg device, need read+write permissions,"
- " even to read it!\n", inf);
- return 1;
- }
- rcoll.in_is_sg = 1;
- if (sz_reserve(rcoll.infd, rcoll.bs, rcoll.bpt))
- return 1;
- }
- }
- if (outf[0] && ('-' != outf[0])) {
- if ((rcoll.outfd = open(outf, O_RDWR | O_NONBLOCK)) >= 0) {
- if (ioctl(rcoll.outfd, SG_GET_TIMEOUT, 0) < 0) {
- /* not a scsi generic device so now try and open RDONLY */
- close(rcoll.outfd);
- }
- else {
- rcoll.out_is_sg = 1;
- if (sz_reserve(rcoll.outfd, rcoll.bs, rcoll.bpt))
- return 1;
- }
- }
- if (! rcoll.out_is_sg) {
- if ((rcoll.outfd = open(outf, O_WRONLY | O_CREAT, 0666)) < 0) {
- snprintf(ebuff, EBUFF_SZ,
- "sgs_dd: could not open %s for writing", outf);
- perror(ebuff);
- return 1;
- }
- else if (seek > 0) {
- off_t offset = seek;
-
- offset *= rcoll.bs; /* could overflow here! */
- if (lseek(rcoll.outfd, offset, SEEK_SET) < 0) {
- snprintf(ebuff, EBUFF_SZ,
- "sgs_dd: couldn't seek to required position on %s", outf);
- perror(ebuff);
- return 1;
- }
- }
- }
- }
- if ((STDIN_FILENO == rcoll.infd) && (STDOUT_FILENO == rcoll.outfd)) {
- printf("Can't have both 'if' as stdin _and_ 'of' as stdout\n");
- return 1;
- }
- if (! (rcoll.in_is_sg || rcoll.out_is_sg)) {
- printf("Either 'if' or 'of' must be a scsi generic device\n");
- return 1;
- }
- if (0 == count)
- return 0;
- else if (count < 0) {
- if (rcoll.in_is_sg) {
- res = read_capacity(rcoll.infd, &in_num_sect, &in_sect_sz);
- if (2 == res) {
- printf("Unit attention, media changed(in), try again\n");
- res = read_capacity(rcoll.infd, &in_num_sect, &in_sect_sz);
- }
- if (0 != res) {
- printf("Unable to read capacity on %s\n", inf);
- in_num_sect = -1;
- }
- else {
- if (in_num_sect > skip)
- in_num_sect -= skip;
- }
- }
- if (rcoll.out_is_sg) {
- res = read_capacity(rcoll.outfd, &out_num_sect, &out_sect_sz);
- if (2 == res) {
- printf("Unit attention, media changed(out), try again\n");
- res = read_capacity(rcoll.outfd, &out_num_sect, &out_sect_sz);
- }
- if (0 != res) {
- printf("Unable to read capacity on %s\n", outf);
- out_num_sect = -1;
- }
- else {
- if (out_num_sect > seek)
- out_num_sect -= seek;
- }
- }
-#ifdef SG_DEBUG
- printf("Start of loop, count=%d, in_num_sect=%d, out_num_sect=%d\n",
- count, in_num_sect, out_num_sect);
-#endif
- if (in_num_sect > 0) {
- if (out_num_sect > 0)
- count = (in_num_sect > out_num_sect) ? out_num_sect :
- in_num_sect;
- else
- count = in_num_sect;
- }
- else
- count = out_num_sect;
- }
-
-#ifdef SG_DEBUG
- printf("Start of loop, count=%d, bpt=%d\n", count, rcoll.bpt);
-#endif
-
- sigemptyset(&rcoll.blocked_sigs);
- sigaddset(&rcoll.blocked_sigs, SIGRTMIN + 1);
- sigaddset(&rcoll.blocked_sigs, SIGINT);
- sigaddset(&rcoll.blocked_sigs, SIGIO);
- sigprocmask(SIG_BLOCK, &rcoll.blocked_sigs, 0);
- rcoll.in_count = count;
- rcoll.in_done_count = count;
- rcoll.in_blk = skip;
- rcoll.out_count = count;
- rcoll.out_done_count = count;
- rcoll.out_blk = seek;
- init_elems(&rcoll);
-
-/* vvvvvvvvvvvvvvvvv Main Loop vvvvvvvvvvvvvvvvvvvvvvvv */
- while (rcoll.out_done_count > 0) {
- crw = can_read_write(&rcoll);
- if (crw < 0)
- break;
- if (SGQ_CAN_READ & crw) {
- res = start_read(&rcoll);
- if (res <= 0) {
- printf("start_read: res=%d\n", res);
- break;
- }
- }
- if (SGQ_CAN_WRITE & crw) {
- res = start_write(&rcoll);
- if (res <= 0) {
- printf("start_write: res=%d\n", res);
- break;
- }
- }
- }
-
- if (STDIN_FILENO != rcoll.infd)
- close(rcoll.infd);
- if (STDOUT_FILENO != rcoll.outfd)
- close(rcoll.outfd);
- if (0 != rcoll.out_count) {
- printf("Some error occurred, remaining blocks=%d\n", rcoll.out_count);
- return 1;
- }
- printf("%d+%d records in\n", count - rcoll.in_done_count,
- rcoll.in_partial);
- printf("%d+%d records out\n", count - rcoll.out_done_count,
- rcoll.out_partial);
- if (rcoll.dio_incomplete)
- printf(">> Direct IO requested but incomplete %d times\n",
- rcoll.dio_incomplete);
- if (rcoll.sum_of_resids)
- printf(">> Non-zero sum of residual counts=%d\n",
- rcoll.sum_of_resids);
- return 0;
-}