Utilities 3 (Disk 38) (Mar 1987) : c / defdisk.c

/*
 * DEFDISK.C
 *
 * A program to make a specified disk/directory the default system disk.
 * It accomplishes this by resetting the DOS library structures to point
 * to the new path. To use this program you will need to compile it as
 * follows:
 *		1> cc defdisk
 *		1> ln defdisk.o -lc
 *
 * Real simple.  I used AZTEC C v3.40a, but I think that 3.30c or later would
 * also work.  It should be possible to compile & build it under LATTICE as
 * well, though I haven't tried.  Once the program is built, put it on your
 * Workbench boot disk somewhere, load up your ram: disk or hard disk and
 *
 *		1> defdisk dh0:
 *		      or
 *		1> defdisk dh0:bin
 *
 * Woila! the standard workbench assignments are now pointed at the hard
 * disk. (SYS, C, L, DEVS, LIBS, FONTS)  The advantage to me in using this
 * is that I don't have to load the Amiga DOS assign program 6 times to
 * point the system at the hard disk.
 *
 * Author: J. K. Levie
 *
 * Version 1.0 31-Mar-1987
 */

#include <stdio.h>
#include <functions.h>
#include <exec/types.h>
#include <exec/exec.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>

extern void BtoCSTR();			/* forward ... */
extern void CtoBSTR();			/* ... references */

struct DevInfo
{
   BPTR di_Next;
   LONG di_Type;
   APTR di_Task;
   BPTR di_Lock;
   BSTR di_Handler;
   LONG di_StackSize;
   LONG di_Priority;
   LONG di_Startup;
   BPTR di_SegList;
   BPTR di_GlobVec;
   BSTR di_Name;
};
struct DosLibrary *dosBase;
struct RootNode *root;
struct DosInfo *info;
struct DevInfo *dev_head, *dev_ele;
struct Lock *lock;

/*
 * Define the logical to physical table.
 */
struct ASSIGNS
{
   char *log_name;			/* logical name to look for */
   char *phy_name;			/* physical name to assign */
   short success;			/* result 0=> failure, 1=> success */
};
struct ASSIGNS assigns[]=
{
   "SYS",   NULL,    0,
   "C",     "c",     0,
   "DEVS",  "devs",  0,
   "LIBS",  "libs",  0,
   "L",     "l",     0,
   "S",     "s",     0,
   "FONTS", "fonts", 0,
   NULL,    NULL
};




main(argc, argv)
int argc;
char *argv[];
{
   char *ptr, *path;
   register int len, n;

   /*
    * See if we can get a lock on the new C directory, if we can't
    * we won't even attempt to do the assigns.
    */
   path=argv[1];
   if(argc!=2 || *path=='?')		/* correct arg cnt?  useage? */
   {
      printf("Usage: defdisk dev:[dir.../dir]\n");
      exit(20);
   }
   /*
    * Now we are ready to fill in the logical name table.  Handle the 
    * Sys logical first since it will not have anything appended.  Then
    * see if we will need to append a path separator to the user
    * specified path.  We stop appending when we see the "T" logical.
    */
   assigns[0].phy_name=path;		/* Sys is special case */
   len=1+strlen(path);			/* find length of physical name */
   if(path[strlen(path)-1]!=':')	/* path specify the root of volume? */
   {
      len++;				/* room for path separator */
      ptr=AllocMem((long)(len+1), MEMF_PUBLIC);
      strcpy(ptr, path);		/* put user specified path in ... */
      strcat(ptr, "/");			/* ... and path separator */
      path=ptr;				/* point to new path */
   }
   /*
    * Now fill in the rest of the table.  Allocate memory for the
    * complete physical name and the directory specified in the table
    * entry.  Then concatenate the path and the directory and set up
    * the new pointer.
    */
   for(n=1; assigns[n].log_name[0]!=NULL; n++)
   {
      ptr=AllocMem((long)(len+strlen(assigns[n].log_name)), MEMF_PUBLIC);
      strcpy(ptr, path);
      strcat(ptr, assigns[n].phy_name);
      assigns[n].phy_name=ptr;
   }
   /*
    * Convert the logical names to B strings.
    */
   for(n=0; assigns[n].log_name!=NULL; n++) CtoBSTR(assigns[n].log_name);

   /*
    * Now for a little paranoia.  I don't want to point the system
    * somewhere that doesn't contain a C directory.
    */
   lock=Lock(assigns[1].phy_name, SHARED_LOCK);
   if(lock==NULL)			/* are we sane? */
   {
      /*
       * NO!  Makes no sense to set the system volume to something that
       * doesn't contain a c directory.
       */
      printf("defdisk-F-%s does not contain a C directory\n",
              assigns[1].phy_name);
      exit(20);
   }
   UnLock(lock);			/* Okay unlock the c directory */

   /*
    * Now open the resources we will need.
    */
   dosBase=(struct DosLibrary *)OpenLibrary(DOSNAME);
   root=(struct RootNode *)dosBase->dl_Root;
   info=(struct DosInfo *)BADDR(root->rn_Info);
   dev_head=(struct DevInfo *)BADDR(info->di_DevInfo);

   Forbid();				/* only us & nobody else */
   /*
    * Walk the DevInfo list looking for the locigal names to change.  For
    * each entry in the list we can check each of the entries in the
    * logical name table.  As we find them reset each logical to point
    * to the new system volume.
    */
   for(dev_ele=dev_head; dev_ele->di_Next;
       dev_ele=(struct DevInfo *)BADDR(dev_ele->di_Next))
   {
      /*
       * Check against each of the logical names in the table.
       */
      for(n=0; assigns[n].log_name!=NULL; n++)
      {
         /*
          * See if this one matches.
          */
         if(Bstrcmp(BADDR(dev_ele->di_Name), assigns[n].log_name))
         {
            /*
             * Name matches, is it the correct type?
             */
            if(dev_ele->di_Type!=DLT_DIRECTORY)
            {
               /*
                * No put logical name back to a C string and error out.
                */
               BtoCSTR(assigns[n].log_name);
               printf("defdisk-F-cannot reassign %s\n", assigns[n].log_name);
               goto done;
            }
            /*
             * Okay get a lock on the physical name for this logical.
             */
            lock=Lock(assigns[n].phy_name, SHARED_LOCK);
            if(!lock)
            {
               /*
                * Whoops, failed somehow, tell the world about it.
                */
               printf("defdisk-F-cannot get a lock on %s\n", assigns[n].phy_name);
               goto done;
            }
            /*
             * Time to clean up the old logical and point it to our
             * physical name.
             */
            UnLock(dev_ele->di_Lock);
            dev_ele->di_Lock=(BPTR)lock;
            dev_ele->di_Task=(APTR)(DeviceProc(assigns[n].phy_name));
            assigns[n].success=1;	/* flag that we did this one */
         }
      }
   }
done:
   Permit();				/* release the system */
   CloseLibrary(dosBase);		/* clean up */
   
   /*
    * Now check to see that all of the assignments were made.
    */
   for(n=0; assigns[n].log_name!=NULL; n++)
   {
      if(assigns[n].success!=1) printf("defdisk-F-assignments failed\n");
   }
}



/*
 * Bstrcmp(a, b)
 *
 * Compare two btrings for equality, case insensitive.
 */
Bstrcmp(a, b)
char *a, *b;
{
   int len=(int)*a;			/* first char of B string is length */

   for(len++; len!=0; len--)		/* compare at most all */
   {
      if((*a&~0x20)!=(*b&~0x20)) return(0); /* quit if not equal */
      a++;				/* point both ... */
      b++;				/* ... at next character */
   }
   return(1);				/* they matched */
}



/*
 * BtoCSTR(bstr)
 *
 * Convert (in place) a B string to a C string.
 */
void BtoCSTR(bstr)
char *bstr;
{
   register int i;
   register UBYTE *bptr, *cptr;

   cptr=(UBYTE *)bstr;			/* point to input B string */
   bptr=cptr;				/* output starts at B string len spot */
   for(i=*bptr++; i!=0; i--) *cptr++=*bptr++; /* left shift the string */
   *cptr='\0';				/* terminate it */
}



/*
 * CtoBSTR(cstr)
 *
 * Convert (in place) a C string to a B string.
 */
void CtoBSTR(cstr)
char *cstr;
{
   register int i, len;
   register UBYTE *cptr, *bptr;

   cptr=(UBYTE *)cstr;			/* pointer to input */
   for(i=0; *cptr; i++, cptr++);	/* count & push pointer to input */
   len=i;				/* save count */
   bptr=cptr;				/* point at end of input */
   cptr--;				/* back up over null */
   while(i--) *bptr--=*cptr--;		/* right the string */
   *bptr=(UBYTE)len;			/* stuff in the string length */
}