(c)  Copyright 1989 Commodore-Amiga, Inc.   All rights reserved.
The information contained herein is subject to change without notice, and 
is provided "as is" without warranty of any kind, either expressed or implied.  
The entire risk as to the use of this information is assumed by the user.

                           Setting Up Your Hard Disk
                              for WorkBench V1.3
                                   Part II

                               by Bill Koester


Part I of this article dealt with the physical details of setting up a hard 
drive and the related system software.  This article covers how to install 
your application software for the best results. 
 
If you followed the guidelines in Part I, you now have a hard disk divided 
into two partitions, dh0: and fh0:.  The fh0: partition should have all the 
system software on it but ONLY ONE user directory, namely fh0:user.  The idea 
is to isolate system software from application software in order to make 
upgrades, backups and file recovery as simple as possible.  Use the standard 
startup sequences on fh0:, but make the following two changes.  First, add
these lines to fh0:s/startup-sequence just before the loadwb command:

      IF EXISTS SYS:user/user.startup-sequence
         execute sys:user/user.startup-sequence
      ENDIF

Second, add these lines to fh0:s/shell-startup:

      IF EXISTS SYS:user/user.shell-startup
         execute sys:user/user.shell-startup
      ENDIF


With this arrangement, all application files are isolated in the SYS:user
directory.  Any additions to the startup-sequence or shell-startup files 
neccessary for a particular application can be made in the user versions
(SYS:user/user.startup-sequence and SYS:user/user.shell-startup) since 
they will now be executed automatically by the main startups.

Keeping user software isolated in its own directory makes it easier to back 
up and easier to restore.  If you make regular backups of the SYS:user 
directory you can feel confident of your ability to reformat and properly 
restore the system - simply reinstall the system (as in Part I of this 
article) and then copy the files from your backup to the SYS:user 
directory.

For more security, you could make two partitions - one for system files and 
the other for user files - then use the V1.3 Lock command to protect the 
system directories from over-writing.  That way you can be sure you will not 
change them.


Applications

Separating system files from user files makes it easier to manage your hard 
disk.  It is also easier if you keep the user files separate from each other.
Many applications need assignments or paths for their directories.  These are 
usually made in the main startup file but this makes moving or deleting an 
application difficult once it has been installed. 

For instance, suppose you have several applications that need special assigns.
You could put these assigns in the user.startup-sequence, but if you do it this
way, as you add applications, the user.startup-sequence could become too large 
to easily edit or understand.  If you decide to move or delete a directory 
with paths or assigns to it, you will first have to remove all references to 
that directory from the user.startup-sequence, reboot the machine and then 
remove the directory.

A much better way is for the applications to do their own startups.  That way,
the special assigns and paths that an application needs can be stored with 
the application itself instead of in some generic, catch-all startup-sequence 
in some other directory.



The Config Program

This is the purpose of the utility program Config.  With Config you can create
a master startup-sequence which will call a local startup for each application 
in turn.  Config will automatically write the master startup script for you.
The command format for Config is:

      Config Directory OutFile SearchName
 
Config will search a given directory and all its sub-directories for files with
the given name.  Each time it finds a match, Config will write these two lines 
to a separate file you specify:

   cd Device:Dir/Dir/Dir
   execute Device:Dir/Dir/Dir/Filename

The first line is a CD to the directory where the file was found.  The second 
line executes the file as a script while CD'ed to its directory.  Adding these 
two lines to a script will cause it to pass control to another script and then
return when that script is done.  For instance assume the following directory 
structure on fh0:

                   SYS:user(dir)
                   /           \
                  /             \
           SuperPaint(dir)    SuperC(dir)
             .startup

The directory SYS:user contains two subdirectories. The subdirectory SuperPaint
contains the file .startup.  If you give the following Config command:

      Config SYS:user SYS:user/user.startup-sequence .startup

then Config will search all of SYS:user looking for files named .startup.  When
Config finds SYS:user/SuperPaint/.startup it will add these two lines to the 
SYS:user/user.startup-sequence file:

      cd SYS:user/SuperPaint
      execute SYS:user/SuperPaint/.startup

Now when the system boots, s:startup-sequence will call sys:user/user.startup-
sequence which will now call sys:user/SuperPaint/.startup and any other 
.startup files found in the sys:user directory.

You can use the same method to add a separate shell-startup script file, called
.shell, for each application with the following Config command:

      Config SYS:user SYS:user/user.shell-startup .shell

These two Config commands will take care of any set up needed for all
applications as long as they have local scripts called .startup and .shell.
For my system I made an IconX script so that these two lines execute from an 
icon on my hard drive.  This is convenient, as you will see, since you have to
reconfigure your system whenever you add or delete directories that had paths
or assigns to them.

Now let's consider the contents of the local .startup and .shell scripts. 
Config requires us to write position-indpendent scripts.  This means that any
.startup or .shell script should work regardless of its physical position in 
the file system.  Let's take SuperPaint as an example.

Suppose that SuperPaint needs the assignment SuperPaint: to function properly 
and that you would also like to add a path to its directory so you can execute 
it from the CLI.  You could use this script:

      assign SuperPaint: sys:user/superpaint
      path               sys:user/superpaint

However, this is not the best solution.  If you decide to move the SuperPaint 
directory to sys:user/Paint/SuperPaint, this script won't work anymore because 
the absolute paths are wrong.  However, if you write the script as:

      assign SuperPaint /SuperPaint         ;You could use "" instead of 
      path              /SuperPaint add     ;/SuperPaint to mean "right here"
      echo "SuperPaint"

then the script will work regardless of its position.   The echo command is 
used here to show what is being configured and in what order.  

The .shell files are similar to .startup files except that they get executed 
every time a new shell is opened.  I use .shell files to configure my source 
code directory.  For example, the .shell for my source directory is:

      alias ls dir
      alias mv rename
      stack 50000
      cd src:config

Each time I open a new shell, the above aliases are entered, my stack is set
to 50000 bytes and I wind up CD'ed to my working directory.  If I change 
projects, I can edit my .shell file to CD me to the right directory.

Using Config in this way, all information needed to set up an application is 
kept in the same directory as the application.  There is still one problem
with this scheme though - and that is how to handle paths to system directories
that may be needed.  Hopefully a future operating system release will allow
multiple paths for system directories, such as:

      assign fonts: sys:fonts                ;First path...
      assign fonts: sys:user/app1/fonts add  ;this command does not exist yet

You can begin to plan for this now.  For example, if an application needs 
fonts, you can modify the .startup file for the application by adding the 
following:

     IF NOT EXISTS fonts:my_app_font  ;Check if a local font has been copied
        copy fonts fonts:             ;if not, copy all fonts from here to the
     ENDIF                            ;main fonts: directory

If this is the .startup file for SuperPaint and the directory SuperPaint/fonts 
exists, then the above script fragment will copy the application-specific fonts
to the system's font directory  where they can be found by all.  The script 
will only copy the fonts if they have not already been copied .  This will
cut down on the user waiting time since these scripts are executed every time 
the system boots.


Maintenance

If you follow the arrangement above, then your system files are separated from
your applications in SYS:user.  Each application has its own sub-directory with
.startup and .shell files if needed.  You also have an IconX script which will 
create the master startup that calls on each application's local .startup file
in turn.  For system maintenance you should also make a IconX script that 
deletes the two files SYS:User/user.startup-sequence and SYS:User/user.shell-
startup.  Maintenance involves three basic operations: adding, deleting and 
moving applications.


Adding
  
To add a new application, make a directory for it in SYS:user or below.  Copy 
the application files to the new directory and create a .startup file if the 
application needs fonts, libs, assigns, paths or any other set-up that only 
needs doing once.  Next create a .shell file if one is needed (most software
can be configured without a .shell).  Now to install the application into the 
system simply click on the IconX script that makes the master startup.  The 
old user.startup-sequence and user.shell-startup will be overwritten with the 
new copy.


Deleting

Since it is not possible to delete a directory that has current assigns or 
paths associated with it, you must first remove the assigns and paths.  To do
this, click on the IconX script that deletes the SYS:User/user.startup-sequence
and SYS:User/user.shell-startup files.  Now reboot the Amiga.  Since the files
no longer exist, the assign and paths will not be set and you can delete the 
application with:

           delete sys:User/SuperPaint#? all quiet

After the desired applications have been removed click on the Config IconX 
script to reconfigure the applications that remain.   Now reboot and 
everything will be in order.

   
Moving

To move an application directory, follow the same rules as for deletion, but 
instead of deleting the directory after the first reboot, use rename to move 
it to another part of the same partition or use copy to move it to another 
drive (rename does not work across devices).  Then delete the old copy of the
application, reconfigure and reboot.

   
Editing

You can edit .startup and .shell files without reconfiguring.  But you will 
have to reboot to activate the changes you have made to a .startup.  For .shell
files, just close and reopen any shell windows and the changes will take effect.


As you can see the Amiga's user environment can be complicated.  I hope the
information given here takes some of the hassle out of setting up your hard 
drives.  By following the procedures here upgrades, backups and restoring 
files will be easier.  You can extend these procedures for more than one 
hard disk, or even to a network.



------------------------ Lauren, code starts here ---------------------


/*********************************************************************/
/*                                                                   */
/* Config.c - Hard Drive Configure Utility by Bill Koester (CATS)    */
/*                                                                   */
/*********************************************************************/

/* Runs from the CLI only */

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

int  gargc;
char *gargv2;
char *gargv3;

main(argc,argv)
int argc;
char *argv[];
{

   int      Error          = 0;
   struct   FileLock *lock = 0;
   struct   FILE     *fp   = 0;

   /*********************
    * Usage Information
    *********************/
   if(argc!=4) {
      printf("\nConfig Version 1.0 by Bill Koester (CATS)\n");
      printf("Usage:\n");

      /*             argv[0]   [1]      [2]       [3]    */
      printf("       Config Directory OutFile SearchName\n\n");
      Error=5;
      goto Cleanup;
   }

   /******************************
    * Initialize globals (yikes!)
    ******************************/
   gargc=argc;
   gargv2=argv[2];
   gargv3=argv[3];

   /*************************
    * Get lock on directory
    *************************/
   if((lock=(struct FileLock *)Lock(argv[1],ACCESS_READ))==0)
   {
      printf("Could not get lock on %s\n",argv[1]);
      Error=5;
      goto Cleanup;
   }

   /*************************
    * Open output file
    *************************/
   if((fp=(struct FILE *)fopen(argv[2],"w+"))==0)
   {
      printf("Could not open file %s\n",argv[2]);
      Error=5;
      goto Cleanup;
   }

   /***************************************************
    * Recursive routine to do this dir and all subdirs
    ***************************************************/
   DoDir(lock,fp);

Cleanup:
   if(lock) UnLock((BPTR)lock);
   if(fp) fclose(fp);

   return(Error);
}
/***********************************************************************
 *
 * DoDir(lock,fp)
 *
 * Starting at the 'lock'ed directory search all subdirectorys
 * for files with the name pointed to by gargv3. for each file found
 * write to the file whose name is pointed to by gargv2.
 *
 ***********************************************************************/
DoDir(lock,fp)
struct FileLock *lock;
struct FILE     *fp;
{
   struct FileInfoBlock *FIB;
   struct FileLock      *OldLock;
   struct FileLock      *TempLock;
   int    Error =0;


   OldLock=(struct FileLock *)CurrentDir((BPTR)lock);

   /**************************
    * Allocate a FileInfoBlock
    **************************/
   if((FIB=(struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),0))==0)
   {
      printf("Could not allocate memory for FIB\n");
      Error=5;
      goto Cleanup;
   }

   /*******************
    * Set up for ExNext
    *******************/
   if(Examine((BPTR)lock,FIB)==0)
   {
      printf("Examine failed\n");
      Error=5;
      goto Cleanup;
   }

more:
   /*********************************************
    * If no more entries in this branch then exit
    *********************************************/
   if((ExNext((BPTR)lock,FIB)==0)&&(IoErr()==ERROR_NO_MORE_ENTRIES))
      goto exit;

   /**********************
    * Is this a directory?
    **********************/
   if(FIB->fib_DirEntryType>0)
   {
      /**************************
       * Yes, get lock on new dir
       **************************/
      if((TempLock=(struct FileLock *)Lock(FIB->fib_FileName,ACCESS_READ))==0)
      {
         printf("DoDir could not get a lock!\n");
      }
      else
      {
         /*****************************************************
          * Call DoDir recursively to process the new directory
          *****************************************************/
         DoDir(TempLock,fp);
         UnLock((BPTR)TempLock);
      }
   }
   else
   {
      /***********************************
       * No, It's a file so check its name
       ***********************************/
      if(stricmp(gargv3,FIB->fib_FileName)==0)
      {
         /**********************************************
          * We have a match so write an entry to OutFile
          **********************************************/
         fprintf(fp,"cd ");
         PrintCurrentDir(lock,fp);
         fseek(fp,-1L,1);           /* Remove trailing backslash */
         fprintf(fp,"\n");

         fprintf(fp,"execute ");
         PrintCurrentDir(lock,fp);
         fprintf(fp,gargv3);
         fprintf(fp,"\n");
      }
   }
   goto more;

exit:

Cleanup:
   CurrentDir((BPTR)OldLock);
   if(FIB) FreeMem((char *)FIB,sizeof(struct FileInfoBlock));
   return(Error);
}

/************************************************************************
 *
 * PrintCurrentDir(lock,fp);
 *
 * Prints to the file  fp the full path name for the entity associated with
 * 'lock'. This function is also recursive.
 ************************************************************************/
PrintCurrentDir(lock,fp)
struct FileLock *lock;
struct FILE     *fp;
{
   struct FileLock *parent;
   struct FileInfoBlock *FIB;

   /************************
    * Allocate FileInfoBlock
    ************************/
   if((FIB=(struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),0))==0)
   {
      printf("PrintCurrentDir could not allocate memory for FIB!\n");
      goto Cleanup;
   }

   /**************************************************************
    * If there is no parent for this lock then we have the volume
    * and our base case.
    **************************************************************/
   if((parent=(struct FileLock *)ParentDir((BPTR)lock))==0)
   {
      /*******************
       * Print volume name
       *******************/
      Examine((BPTR)lock,FIB);
      fprintf(fp,"%s:",FIB->fib_FileName);
      goto Cleanup;
   }
   /**************************************************
    * Recursively print the parent of the current lock
    **************************************************/
   PrintCurrentDir(parent,fp);
   UnLock((BPTR)parent);

   /*****************************************
    * Then tack the current lock onto the end
    *****************************************/
   Examine((BPTR)lock,FIB);
   fprintf(fp,"%s/",FIB->fib_FileName);

Cleanup:
   if(FIB) FreeMem((char *)FIB,sizeof(struct FileInfoBlock));
   return(0);
}

