1 Introduction
2 Ground Rules

Building a File System
3 File Systems
4 File Content Data Structure
5 Allocation Cluster Manager
6 Exceptions and Emancipation
7 Base Classes, Testing, and More
8 File Meta Data
9 Native File Class
10 Our File System
11 Allocation Table
12 File System Support Code
13 Initializing the File System
14 Contiguous Files
15 Rebuilding the File System
16 Native File System Support Methods
17 Lookups, Wildcards, and Unicode, Oh My
18 Finishing the File System Class

The Init Program
19 Hardware Abstraction and UOS Architecture
20 Init Command Mode
21 Using Our File System
22 Hardware and Device Lists
23 Fun with Stores: Partitions
24 Fun with Stores: RAID
25 Fun with Stores: RAM Disks
26 Init wrap-up

The Executive
27 Overview of The Executive
28 Starting the Kernel
29 The Kernel
30 Making a Store Bootable
31 The MMC
32 The HMC
33 Loading the components
34 Using the File Processor
35 Symbols and the SSC
36 The File Processor and Device Management
37 The File Processor and File System Management
38 Finishing Executive Startup

Users and Security
39 Introduction to Users and Security
40 More Fun With Stores: File Heaps
41 File Heaps, part 2
42 SysUAF
43 TUser
44 SysUAF API

UCL
45 Shells and UCL

Glossary/Index


Download sources
Download binaries

Finishing Executive Startup

At this point, the executive is set up and ready for action. Our final task is to start the system startup process. As discussed in past articles, UOS startup occurs in two phases. The first is the executive startup, embodied in the TKernel.Startup method. The second is the system startup.

    // Create a process...
    PID := USC.Create_Process( 0 ) ;
    if( PID = 0 ) then
    begin
        Output( 'Could not create startup process' ) ;
        H.Halt ;
    end ;
    FiP.Attach_Device( '_TERMA0:', PID ) ;
    if( USC.Force_Login( PID, 1 ) ) then // Log us in as Startup
    begin
        if( H.Console <> nil ) then
        begin
            H.Console.Output( PChar( USC.Last_Error.Error_Text( _S, _T ) + CRLF ), -1 ) ;
        end ;
        Output( 'Could not log in Startup' ) ;
        H.Halt ;
    end ;
    USC.Run( PID, 'sys$system:ucl.exe', 'sys$system:startup.ucl' ) ;
    Idle ;
end ; // TKernel.Startup

Outside of the executive, all system activity occurs within the context of processes, so we create a process for the system startup. We will discuss processes in detail in a future article. For now, all you need to know is that each process has a numeric identifier called the process ID (or PID). The USC.Create_Process method returns the ID of the newly created process which we store in the PID variable. Note that all process IDs must be greater than zero. So, if we get a 0 back from Create_Process, it means that the process creation failed and we show the error and halt.
Next we attach the process to the system console (_TERMA0:). This is also something we will discuss later. For now, just understand that attaching a device associates it with a process. This is necessary since there may be multiple terminals on a system, so the process needs to know which one it will interact with.
The next step is to login the process as the Startup user (user ID 1). The USC.Force_Login method does the login without requiring a password (or any other interaction with the console). If the method returns true, there was a login failure and so we display the error and halt. Discussion of logging in will require an article of its own, so we won't go into any more detail here.
Once we have a logged-in process, we run the default shell, telling it to run the startup.ucl command file. The UOS Command Language (UCL) is the default shell and the one we use to run system startup. In point of fact, the USC.Run method doesn't actually start running any programs - it merely schedules them to run. We will cover this process in detail when we discuss multi-tasking in a future article.
The final act of the kernel Startup method is to call the Idle method. Control never returns from that method.

Here is the Idle method:

procedure TKernel.Idle ;

begin
    while( True ) do
    begin
        if( not Schedule_Task ) then
        begin
            HAL.Idle ;
        end ;
    end ;
end ;

The Idle method never exits - it is an infinite loop. Within this loop, it calls the Schedule_Task method, which decides what task to execute next. If it returns false, there is nothing to run at present and the HAL's Idle method is called. What does HAL.Idle do? That depends on the hardware, of course. It may poll devices, put the hardware into a low-power mode, or do nothing at all. On the venerable RSTS/E operating system, an idle machine was denoted by a rotating pattern of lights on the front panel. If the HAL were running on a PDP-11 computer, it might do something similar. UOS doesn't need to care what HAL.Idle does, it simply has to make sure to call it when the system is idle. As mentioned above, we will discuss the scheduling of tasks in a future article.

Revisting Init
Before we end this set of articles, let us examine the facility provided by Init to manage multiple UOS installations. As we mentioned in an earlier article, there can be multiple installations of UOS existing on a store. One is considered the default version, which is what is started unless overriden by the user. Whichever one is started, whether default or not, is considered the "installed" version for that run of UOS. The "UOS" command in Init is what we use to manage all of the versions of UOS.

if( Match( 'UOS', S, 1 ) ) then
begin
    UOS_Defaults( S1 ) ;
end else

The above code is added to the Command_Mode function in Init. And the following line is added to the paragraph of code for the HELP command:
Output_Line( 'UOS - Manage UOS defaults and setups' ) ;

Here is the UOS_Defaults routine:

function UOS_Defaults( S : string ) : boolean ;

var S1 : string ;
    Prompt : boolean ;

begin
    Result := False ;
    Prompt := S = '' ;
    while( True ) do
    begin
        if( Prompt ) then
        begin
            Output( 'UOS> ' ) ;
            S := Input( '' ) ;
        end ;
        case( Process_Input( S, S1 ) ) of
            1 : begin
                    Result := True ;
                    exit ;
                end ;
            2 : begin
                    exit ;
                end ;
        end ;
        if( ( S = '?' ) or Match( 'HELP', S, 1 ) ) then
        begin
            Output_Line( 'DEFAULT <disk> - Set default installation' ) ;
            Output_Line( 'HELP - Show this text' ) ;
            Output_Line( 'LIST <disk> - Show UOS installations' ) ;
            Output_Line( 'UNINSTALL <disk> - Remove installation' ) ;
        end else
        if( Match( 'DEFAULT', S, 1 ) ) then
        begin
            if( UOS_Default( S1 ) ) then
            begin
                exit ;
            end ;
        end else
        if( Match( 'LIST', S, 1 ) ) then
        begin
            if( UOS_List( S1 ) ) then
            begin
                exit ;
            end ;
        end else
        if( Match( 'UNINSTALL', S, 1 ) ) then
        begin
            if( UOS_Uninstall( S1 ) ) then
            begin
                exit ;
            end ;
        end else
        if( S <> '' ) then
        begin
            Output_Line( 'Invalid UOS command' ) ;
        end ;
        if( not Prompt ) then
        begin
            exit ;
        end ;
    end ; // while( True )
end ; // Init_UOS

This is a standard sub-command handling routine, like the others we've looked at in Init in past articles. Init supports three sub-commands of the UOS command.

The first UOS sub-command is the DEFAULT sub-command, which is used to set the default installation for a store.

function UOS_Default( S : string ) : boolean ;

var Store : TCOM_Store64 ;
    S1 : string ;
    Prompt : boolean ;

begin
    Result := False ;
    Prompt := S = '' ;
    while( True ) do
    begin
        if( Prompt ) then
        begin
            Output( 'UOS (DISKA0) > ' ) ;
            S := Input( 'DISKA0' ) ;
        end ;
        case( Process_Input( S, S1 ) ) of
            1 : begin
                    Result := True ;
                    exit ;
                end ;
            2 : begin
                    exit ;
                end ;
        end ;
        if( ( S = '?' ) or Match( 'HELP', S, 1 ) ) then
        begin
            Output_Line( '<name> - Name of installation to default to' ) ;
            Output_Line( 'HELP - Show this text' ) ;
            Output_Line( '' ) ;
        end else
        if( S <> '' ) then
        begin
            Store := Parse_Device( S ) ;
            if( Store = nil ) then
            begin
                Output_Line( 'Invalid device' ) ;
            end else
            if( not Valid_File_System( Store ) ) then
            begin
                Output_Line( 'Not a valid file system' ) ;
            end else
            if( Store.Read_Only ) then
            begin
                Output_Line( 'Store is read-only' ) ;
            end else
            if( UOS_Default_Store( S, S1, Store ) ) then
            begin
                exit ;
            end ;
        end ;
        if( not Prompt ) then
        begin
            exit ;
        end ;
    end ; // while( true )
end ; // UOS_Default

First we prompt for the disk, allowing the user to backup or exit. Then we check for a query for help. Finally, we validate the store, the file system on that store, and that the store is writeable. Finally, we call UOS_Default_Store to do the actual operation.

Here is the code for the UOS_Default_Store method:

function UOS_Default_Store( S, St : string ; Store : TCOM_Store64 ) : boolean ;

var Fil : TUOS_File ;
    FS : TUOS_Native_File_System ;
    Info : TUOS_File_Info ;
    MStore : TUOS_Managed_Store ;
    Prompt : boolean ;
    S1, S2 : string ;
    UE : TUnified_Exception ;

begin
    Result := True ;
    MStore := TUOS_Managed_Store.Create ;
    Store.Attach ;
    MStore.Store := Store ;
    FS := TUOS_Native_File_System.Create ;
    try
        // Mount the file system...
        FS.Store := MStore ;
        FS.Mount( '', '', 0 ) ;
        UE := FS.Last_Error ;
        if( UE <> nil ) then
        begin
            if( UE.Get_Error = UOS_File_System_Is_Dirty ) then
            begin
                Output_Line( 'Disk is dirty - rebuilding...' ) ;
                if( FS.Rebuild ) then
                begin
                    Output_Line( 'File system structure corruption found - run recovery process' ) ;
                    exit ;
                end ;
            end ;
            FS.Mount( '', '', 0 ) ;
        end ;
        UE := FS.Last_Error ;
        if( UE <> nil ) then
        begin
            Show_Error( FS.Last_Error ) ;
            Result := False ;
            exit ;
        end ;

        Prompt := S = '' ;
        while( True ) do
        begin
            if( Prompt ) then
            begin
                Output( 'UOS DEFAULT ' + St + '> ' ) ;
                S := Input( '' ) ;
            end ;
            case( Process_Input( S, S1 ) ) of
                1 : begin
                        Result := True ;
                        exit ;
                    end ;
                2 : begin
                        exit ;
                    end ;
            end ;
            if( ( S = '?' ) or Match( 'HELP', S, 1 ) ) then
            begin
                Output_Line( 'Enter installation directory name' ) ;
            end else
            if( S = '' ) then
            begin
                continue ;
            end ;

The first thing we do is mount the file system. If it is dirty, we rebuild it and try to remount. If it fails, we show the user and exit. Then we go into an input loop. We prompt the user, if the installation wasn't already provided.

            // Validate the specified installation directory...
            Info := FS.Get_File_Info( PChar( 'uos\' + S ), 0 ) ;
            if( ( FS.Last_Error <> nil ) or ( ( Info.Flags and FAF_DIRECTORY ) = 0 ) ) then
            begin
                Output( 'Installation not found' + CRLF ) ;
                Result := False ;
                if( Prompt ) then
                begin
                    continue ;
                end ;
                exit ;
            end ;

            // Create the default link...
            fillchar( Info, sizeof( Info ), 0 ) ;
            Info.Flags := FAF_LINK ;
            UE := FS.Create_File( '\uos\default.sys', Info ) ;
            if( UE <> nil ) then // Could not create default.sys
            begin
                Show_Error( UE ) ;
            end else
            begin
                Fil := FS.Get_File( '\uos\default.sys' ) ;
                try
                    S2 := '\uos\' + S ;
                    Fil.Write( 0, 0, length( S2 ), PChar( S2 )[ 0 ] ) ;
                    if( Fil.Last_Error <> nil ) then
                    begin
                        Show_Error( Fil.Last_Error ) ;
                    end ;
                finally
                    Fil.Detach ;
                end ;
            end ;
            if( not Prompt ) then
            begin
                exit ;
            end ;
        end ; // while( True )

    finally
        FS.Dismount ;
        FS.Free ;
        MStore.Free ;
    end ;
end ; // UOS_Default_Store

When the user supplies an installation (a directory), we verify that it exists. If not, we show an error. Otherwise, we write the new directory to the default.sys file. Since link files simply contain the target directory, this is all we need to do in order to create the link.

Here is the code for the UOS_List method:

function UOS_List( S : string ) : boolean ;

var Context : pointer ;
    Default, Installed : string ;
    Info : TUOS_File_Info ;
    Store : TCOM_Store64 ;
    S1 : string ;
    Prompt : boolean ;
    FS : TUOS_Native_File_System ;
    MStore : TUOS_Managed_Store ;
    UE : TUnified_Exception ;
    UF : TUOS_File ;

begin
    Result := False ;
    Prompt := S = '' ;
    while( True ) do
    begin
        if( Prompt ) then
        begin
            Output( 'UOS List (DISKA0) > ' ) ;
            S := Input( 'DISKA0' ) ;
        end ;
        case( Process_Input( S, S1 ) ) of
            1 : begin
                    Result := True ;
                    exit ;
                end ;
            2 : begin
                    exit ;
                end ;
        end ;
        if( ( S = '?' ) or Match( 'HELP', S, 1 ) ) then
        begin
            Output_Line( '<name> - Name of installation to remove' ) ;
            Output_Line( 'HELP - Show this text' ) ;
            Output_Line( '' ) ;
        end else
        if( S <> '' ) then
        begin
            Store := Parse_Device( S ) ;
            if( Store = nil ) then
            begin
                Output_Line( 'Invalid device' ) ;
            end else
            if( not Valid_File_System( Store ) ) then
            begin
                Output_Line( 'Not a valid file system' ) ;
            end else
            begin
                MStore := TUOS_Managed_Store.Create ;
                Store.Attach ;
                MStore.Store := Store ;
                FS := TUOS_Native_File_System.Create ;
                try
                    FS.Store := MStore ;
                    FS.Mount( '', '', 0 ) ;
                    UE := FS.Last_Error ;
                    if( UE <> nil ) then
                    begin
                        if( UE.Get_Error = UOS_File_System_Is_Dirty ) then
                        begin
                            Output_Line( 'Disk is dirty - rebuilding...' ) ;
                            if( FS.Rebuild ) then
                            begin
                                Output_Line( 'File system structure corruption found - run recovery process' ) ;
                                exit ;
                            end ;
                        end ;
                        FS.Mount( '', '', 0 ) ;
                    end ;

This method displays a list of UOS installations on a store. We prompt the user, as normal. When a store is provided, we validate the store, then mount the file system, and rebuild it if necessary. If there are any problems, we notify the user.

                    // Get installed and default UOS...
                    UF := FS.Get_File( '\uos\installed.sys' ) ;
                    if( UF <> nil ) then
                    begin
                        Info := FS.Get_File_Info( PChar( 'uos\installed.sys' ), 0 ) ;
                        setlength( Installed, Info.EOF ) ;
                        UF.Read( 0, 0, length( Installed ), PChar( Installed )[ 0 ] ) ;
                        UF.Free ;
                    end ;
                    Installed := lowercase( Installed ) ;
                    UF := FS.Get_File( '\uos\default.sys' ) ;
                    if( UF <> nil ) then
                    begin
                        Info := FS.Get_File_Info( PChar( 'uos\default.sys' ), 0 ) ;
                        setlength( Default, Info.EOF ) ;
                        UF.Read( 0, 0, length( Default ), PChar( Default )[ 0 ] ) ;
                        UF.Free ;
                    end ;
                    Default := lowercase( Default ) ;

                    // List installations...
                    Context := nil ;
                    S := FS.Lookup( PChar( 'uos\*.*' ), Context ) ;
                    try
                        while( Context <> nil ) do
                        begin
                            Info := FS.Get_File_Info( PChar( 'uos\' + S ), 0 ) ;
                            if( ( Info.Flags and FAF_DIRECTORY ) <> 0 ) then
                            begin
                                S1 := lowercase( S ) ;
                                while( length( S ) < 16 ) do
                                begin
                                    S := S + ' ' ;
                                end ;
                                Output( S + '    ' ) ;
                                S := Format_Sirius_Date( '', Info.Creation ) + ' ' +
                                    Format_Sirius_Time( 'HH:MM', Info.Creation ) ;
                                Output( S ) ;
                                if( '\uos\' + S1 = Default ) then
                                begin
                                    Output( '  Default' ) ;
                                end ;
                                if( '\uos\' + S1 = Installed ) then
                                begin
                                    Output( '  Installed' ) ;
                                end ;
                                Output( CRLF ) ;
                            end ;
                            S := FS.Lookup( '', Context ) ;
                        end ; // while( Context <> nil )
                    finally
                        FS.Clear_Context( Context ) ;
                    end ;
                finally
                    FS.Dismount ;
                    FS.Free ;
                    MStore.Free ;
                end ;
            end ;
        end ;
        if( not Prompt ) then
        begin
            exit ;
        end ;
    end ; // while( true )
end ; // UOS_List

Next we get the default and installed links (if they exist). Then we loop through the directories under the \uos directory. Each one is displayed, and if it matches either (or both) of the links, we display that next to the name. When done, we clean up the context, dismount the file system, and free the various objects.

Finally, we look at the UOS uninstall method. All that this routine needs to do is delete a given UOS installation directory and all of the files it contains.

function UOS_Uninstall( S : string ) : boolean ;

var Store : TCOM_Store64 ;
    S1 : string ;
    Prompt : boolean ;

begin
    Result := False ;
    Prompt := S = '' ;
    while( True ) do
    begin
        if( Prompt ) then
        begin
            Output( 'UOS (DISKA0) > ' ) ;
            S := Input( 'DISKA0' ) ;
        end ;
        case( Process_Input( S, S1 ) ) of
            1 : begin
                    Result := True ;
                    exit ;
                end ;
            2 : begin
                    exit ;
                end ;
        end ;
        if( ( S = '?' ) or Match( 'HELP', S, 1 ) ) then
        begin
            Output_Line( '<name> - Name of installation to remove' ) ;
            Output_Line( 'HELP - Show this text' ) ;
            Output_Line( '' ) ;
        end else
        if( S <> '' ) then
        begin
            Store := Parse_Device( S ) ;
            if( Store = nil ) then
            begin
                Output_Line( 'Invalid device' ) ;
            end else
            if( not Valid_File_System( Store ) ) then
            begin
                Output_Line( 'Not a valid file system' ) ;
            end else
            if( Store.Read_Only ) then
            begin
                Output_Line( 'Store is read-only' ) ;
            end else
            if( UOS_Uninstall_Store( S, S1, Store ) ) then
            begin
                exit ;
            end ;
        end ;
        if( not Prompt ) then
        begin
            exit ;
        end ;
    end ; // while( true )
end ; // UOS_Uninstall

This function simply prompts the user for which installation to uninstall, if the installation isn't already provided. It verifies that the file system is valid and not read-only. If everything passes muster, we call UOS_Uninstall_Store.

Here is the UOS_Uninstall_Store method. All that this routine needs to do is delete a given UOS installation directory and all of the files it contains.

function UOS_Uninstall_Store( S, S1 : string ; Store : TCOM_Store64 ) : boolean ;

var Context : pointer ;
    Default, Installed : string ;
    E : TUnified_Exception ;
    FS : TUOS_Native_File_System ;
    Info : TUOS_File_Info ;
    List : TStringList ;
    Loop : integer ;
    MStore : TUOS_Managed_Store ;
    Prompt : boolean ;
    S2 : string ;
    UE : TUnified_Exception ;
    UF : TUOS_File ;

begin
    Result := False ;
    Prompt := S1 = '' ;
    while( True ) do
    begin
        if( Prompt ) then
        begin
            Output( 'UOS Uninstall ' + S + ' > ' ) ;
            S1 := Input( '' ) ;
        end ;
        case( Process_Input( S1, S2 ) ) of
            1 : begin
                    Result := True ;
                    exit ;
                end ;
            2 : begin
                    exit ;
                end ;
        end ;
        if( S1 <> '' ) then
        begin
            Context := nil ;
            MStore := TUOS_Managed_Store.Create ;
            Store.Attach ;
            MStore.Store := Store ;
            FS := TUOS_Native_File_System.Create ;
            try
                FS.Store := MStore ;
                Info := FS.Get_File_Info( PChar( 'uos\' + S1 ), 0 ) ;
                if( ( FS.Last_Error <> nil ) or ( ( Info.Flags and FAF_DIRECTORY ) = 0 ) ) then
                begin
                    Output( 'Installation not found' + CRLF ) ;
                end else

First, we prompt for the UOS installation to uninstall, if one was not provided. We check to make sure that the directory exists and show an error if there is a problem.

                begin
                    List := TStringList.Create ;
                    FS.Mount( '', '', 0 ) ;
                    UE := FS.Last_Error ;
                    if( UE <> nil ) then
                    begin
                        if( UE.Get_Error = UOS_File_System_Is_Dirty ) then
                        begin
                            Output_Line( 'Disk is dirty - rebuilding...' ) ;
                            if( FS.Rebuild ) then
                            begin
                                Output_Line( 'File system structure corruption found - run recovery process' ) ;
                                exit ;
                            end ;
                        end ;
                        FS.Mount( '', '', 0 ) ;
                        UE := FS.Last_Error ;
                        if( UE <> nil ) then
                        begin
                            Show_Error( UE ) ;
                            if( not Prompt ) then
                            begin
                                exit ;
                            end ;
                            continue ;
                        end ;
                    end ;
                    S := FS.Lookup( PChar( 'uos\' + S1 + '\*.*' ), Context ) ;
                    while( Context <> nil ) do
                    begin
                        List.Add( S ) ;
                        S := FS.Lookup( '', Context ) ;
                    end ; // while( Context <> nil )
                    for Loop := 0 to List.Count - 1 do
                    begin
                        S := List[ Loop ] ;
                        E := FS.Delete_File( PChar( '\uos\' + S1 + '\' + S ) ) ;
                        if( Show_Error( E ) ) then
                        begin
                            break ;
                        end ;
                    end ;
                    E := FS.Delete_File( PChar( '\uos\' + S1 ) ) ;
                    Show_Error( E ) ;

Next we create a string list, mount the store, and rebuild it if necessary. Then we iterate through the files in the specified installation directory, adding them to the List. Then we iterate through that list, deleting each file. Finally we delete the directory itself.

                    // Handle links...
                    UF := FS.Get_File( '\uos\installed.sys' ) ;
                    if( UF <> nil ) then
                    begin
                        Info := FS.Get_File_Info( PChar( '\uos\installed.sys' ), 0 ) ;
                        setlength( Installed, Info.EOF ) ;
                        UF.Read( 0, 0, length( Installed ), PChar( Installed )[ 0 ] ) ;
                        UF.Free ;
                    end ;
                    Installed := lowercase( Installed ) ;
                    if( Installed = '\uos\' + lowercase( S1 ) ) then
                    begin
                        E := FS.Delete_File( '\uos\installed.sys' ) ;
                        Show_Error( E ) ;
                    end ;
                    UF := FS.Get_File( '\uos\default.sys' ) ;
                    if( UF <> nil ) then
                    begin
                        Info := FS.Get_File_Info( PChar( '\uos\default.sys' ), 0 ) ;
                        setlength( Default, Info.EOF ) ;
                        UF.Read( 0, 0, length( Default ), PChar( Default )[ 0 ] ) ;
                        UF.Free ;
                    end ;
                    if( Default = '\uos\' + lowercase( S1 ) ) then
                    begin
                        E := FS.Delete_File( '\uos\default.sys' ) ;
                        Show_Error( E ) ;
                    end ;
                end ; // if
            finally
                FS.Clear_Context( Context ) ;
                FS.Dismount ;
                List.Free ;
                FS.Free ;
                MStore.Free ;
            end ;
        end ; // if( S1 <> '' )
        if( not Prompt ) then
        begin
            exit ;
        end ;
    end ; // while( true )
end ; // UOS_Uninstall_Store

Finally, we check the installed and default links. If either (or both) links point to the directory we just deleted, we delete the link file - it won't do to have links to non-existent directories.

In the next series of articles, we will discuss users and security.