
==========
amiga/programs #367, from talin, 9715 chars, Sun Feb  7 07:56:54 1988
Comment to 366. 
----------
/***********************************************************************
 * bootback.c - copies boot blocks to file, or files to boot blocks    *
 * By Talin, otherwise known as David Joiner                           *
 * Note comments are only mostly serious                               *
 ***********************************************************************/
/* compiled like this:
    cc +l bootback
    ln bootback.o -lc32
*/

#include "exec/types.h"
#include "exec/memory.h"
#include "libraries/dosextens.h"        /* my DOS is bigger than your DOS */
#include "libraries/filehandler.h"
#include "devices/trackdisk.h"          /* But does it make a good frisbee? */

#include "arp/arpbase.h"
#include "arp/arpfunctions.h"

#define SCAT            goto exit_pgm
#define MAX_FILENAME    32

struct ArpBase          *ArpBase;       /* Mama! */
void                    *OpenLibrary(), /* Daddy! */
                        *AllocMem();    /* Cheetah! */

/* This is the stuff mother never told you about */

struct DevEnviron {
    ULONG   TableSize, SizeBlock, SecOrg, NumHeads,
            SecsPerBlock, BlocksPerTrack, ReservedBlocks, Preface,
            Interleave, LowCylinder, UpperCylinder, NumBuffers,
            MemBufType;
} *environ;

ULONG       blocksize;

struct MsgPort *diskport, *CreatePort();
struct IOExtTD *diskreq, *CreateExtIO();

#define ADDR(a) (void *)( (int)a << 2)  /* I don't like the standard macro */

/*      This is a rather EVIL way to do this, but I can think of nothing
    else that will work in a reasonable fashion.
        Essentially what this does is take a name of a device or volume
    and returns the DeviceNode entry for that device, buy brute force
    searching through the AmigaDOS device list. For a volume, the
    search has to be done twice, and is rather kludgey.
        Works like a charm. I wish it worked like software instead.
        Once this is done, the caller can easily determine the device
    driver name for exec-level IO. (see main below).
*/

struct DeviceNode *get_device(name) char *name;
{   struct DeviceNode   *dlist = NULL;
    char                device_name[MAX_FILENAME+2];
    short               length;

    while (dlist = (struct DeviceNode *)GetDevInfo(dlist))
    {   length = BtoCStr(device_name,dlist->dn_Name,33);
        device_name[length++] = ':';    /* Appendix a Colon on the end */
        device_name[length] = '\0';     /* and that other thing */

            /* try to find a match with name */
        if (Strcmp(name,device_name)==0)
        {   if (dlist->dn_Type == DLT_DEVICE) return dlist;
            if (dlist->dn_Type == DLT_VOLUME)
            {   struct Task *dev_task;
                char *task_name, *colon_name;
                struct MsgPort *proc;       /* actually a Process, but those */
                                            /* makes no sense anyway */
                proc = (struct MsgPort *)dlist->dn_Task;
                    /* Oooh, I remembered 'mp_SigTask' without looking it
                        up...that's Scary. */

                dev_task = proc->mp_SigTask;    /* not very kosher */
                colon_name = device_name;       /* copy device name to here */
                task_name = dev_task->tc_Node.ln_Name;  /* BAD Talin! BAD! */
                while (*task_name) *colon_name++ = *task_name++;    /* copy */
                *colon_name++ = ':';            /* put a colon on it, bud. */
                *colon_name++ = '\0';           /* and stop it from bleeding */
                return get_device(device_name); /* recursive but only once */
            }
            return NULL;                        /* return NULL for assigns: */
        }
    }
    return NULL;                                /* Negative, Will Robinson */
}

extern struct WBStartup *WBenchMsg;

wb_parse();										/* stub */

main(argc, argv) LONG argc; UBYTE **argv;
{   char                        driver_name[MAX_FILENAME+2];
    ULONG                       error,          /* open device error */
                                arg_device,     /* which arg was the device */
                                arg_file;       /* and which was the file? */
    struct FileSysStartupMsg    *fssm;          /* filesys startup message */
    struct DeviceNode           *d1,            /* Device node entries for */
                                *d2,            /*    arg1, arg2 and       */
                                *dvc;           /*    whichever one we open */
    struct FILE                 *save_file=NULL, *Open();
    APTR                        buff=NULL;      /* buffer for loaded blocks */
    UBYTE                       device_open=0;  /* flag is device was open */

    diskport = NULL; diskreq = NULL;

    if (WBenchMsg) exit(0);                     /* HELL NO, WE WON'T GO! */

    if (!(ArpBase = OpenLibrary("arp.library",0)))  /* open up there, arp! */
    {   Write(Output(),"Can't find arp.library\n",23);  /* You Varmit! */
        exit(20);
    }

    if (argc != 3)          /* check to make sure correct # of arguments */
    {   Printf("BootBack - Saves and restores custom boot blocks\n");
        Printf("Usage:\n\n");
        Printf("To save boot block:      BootBack <device> <file>\n");
        Printf("To restore boot block:   BootBack <file> <device>\n");
        SCAT;                               /* Take a powder */
    }

    d1 = get_device(argv[1]);
    d2 = get_device(argv[2]);

    if (d1 && d2) { Printf("They can't BOTH be devices!\n"); SCAT; }
    if (!d1 && !d2) { Printf("Neither of those is a device, silly!\n"); SCAT; }

    if (d1) { dvc = d1; arg_device = 1; arg_file = 2; }
    if (d2) { dvc = d2; arg_device = 2; arg_file = 1; }

    fssm = ADDR(dvc->dn_Startup);
    if (!fssm)
	{ Printf("Can't find device driver for <%s>.\n",argv[arg_device]); SCAT; }

    BtoCStr(driver_name,fssm->fssm_Device,33);
    environ = ADDR(fssm->fssm_Environ);
    blocksize = environ->SizeBlock * sizeof (LONG);     /* BCPL foolishness */

    if (arg_file == 1) save_file = Open(argv[arg_file],MODE_OLDFILE);
    else save_file = Open(argv[arg_file],MODE_NEWFILE);

    if (!save_file)
    {   Printf("Can't open save file <%s>.\n",argv[arg_file]); SCAT; }

        /* Ah pity the foo don't have enough memory to run this program! */
    buff = AllocMem(2 * blocksize,MEMF_CHIP);
    if (!buff) { Printf("Not enough memory.\n"); SCAT; }    /* TILT! */

    if (!(diskport = CreatePort(0,0)) ||
        !(diskreq = CreateExtIO(diskport,sizeof (struct IOExtTD))) ||
        (error = OpenDevice(driver_name,fssm->fssm_Unit,
							diskreq,fssm->fssm_Flags)) )
    {   Printf("Problems opening disk device...!\n");
        if (error) Printf("Error = %d.\n",error);
        SCAT;                               /* get outta here, ya nut! */
    }
    device_open = TRUE;
    Printf("%s opened.\n",driver_name);     /* chatty but educational */

    if (arg_file == 2)                      /* if filename was 2nd arg */
    {   if (load_track_range(0,2,buff))     /* 2 lumps please */
        {   Printf("Problem reading device...\n"); SCAT; }  /* TOAST */
        Write(save_file,"BOOTBLOC",8);      /* id check for safety's sake */
        Write(save_file,buff,2*blocksize);  /* Doit Toit */
    }
    else
    {   char file_id[9];                    /* id string */
        Read(save_file,file_id,8);          /* read id */
        file_id[8] = 0;                     /* null terminate */
        if (Strcmp(file_id,"BOOTBLOC"))
        {   Printf("This file is NOT a saved boot block!\n"); SCAT; }
        Read(save_file,buff,2 * blocksize);
        if (save_track_range(0,2,buff))     /* Thou art Healed! A Miracle! */
        {   Printf("Problem writing device...\n"); SCAT; }  /* Well, Almost */
    }

	Printf("Done!\n");
exit_pgm:
    if (device_open) { motor_off(); CloseDevice(diskreq); }
    if (diskreq) DeleteExtIO(diskreq,sizeof (struct IOExtTD));
    if (diskport) DeletePort(diskport);
    if (buff) FreeMem(buff,2 * blocksize);
    if (save_file) Close(save_file);
    if (ArpBase) CloseLibrary(ArpBase);
}

save_track_range(first_block,block_count,buffer)
    short first_block, block_count; char *buffer;
{   diskreq->iotd_Req.io_Length = (block_count * blocksize);
    diskreq->iotd_Req.io_Data = (APTR)buffer;
    diskreq->iotd_Req.io_Command = CMD_WRITE;
    diskreq->iotd_Req.io_Offset = (first_block * blocksize);
    DoIO(diskreq);
    return diskreq->iotd_Req.io_Error;
}

load_track_range(first_block,block_count,buffer)
    short first_block, block_count; char *buffer;
{   diskreq->iotd_Req.io_Length = (block_count * blocksize);
    diskreq->iotd_Req.io_Data = (APTR)buffer;
    diskreq->iotd_Req.io_Command = CMD_READ;
    diskreq->iotd_Req.io_Offset = (first_block * blocksize);
    DoIO(diskreq);
    return diskreq->iotd_Req.io_Error;
}

motor_off()
{   diskreq->iotd_Req.io_Length = 0;
    diskreq->iotd_Req.io_Command = TD_MOTOR;
    DoIO(diskreq);
}

#asm
            cseg
            include "arp/arpbase.i"

            public  _ArpBase

            public  _Printf
_Printf     move.l  4(sp),a0
            lea     8(sp),a1
            move.l  _ArpBase,a6
            jmp     _LVOPrintf(a6)

            public  _Strcmp
_Strcmp     move.l  4(sp),a0
            move.l  8(sp),a1
            move.l  _ArpBase,a6
            jmp     _LVOStrcmp(a6)

            public  _GetDevInfo
_GetDevInfo move.l  4(sp),a2
            move.l  _ArpBase,a6
            jmp     _LVOGetDevInfo(a6)

            public  _BtoCStr
_BtoCStr    move.l  4(sp),a0
            move.l  8(sp),d0
            move.l  12(sp),d1
            move.l  _ArpBase,a6
            jmp     _LVOBtoCStr(a6)

#endasm

/* That's all, folks! */
