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

Terminal I/O
45 Shells and UCL
46 UOS API, the Application Side
47 UOS API, the Executive Side
48 I/O Devices
49 Streams
50 Terminal Output Filters
51 The TTerminal Class
52 Handles
53 Putting it All Together
54 Getting Terminal Input
55 QIO
56 Cooking Terminal Input
57 Putting it all together, part 2
58 Quotas and I/O

UCL
59 UCL Basics
60 Symbol Substitution
61 UCL Command execution
62 UCL Command execution, part 2
63 UCL Command Abbreviation
64 ASTs
65 UCL Expressions, Part 1
66 UCL Expressions, Part 2: Support code
67 UCL Expressions, part 3: Parsing
68 SYS_GETJPIW and SYS_TRNLNM
69 UCL Expressions, part 4: Evaluation

UCL Lexical Functions
70 PROCESS_SCAN
71 PROCESS_SCAN, Part 2
72 TProcess updates
73 Unicode revisted
74 Lexical functions: F$CONTEXT
75 Lexical functions: F$PID
76 Lexical Functions: F$CUNITS
77 Lexical Functions: F$CVSI and F$CVUI
78 UOS Date and Time Formatting
79 Lexical Functions: F$CVTIME
80 LIB_CVTIME
81 Date/Time Contexts
82 SYS_GETTIM, LIB_Get_Timestamp, SYS_ASCTIM, and LIB_SYS_ASCTIM
83 Lexical Functions: F$DELTA_TIME
84 Lexical functions: F$DEVICE
85 SYS_DEVICE_SCAN
86 Lexical functions: F$DIRECTORY
87 Lexical functions: F$EDIT and F$ELEMENT
88 Lexical functions: F$ENVIRONMENT
89 SYS_GETUAI
90 Lexical functions: F$EXTRACT and F$IDENTIFIER
91 LIB_FAO and LIB_FAOL
92 LIB_FAO and LIB_FAOL, part 2
93 Lexical functions: F$FAO
94 File Processing Structures
95 Lexical functions: F$FILE_ATTRIBUTES
96 SYS_DISPLAY
97 UCL Lexical functions: F$GETDVI
98 Parse_GetDVI

Glossary/Index


Download sources
Download binaries

SYS_GETUAI

In the last article we looked at the code for F$ENVIRONMENT. That code made calls to a new system routine - SYS_GETUAI - which we will cover in this article.

function GETUAI( context : int64 ; const username : string ;
    itemlist : int64 ) : int64 ;

var SRB : TSRB ;

begin
    Set_String( username, SRB ) ;
    Result := SYS_GETUAI( 0, 0, SRB, itemlist, 0, 0, 0 ) ;
end ;
This routine is added to the PasStarlet unit. It simply wraps the string in a TSRB structure and passes it, and the other parameters, on to SYS_GETUAI.

function SYS_GETUAI( nullarg1, context : int64 ; username : TSRB ;
    itemlist, nullarg2, nullarg3, nullarg4 : int64 ) : int64 ;

var Status : byte ;
    SysRequest : TS1I2_Request ;

begin
    fillchar( SysRequest, sizeof( SysRequest ), 0 ) ;
    SysRequest.Request.Subsystem := UOS_Subsystem_USC ;
    SysRequest.Request.Request := UOS_USC_GETUAI ;
    SysRequest.Request.Length := sizeof( SysRequest ) - sizeof( Sysrequest.Request ) ;
    SysRequest.Request.Status := integer( @Status ) ;
    SysRequest.Integer1 := Context ;
    SysRequest.Integer2 := Itemlist ;
    SysRequest.SRB := username ;

    Call_To_Ring0( integer( @SysRequest ) ) ;

    Result := Status ;
end ;
This is like all of our other system calls, so I won't comment on it here.

        UOS_USC_GETUAI:
            begin
                UE := Enter_System_Call( Request, SReq, PID, MMC, 
                    sizeof( S1I2_Request ) - sizeof( SReq ), Address ) ;
                if( UE <> nil ) then
                begin
                    Set_Last_Error( UE ) ;
                    exit ;
                end ;
                try
                    Get_UAI( Kernel, PID, S1I2_Request.Integer1, S1I2_Request.SRB, 
                        S1I2_Request.Integer2, IOSB ) ;
                finally
                    Exit_System_Call( Request, PID, MMC, sizeof( S1I2_Request ) - sizeof( SReq ) ) ;
                end ;
            end ;
We add the above code to the USC.API method to handle the new SYS_USC_GETUAI call.

procedure TUSC.Get_UAI( Kernel : TUOS_Kernel ; PID : TPID ; Context : int64 ;
    Username : TSRB ; ItemList : int64 ; var IOSB : TIOSB ) ;

var Buff : PChar ;
    Descriptor : TSYS_Descriptor ;
    Len : integer ;
    Name : string ;
    Offset : int64 ;
    Process : TProcess ;
    US : TUOS_String ;
    User : TUser ;
    I : integer ;
    Owner : TUser ;
    S : string ;

begin
    US := Get_User_String( Kernel, PID, Username, IOSB.r_io_64.w_status ) ;
    if( IOSB.r_io_64.w_status = UE_Error ) then
    begin
        if( US <> nil ) then
        begin
            US.Free ;
        end ;
        exit ;
    end ;
    Name := trim( As_UTF8( US ) ) ;
    if( US <%gt; nil ) then
    begin
        US.Free ;
    end ;
We start by obtaining the username from the user memory.

    if( Name = '' ) then
    begin
        Process := Get_Process( PID ) ;
        Name := Process.User.Name ;
    end ;
    User := Get_User( Name ) ;
    if( User = nil ) then // Not found
    begin
        IOSB.r_io_64.w_status := UE_Error ;
        Generate_Exception( UOSErr_User_Not_Found ) ;
        exit ;
    end ;
If no user name was passed, we assume the user name of the current process. In either case, we get an instance of the TUser class for that user.

    // Process the item list...
    while( true ) do
    begin
        // Map item and process descriptor...
        Offset := MMC.Lock_Pages( PID, itemlist, sizeof( Descriptor ) ) ;
        try
            Buff := PAnsiChar( MMC.Map_Pages( PID, 0, itemlist, sizeof( Descriptor ), 
                MAM_Read or MAM_Lock ) ) ;
            if( Buff = nil ) then
            begin
                if( MMC.Last_Error = nil ) then
                begin
                    Generate_Exception( UOSErr_Memory_Address_Error ) ;
                end ;
                exit ;
            end ;

            try
                move( Buff[ Offset ], Descriptor, sizeof( Descriptor ) ) ;
                if(
                    ( Descriptor.Buffer_Length = 0 )
                    or
                    ( Descriptor.Buffer_Address = 0 )
                    or
                    ( Descriptor.Return_Length_Address = 0 )
                  ) then // End of list
                begin
                    exit ;
                end ;
                Len := Descriptor.Buffer_Length ;
                if( Descriptor.Buffer_Address = 0 ) then
                begin
                    IOSB.r_io_64.w_status := UE_Error ;
                    Generate_Exception( UOSErr_Memory_Address_Error ) ;
                    exit ;
                end ;
                case Descriptor.Item_Code of
                    UAI_ACCOUNT : // Account name
                        begin
                            if( Write_String( User.Name ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_ACCOUNT_Length : // Account name length
                        begin
                            if( Write_Integer( length( User.Name ) ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_ASTLM : // AST queue limit
                        begin
                            if( Write_Integer( User.Quotas.ASTLM ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_BATCH_ACCESS_P : // Range of times batch access is permitted on primary days
                        begin
                            if( Write_Access( UAT_Batch, True ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_BATCH_ACCESS_S : // Range of times batch access is permitted on secondary days
                        begin
                            if( Write_Access( UAT_Batch, False ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_BIOLM : // Buffered I/O count
                        begin
                            if( Write_Integer( User.Quotas.BIOLM ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_BYTLM : // Buffered I/O byte limit
                        begin
                            if( Write_Integer( User.Quotas.BYTLM ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_CLITABLES : // CLI table name for account
                        begin
                            if( Write_String( User.Name ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_CLITABLES_LENGTH : // CLI table name length for account
                        begin
                            if( Write_Integer( length( User.Name ) ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_CPUTIM : // Maximum CPU time limit per session
                        begin
                            if( Write_Integer( User.Quotas.CPUTIM ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_DEFCLI : // Default shell filename
                        begin
                            if( Write_String( User.Shell ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_DEFCLI_LENGTH : // Default shell filename length
                        begin
                            if( Write_Integer( length( User.Shell ) ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_DEFDEV : // Name of default device
                        begin
                            S := User.Home ;
                            I := pos( ':', S ) ;
                            setlength( S, I ) ;
                            if( Write_String( S ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_DEFDEV_LENGTH : // Length of the name of default device
                        begin
                            S := User.Home ;
                            I := pos( ':', S ) ;
                            setlength( S, I ) ;
                            if( Write_Integer( length( S ) ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_DEFDIR : // Default directory name
                        begin
                            S := User.Home ;
                            I := pos( ':', S ) ;
                            S := copy( S, I + 1, length( S ) ) ;
                            if( Write_String( S ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_DEFDIR_LENGTH : // Default directory name length
                        begin
                            S := User.Home ;
                            I := pos( ':', S ) ;
                            S := copy( S, I + 1, length( S ) ) ;
                            if( Write_Integer( length( S ) ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_DEF_PRIV : // Default privileges
                        begin
                            if( Write_Integer( User.Privileges ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_DFWSCNT : // Default working set size in pages
                        begin
                            if( Write_Integer( User.Quotas.WSDEFAULT ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_DIOLM : // Direct I/O count limit
                        begin
                            if( Write_Integer( User.Quotas.DIOLM ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_DIALUP_ACCESS_P : // Range of times dialup access is permitted for primary days
                        begin
                            if( Write_Access( UAT_Dialup, True ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_DIALUP_ACCESS_S : // Range of times dialup access is permitted for secondary days
                        begin
                            if( Write_Access( UAT_Dialup, False ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_ENCRYPT : // Encryption algorithm ID for the primary password
                        begin
                            if( Write_Integer( 0 ) ) then //TODO
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_ENCRYPT2 : // Encryption algorithm ID for the secondary password
                        begin
                            if( Write_Integer( 0 ) ) then //TODO
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_ENQLM : // Lock queue limit
                        begin
                            if( Write_Integer( User.Quotas.ENQLM ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_EXPIRATION : // Date/time of account expiration
                        begin
                            if( Write_Integer( User.Expiration ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_FILLM : // Open file limit
                        begin
                            if( Write_Integer( User.Quotas.FILLM ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_FLAGS : // Account flags (see UAF_*)
                        begin
                            if( Write_Integer( User.Flags ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_JTQUOTA : // Initial byte quota for job symbol table
                        begin
                            if( Write_Integer( User.Flags ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_LASTLOGIN_I : // Date/time of last interactive login
                        begin
                            if( Write_Integer( User.Last_Interactive_Login ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_LASTLOGIN_N : // Date/time of last noninteractive login
                        begin
                            if( Write_Integer( User.Last_NonInteractive_Login ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_LGICMD : // Name of default login command file
                        begin
                            if( Write_String( User.LGICMD ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_LGICMD_LENGTH : // Name of default login command file
                        begin
                            if( Write_Integer( length( User.LGICMD ) ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_LOCAL_ACCESS_P : // Range of times local access is permitted for primary days
                        begin
                            if( Write_Access( UAT_Interactive, True ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_LOCAL_ACCESS_S : // Range of times local access is permitted for secondary days
                        begin
                            if( Write_Access( UAT_Interactive, False ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_LOGFAILS : // Count of login failures since last login
                        begin
                            if( Write_Integer( User.Login_Failures ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_MAXACCTJOBS : // Max processes for all sessions of this user
                        begin
                            if( Write_Integer( User.Quotas.MaxAcctJobs ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_MAXDETACH : // Max detached processes
                        begin
                            if( Write_Integer( User.Quotas.MAXDETJOBS ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_MAXJOBS : // Max processes for each session
                        begin
                            if( Write_Integer( User.Quotas.MaxJobs ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_NETWORK_ACCESS_P : // Range of times network access is permitted for primary days
                        begin
                            if( Write_Access( UAT_Network, True ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_NETWORK_ACCESS_S : // Range of times network access is permitted for secondary days
                        begin
                            if( Write_Access( UAT_Network, False ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_OWNER : // Name of account owner
                        begin
                            Owner := Get_User( User.Owner ) ;
                            if( Write_String( Owner.Name ) ) then
                            begin
                                Owner.Detach ;
                                exit ;
                            end ;
                            Owner.Detach ;
                        end ;
                    UAI_OWNER_LENGTH : // Length of name of account owner
                        begin
                            Owner := Get_User( User.Owner ) ;
                            if( Write_Integer( length( Owner.Name ) ) ) then
                            begin
                                Owner.Detach ;
                                exit ;
                            end ;
                            Owner.Detach ;
                        end ;
                    UAI_PBYTLM : // Paged buffer I/O byte count
                        begin
                            if( Write_Integer( User.Quotas.PBYTLM ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_PGFLQUOTA : // Paging file quote (in pages)
                        begin
                            if( Write_Integer( User.Quotas.PGFLQUOTA ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_PRCCNT : // Subprocess creation limit
                        begin
                            if( Write_Integer( User.Quotas.PRCLM ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_PRI : // Default base priority
                        begin
                            if( Write_Integer( User.Priority ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_PRIMEDAYS : // Which days represent primary days
                        begin
                            if( Write_Integer( 0 ) ) then // TODO
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_PRIV : // Privileges for user
                        begin
                            if( Write_Integer( User.Privileges ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_PWD : // Hashed primary password
                        begin
                            if( Write_Integer( 0 ) ) then // TODO
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_PWD_DATE : // Date/time of last password change (-1 means pre-expired)
                        begin
                            if( Write_Integer( 0 ) ) then // TODO
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_PWD_LENGTH : // Minimum password length
                        begin
                            if( Write_Integer( 0 ) ) then // TODO
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_PWD_LIFETIME : // Password lifetime in UOS time format
                        begin
                            if( Write_Integer( 0 ) ) then // TODO
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_PWD2 : // Hashed secondary password
                        begin
                            if( Write_Integer( 0 ) ) then // TODO
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_PWD2_DATE : // Date/time of last secondary password change (-1 means pre-expired)
                        begin
                            if( Write_Integer( 0 ) ) then // TODO
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_QUEPRI : // Maximum job queue priority
                        begin
                            if( Write_Integer( User.QPriority ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_REMOTE_ACCESS_P : // Range of times remote access is permitted for primary days
                        begin
                            if( Write_Access( UAT_Remote, True ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_REMOTE_ACCESS_S : // Range of times remote access is permitted for secondary days
                        begin
                            if( Write_Access( UAT_Remote, False ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_SALT : // Random password salt
                        begin
                            if( Write_Integer( 0 ) ) then // TODO
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_SHRFILLM : // Shared file limit
                        begin
                            if( Write_Integer( User.Quotas.SFILLM ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_TQCNT : // Timer queue entry limit
                        begin
                            if( Write_Integer( User.Quotas.TQELM ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_UIC : // UIC
                        begin
                            if( Write_Integer( User.UIC ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_USER_DATA : // Up to 255 bytes of customer information
                        begin
                            if( Write_String( User.Custom ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_WSEXTENT : // Working set extent in pages
                        begin
                            if( Write_Integer( User.Quotas.WSEXTENT ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                    UAI_WSQUOTA : // Working set quota in pages
                        begin
                            if( Write_Integer( User.Quotas.WSDEFAULT ) ) then
                            begin
                                exit ;
                            end ;
                        end ;
                end ;
            finally
                MMC.UnMap_Pages( 0, itemlist, sizeof( Descriptor ) ) ;
            end ;
        finally
            MMC.Unlock_Pages( PID, itemlist, sizeof( Descriptor ) ) ;
        end ;
        itemlist := itemlist + sizeof( Descriptor ) ;
    end ; // while( true )
end ; // TUSC.Get_UAI
The rest of the routine processes through a set of descriptors, as we've seen in previous articles (for instance, the GETJPI system call). Some of the items are marked with //TODO to indicate features which we haven't talked about yet. We will cover these in future articles. To simplify the code, we call some local functions.

    function Write_Integer( I : int64 ) : boolean ;

    begin
        if( Len > sizeof( I ) ) then
        begin
            Len := sizeof( I ) ;
        end ;
        IOSB.r_io_64.w_status := Write_User( Kernel, PID, Descriptor.Buffer_Address, Len, I ) ;
        Result := ( IOSB.r_io_64.w_status <> 0 ) ;
    end ;


    function Write_String( S : string ) : boolean ;

    var SRB : TSRB ;

    begin
        if( Len < Length( S ) ) then
        begin
            setlength( S, Len ) ;
        end ;
        SRB.Buffer := Descriptor.Buffer_Address ;
        SRB.Length := Len ;
        IOSB.r_io_64.w_status := Set_User_String( Kernel, PID, SRB, S ) ;
        Result := ( IOSB.r_io_64.w_status <> 0 ) ;
    end ;


    function Write_Access( UAT : integer ; Primary : boolean ) : boolean ;

    begin
        //TODO
        Result := False ;
    end ;
These functions write integer and string values to the user's data space.

In the next article, we'll look at the next lexical function.

 

Copyright © 2020 by Alan Conroy. This article may be copied in whole or in part as long as this copyright is included.