ftp.nice.ch/pub/next/unix/disk/rawdisk.N.bs.tar.gz#/rawdisk/rawdisk.c

This is rawdisk.c in view mode; [Download] [Up]

/*
 * rawdisk: spew stdin to raw disk(s) or raw disk(s) to stdout
 *	    for more details, see acompanying README file
 *
 * Copyright (C) 1991, Richard O'Neill.
 *
 * 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 1, 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.
 *
 *
 */

#include <c.h>
#include <stdio.h>
#include <stdlib.h>
#include <varargs.h>
#include <sys/errno.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <nextdev/disk.h>

const char *programname = "rawdisk";

/*
 * Emergency exiting...
 */

struct suicide_handler_info {};

typedef void ((*suicide_fun)(struct suicide_handler_info *, va_list args));

struct suicide_handler {
    suicide_fun action;
    struct suicide_handler_info info;
};

struct suicide_handler_list {
    struct suicide_handler *handler;
    struct suicide_handler_list *next;
};


void std_suicide (struct suicide_handler_info *info, va_list args)
{
    char *format;
    
    format = va_arg(args, char *);
    
    fprintf(stderr,"%s: ",programname);
    vfprintf(stderr,format,args);
    if (errno)
        fprintf(stderr," (%s)\n",strerror(errno));
    else
        fputc('\n',stderr);
}

struct suicide_handler 
    std_suicide_handler = {std_suicide, {}};

struct suicide_handler_list
    initial_suicide_handler_list = {&std_suicide_handler, NULL};
    
struct suicide_handler_list 
    *suicide_handler_list_ptr = &initial_suicide_handler_list;

static int exitcode;

void suicide (va_alist)
    va_dcl
{
    struct suicide_handler_list *cell_ptr;
    va_list args;
    
    va_start(args);
    exitcode = va_arg(args, int);
    cell_ptr = suicide_handler_list_ptr;
    while (cell_ptr != NULL) {
        (cell_ptr->handler->action)(&(cell_ptr->handler->info),args);
	cell_ptr = cell_ptr->next;
    }
    va_end(args);
    /* if (exitcode != 0xdeafbabe) */
        exit(exitcode);
}

void push_suicide_handler (struct suicide_handler *candidate) 
{
    struct suicide_handler_list *cell_ptr;
    
    cell_ptr = (struct suicide_handler_list *) malloc(sizeof(struct suicide_handler_list));
    if (cell_ptr == NULL)
        suicide(4, "Can't install error handler");
    cell_ptr->handler = candidate;
    cell_ptr->next = suicide_handler_list_ptr;
    suicide_handler_list_ptr = cell_ptr;
}

struct suicide_handler *pop_suicide_handler()
{
    struct suicide_handler_list *cell_ptr;
    struct suicide_handler *handler;

    cell_ptr = suicide_handler_list_ptr;
    suicide_handler_list_ptr = cell_ptr->next;
    handler = cell_ptr->handler;
    free(cell_ptr);
    return handler;
}


struct diskopen_suicide_handler_info {
    int disk_fd;
};

struct diskopen_suicide_handler {
    suicide_fun action;
    struct diskopen_suicide_handler_info info;
};

void diskopen_suicide(struct suicide_handler_info *info, va_list args)
{
   closedisk(((struct diskopen_suicide_handler_info *) info)->disk_fd);
}

void push_diskopen_suicide_handler(int disk_fd)
{
    struct diskopen_suicide_handler *handler;
    
    handler = (struct diskopen_suicide_handler *) malloc(sizeof(struct diskopen_suicide_handler));
    
    if (handler == NULL) {
        _closedisk(disk_fd);
        suicide(8,"Can't install error handler");
    }
	
    handler->action = diskopen_suicide;
    handler->info.disk_fd = disk_fd;
    
    push_suicide_handler((struct suicide_handler *) handler);
}

void pop_diskopen_suicide_handler()
{
   free(pop_suicide_handler());
}



int opendisk (flags)
   int flags;
{
    int ctrl_fd, disk_fd;
    int freevol;
    static char rawdevice[] = "/dev/rfd0a";
    struct drive_info drive_info;
    const char *control_dev = "/dev/fdc0";
    
    ctrl_fd = open (control_dev, O_RDONLY, 0);
    if (ctrl_fd < 0) 
        suicide(4, "Can't open disk controller, %s", control_dev);
    if (ioctl(ctrl_fd, DKIOCGFREEVOL, &freevol)) 
        suicide(8, "Can't find free volume, %s", control_dev);
    rawdevice[8] += freevol;
    disk_fd = open (rawdevice, flags, 0);
    close(ctrl_fd);
    if (disk_fd < 0) 
        suicide(2,"Can't open raw disk, %s", rawdevice);
    push_diskopen_suicide_handler(disk_fd);
    return disk_fd;
}

int _closedisk (disk_fd)
    int disk_fd;
{
    if (ioctl(disk_fd,DKIOCEJECT,NULL)) 
        suicide(8, "Can't eject disk");
    close(disk_fd);
}

int closedisk (disk_fd)
    int disk_fd;
{
    pop_diskopen_suicide_handler();
    _closedisk(disk_fd);
}

int sectorsize(disk_fd)
    int disk_fd;
{
    struct drive_info drive_info;

    if (ioctl(disk_fd,DKIOCINFO,&drive_info))
        suicide(8, "Can't determine sector size");
    return drive_info.di_devblklen;
}

#define CHUNKSIZE 65536

int readdisk()
{
    int in_fd;
    const int out_fd = 1;
    bool usingthisdisk, demand = true;
    int blocksize, chunksize, buffersize;
    void *buffer, *buffer_posn;
    int in_count, out_count, buffer_count;
    
    buffersize = 0;
    while(demand) {
        usingthisdisk = true;
        in_fd = opendisk(O_RDONLY);
        blocksize = sectorsize(in_fd);
	chunksize = (CHUNKSIZE / blocksize) * blocksize;
        if (buffersize < chunksize) {
           buffersize = chunksize;
           buffer = alloca(buffersize);
	}
        while(usingthisdisk) {
	    in_count = read(in_fd,buffer,chunksize);
	    if (in_count < 0) 
	    	suicide(4,"Unexpected error reading floppy");
	    else if (in_count == 0)
		usingthisdisk = false;
	    else {
	    	buffer_posn = buffer;
		buffer_count = in_count;
	    	do {
	    	    out_count = write(out_fd,buffer_posn,buffer_count);
		    buffer_posn += out_count;
		    buffer_count -= out_count;
		} while((buffer_count > 0) && (out_count > 0));
		if (out_count < 0) {
		    if (errno == EPIPE) {
		        usingthisdisk = false;
			demand = false;
		    }
		    else
		        suicide(4,"Unexpected error writing to stdout");
		} else if (out_count == 0)
		    suicide(8,"Strangeness writing to stdout");
	    }
	}
	closedisk(in_fd);
    }
}

int writedisk()
{
    const int in_fd = 0;
    int out_fd;
    bool usingthisdisk, roundagain, demand = true;
    int blocksize, chunksize, buffersize;
    void *buffer, *buffer_posn;
    int in_count, out_count, buffer_count;
    
    buffersize = 0;
    buffer_count = 0;
    while(demand || roundagain) {
        usingthisdisk = true;
	roundagain = false;
        out_fd = opendisk(O_WRONLY);
        blocksize = sectorsize(out_fd);
	chunksize = (CHUNKSIZE / blocksize) * blocksize;
        if (buffersize < chunksize) {
           buffersize = chunksize;
           buffer = alloca(buffersize);
	}
        while(usingthisdisk) {
	    if (buffer_count == 0) {
	        buffer_posn = buffer;
	    	do {
	    	    in_count = read(in_fd,buffer_posn,chunksize);
		    buffer_posn += in_count;
		    buffer_count += in_count;
		} while((buffer_count % blocksize) && (in_count > 0));
		if (in_count < 0)
		    suicide(4,"Unexpected error reading stdin");
		else if (in_count == 0) {
		    if (buffer_count % blocksize)
		        buffer_count = (buffer_count / blocksize + 1) * blocksize;
		    usingthisdisk = false;
		    demand = false;
		}
		buffer_posn = buffer;
	    }
	    if (buffer_count > 0) {
	        out_count = write(out_fd,buffer_posn,buffer_count);
	        if (out_count < 0) 
	            suicide(2,"Unexpected error writing to disk");
	        else if (out_count == 0) {
	            usingthisdisk = false;
		    roundagain = true;
	        }
	        else {
	            buffer_posn += out_count;
		    buffer_count -= out_count;
	        }
	    }
	}
	closedisk(out_fd);
    }
}

void interupt()
{
    suicide(2,"Transfer aborted by user");
}

main (argc, argv)
    int argc;
    char * argv[];
{
    int opt;
    bool opterr = false;
    extern int optind;
    extern char *optarg;
    enum {Read, Write, Undefined} operation = Undefined;

    int disk_fd;
    struct drive_info drive_info;

    signal(SIGPIPE, SIG_IGN);
    signal(SIGINT, interupt);
    while ((opt = getopt(argc, argv, "rw")) != EOF)
        switch (opt) {
	    case 'r':
	        if (operation == Undefined)
		    operation = Read;
		else
		    opterr = true;
		break;
	    case 'w':
	        if (operation == Undefined)
		    operation = Write;
		else
		    opterr = true;
		break;
	    case '?':
	    default:
	    	opterr = true;
		break;
	}
    if (opterr || (operation == Undefined)) {
        fprintf(stderr,"Usage:\t%s -r\n\t%s -w\n",argv[0],argv[0]);
        exit(1);
    }
    switch(operation) {
        case Read:
	    readdisk();
	    break;
	case Write:
	    writedisk();
	    break;
    }
}
    

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.