MULTICS ADMINISTRATIVE BULLETIN MAB-068 To: MAB Distribution From: Ron Barstad Date: August 13, 1985 Subject: Multics Configuration Management: Programming Standards A description of the Standards, Conventions, and Guidelines Used in the Software and Documentation of the Multics Operating System, this MAB is one of a set dealing with Multics Configuration Management. For an overview of this set see MAB-070 "Multics Configuration Management: Policy Statement". This MAB replaces the Level 68 manual AN82, "Standards/System Designers' Notebook" dated June, 1980. Corrections to the original sections 1 through 12 are noted by change bars. Sections 13, 14, and 15 are new for this MAB and contain no change bars in the text. Republished as a MAB, these programming standards are now Multics administrative policy. _________________________________________________________________ Multics Project internal working documentation. Not to be reproduced or distributed outside the Multics project. MAB-068 Multics Programming Standards REVISION HISTORY REVISION DATE AUTHOR initial June, 1980 draft June, 1985 Benson I. Margulies final August, 1985 Ron Barstad ii CONTENTS Page Section 1 Introduction . . . . . . . . . . . . . . 1-1 How to Use This Document . . . . . . . 1-1 Volatility of Contents . . . . . . . . 1-1 General Issues . . . . . . . . . . . . 1-1 Registered Names . . . . . . . . . . . 1-2 Topics . . . . . . . . . . . . . . . . 1-2 Section 2 Interface Standards . . . . . . . . . . . 2-1 Command Interfaces . . . . . . . . . . 2-1 Storage System Conventions . . . . 2-1 Command Arguments . . . . . . . . . 2-3 Pathname Conventions . . . . . . . 2-4 Control Argument Conventions . . . 2-5 Output Conventions . . . . . . . . 2-5 User Interaction Conventions . . . 2-6 Subroutine Interface Standards . . . . 2-7 Subroutine Names . . . . . . . . . 2-7 Argument Standards . . . . . . . . 2-7 Section 3 General Programming Standards . . . . . . 3-1 Command Standards . . . . . . . . . . 3-1 Naming Standards . . . . . . . . . . . 3-2 Storage System Conventions . . . . . . 3-2 Output Conventions . . . . . . . . 3-3 Use of On Units for the Cleanup Condition . . . . . . . . . . . . 3-3 Coding Conventions . . . . . . . . 3-3 Section 4 Modularity . . . . . . . . . . . . . . . 4-1 Program Structure . . . . . . . . . . 4-1 Compilable Unit Size . . . . . . . . . 4-1 Generality of Mechanism . . . . . . . 4-1 External Availability of Mechanism . . 4-1 Binding and Bindfiles . . . . . . . . 4-3 Contents of Bound Segments . . . . 4-3 Names of Bound Segments . . . . . . 4-3 Bindfile Contents . . . . . . . . . 4-3 Bindfile Formatting . . . . . . . . 4-4 Section 5 Environment Independence . . . . . . . . 5-1 Reentrancy . . . . . . . . . . . . . . 5-1 iii CONTENTS (cont) Page Transparency . . . . . . . . . . . . . 5-1 Interruptibility . . . . . . . . . . . 5-2 Condition Handling . . . . . . . . . . 5-2 Access Assumptions . . . . . . . . . . 5-2 Use of Standard Mechanisms . . . . . . 5-2 Pathnames and Search Rules . . . . . . 5-2 Section 6 Program Format . . . . . . . . . . . . . 6-1 Comments in Programs . . . . . . . . . 6-1 Copyright Notice . . . . . . . . . 6-1 Journalization Notice . . . . . . . 6-1 Interface Descriptions . . . . . . 6-2 Program Comments . . . . . . . . . 6-2 General Layout of a PL/I Program . . . 6-2 Standard Format . . . . . . . . . . 6-3 ALM Program Considerations . . . . . . 6-3 Section 7 Include File Format and Constraints . . . 7-1 Include File Format . . . . . . . . . 7-1 Use of Include Files . . . . . . . . . 7-2 Naming Include Files . . . . . . . . . 7-2 PL/I and ALM Include Files . . . . . . 7-2 Section 8 PL/I Language Conventions . . . . . . . . 8-1 Constraints . . . . . . . . . . . . . 8-1 Efficient PL/I Constructs . . . . . . 8-2 The Alignment Attributes . . . . . 8-2 Attributes with Arithmetic and Pointer Variables . . . . . . . 8-2 Use of the Alignment Attributes with Short Strings . . . . . . 8-3 Use of the Alignment Attribute with Long Strings . . . . . . . 8-3 Use of Unaligned Short Variables in Arrays and Structures . . . 8-3 Use of the Precision Attribute in Offset and Length Expressions . . 8-3 The Use of Internal Static to Simulate Named Constants . . . . . 8-4 Use of the Initial Attribute . . . 8-5 The Assignment Operation . . . . . 8-5 The Multiple Assignment Statement . . . . . . . . . . . 8-5 Conversions . . . . . . . . . . 8-6 Pictures . . . . . . . . . . . . 8-6 Arithmetic Operations . . . . . . . . 8-7 Binary Operations . . . . . . . 8-7 Decimal Operations . . . . . . . 8-7 String Operations . . . . . . . . . 8-8 iv CONTENTS (cont) Page Special Case of Concatenation . 8-8 Operations on Long Strings . . . 8-8 Aggregate Operations . . . . . . 8-9 Use of the Builtin Functions . . . 8-9 Arithmetic Builtins . . . . . . 8-9 String Builtins . . . . . . . . 8-10 Mathematical Builtins . . . . . 8-10 The Call Statement and Function References . . . . . . . . . . . . 8-11 Determining the 'Quickness' of a Block . . . . . . . . . . . . . 8-11 Using Constant Argument Lists . 8-12 Using If Statements . . . . . . . . 8-13 Optimization of Comparisons . . . . 8-13 Other Constructs That Are Costly or Dangerous . . . . . . . . . . . . 8-14 Section 9 Storage Management . . . . . . . . . . . 9-1 Use of the Storage System . . . . . . 9-1 Pathnames . . . . . . . . . . . . . 9-1 Naming Conventions . . . . . . . . 9-2 Working Directory Use . . . . . . . 9-2 Access Control List Management . . 9-2 Making Segments Known and Unknown . 9-3 Pathnames vs. Segment Pointers . . 9-3 Multisegment Files . . . . . . . . 9-4 Use of the Bit Count . . . . . . . 9-5 Storage Allocation . . . . . . . . . . 9-5 Internal Static Storage . . . . . . 9-5 PL/I Areas . . . . . . . . . . . . 9-5 Temporary Segments . . . . . . . . 9-6 Section 10 Documentation Standards . . . . . . . . . 10-1 Location of Documents . . . . . . . . 10-1 Section 11 Info Segments . . . . . . . . . . . . . . 11-1 Style . . . . . . . . . . . . . . . . 11-1 Physical Appearance . . . . . . . . . 11-1 Naming Conventions . . . . . . . . . . 11-2 Syntax of Info Segments . . . . . . . 11-2 Title . . . . . . . . . . . . . . . 11-2 Paragraphs . . . . . . . . . . . . 11-3 Sections . . . . . . . . . . . . . 11-3 Command Descriptions . . . . . . . 11-3 Subroutine Descriptions . . . . . . 11-4 Other Info Segments . . . . . . . . 11-4 Section 12 Rules for Translator Writers . . . . . . 12-1 The Command Program . . . . . . . . . 12-1 v CONTENTS (cont) Page The Object Segment Created . . . . . . 12-1 Listing Output . . . . . . . . . . . . 12-2 Miscellaneous Requirements . . . . . . 12-3 Section 13 Rules for Coding Trusted Software . . . . 13-1 Trusted Software . . . . . . . . . . . 13-1 Trusted Programs and the NCSC Security Rating . . . . . . . . . . . . . . . 13-1 User interface parameters and their importance . . . . . . . . . . . . . 13-2 General rules for all trusted code . . 13-2 The ring model . . . . . . . . . . . . 13-3 Hardware ring checks . . . . . . . 13-3 Ring of execution . . . . . . . 13-3 ring numbers in pointers . . . . 13-4 Examples of Hardware Ring Checks 13-4 Software ring checks -- the validation level . . . . . . . . . 13-5 gate parameters: security considerations . . . . . . . . . . . 13-6 Naming Conventions for Gate Parameters . . . . . . . . . . . . 13-7 Rules for gate parameters -- forbidden reference patterns . . . 13-7 multiple parameter read . . . . 13-8 parameter write, then read . . . 13-8 multiple parameter write . . . . 13-8 passing parameter to another subroutine . . . . . . . . . . 13-8 parameters in expressions . . . 13-9 Packed pointer parameters . . . 13-9 Improper reference to structure parameters . . . . . . . . . . 13-9 When should TCB modules generate an audit trail . . . . . . . . . . . . . 13-10 Information that is Necessary . . . 13-10 Trusted server interfaces . . . . . . 13-11 Ring 1 circumvention of AIM policies . 13-11 Privileged exec_coms that walk the hierarchy . . . . . . . . . . . . . . 13-12 system error message documentation . . 13-12 What messages should be documented 13-12 How to document them . . . . . . . 13-13 Commentary in Programs and Include Files . . . . . . . . . . . . . . . . 13-15 Commentary in Source . . . . . . . 13-16 Section 14 Writing and Updating Multics Design Documents . . . . . . . . . . . . . . . 14-1 vi CONTENTS (cont) Page Content of an MDD . . . . . . . . . . 14-1 The format of an MDD . . . . . . . . . 14-2 Section 15 Coding Standards For B2 Functional Tests And Utilities . . . . . . . . . . . . . 15-1 General Standards . . . . . . . . . . 15-1 Test Program Standards . . . . . . . . 15-2 Utility Program Standards . . . . . . 15-5 Appendix A Registered Control Arguments . . . . . . A-1 Appendix B Registered Suffixes . . . . . . . . . . . B-1 List of Suffixes . . . . . . . . . . . B-1 Appendix C Registered I/O Switch Names . . . . . . . C-1 List of I/O Switch Names . . . . . . . C-1 Appendix D Registered Condition Names . . . . . . . D-1 List of Condition Names . . . . . . . D-1 vii TABLES Table A-1 Approved Standard Control Arguments . . . A-1 Table A-2 Approved Special Control Arguments . . . A-5 1 SECTION 1 INTRODUCTION HOW TO USE THIS DOCUMENT This document should be read in its entirety in order to understand its contents. It should then be used as a reference document whenever relevant to the work being done. VOLATILITY OF CONTENTS The information in this document will be updated. Because the standards change as the system evolves, much of the system will not completely conform to the standards. As part of the development effort, software should be upgraded to meet the requirements of the new or changed standards whenever this is possible. GENERAL ISSUES To expound upon the general issues that comprise the design goals of the Multics Operating System is beyond the scope of this document. However, it is useful to remind the reader of some of the most important issues. Multics interfaces are designed with the average user in mind. As a result the needs of the very inexperienced or the very sophisticated user may be slighted. Consistency among all parts of the system is stressed in order to make this very complicated system possible to use and to allow different subsystems to be combined in ways not originally planned. The issue of general style has always been considered important. For example, minimal use of jargon and the use of correct English is considered to be very important for both the documentation and the system interfaces themselves. Thus, 1-1 diagnostic messages are sentences that begin with an upper case letter and end with a period. REGISTERED NAMES One of the most important parts of the user interface that must be kept consistent is that of the several classes of names used by commands and subroutines. This manual contains a number of appendices that register these names. Only those names registered here may be used; if new names are required they must be registered. Appendix A lists control arguments. Appendix B lists suffixes. Appendix C lists I/O switch names. Appendix D lists condition names. TOPICS Main topics included in this manual are interface standards (including both commands and subroutines), programming standards, modularity, environment independence, program format, include file format, PL/I language conventions, storage management, use of the storage system, documentation standards, info segments, and rules for translator writers. 1-2 SECTION 2 INTERFACE STANDARDS COMMAND INTERFACES Commands are a special class of programs designed with the terminal user in mind. They serve as the principal interface between the system and all of its users. Since many commands are used by both naive and sophisticated users, they must be designed with a two-fold purpose. The naive user should not be burdened with information he doesn't understand; the sophisticated user must not be denied the facilities that he needs. Commands should not be too powerful. The result of a typing error should not be a disaster for the user. Commands should be recursive, i.e., they should be able to be interrupted in midstream and invoked again. If it is inappropriate for a particular command to be used in this way, protection should be built into the command to query or inform the user. Commands should not retain information from one invocation to the next in such a way that behavior of the second invocation is affected by some hidden implication of the first. For example, the use of the -brief control argument in one invocation should not make all future output be in -brief form. On the other hand, a metering command that accumulates data should have a -reset option to reset the accumulated values. Storage System Conventions In general, commands should deal with multisegment files as well as segments, unless inappropriate. 2-1 Commands should not perform write operations on the components of archive segments, except for the archive, archive_sort, and reorder_archive commands. Commands should have no knowledge of the structure of archive segments, except for the commands mentioned above and the bind command. Generally, commands should chase links, i.e., they should perform the operation on the storage system entry to which a link points. However, there are two exceptions. Links should not be chased when the command can manipulate the attributes of the link, for example, the rename command. Links should also not be chased by default when a starname is given. The -chase control argument should be used to explicitly cause chasing of links. Refer to the copy command in the MPM Commands and Active Functions, Order No. AG92. A command name generally starts with a verb. Multiword names should have each word separated with an underscore. A command name should consist only of lowercase letters and the underscore character. The pl1 command is an obvious exception, but doesn't invalidate the rule. Its name was chosen by another guideline for constructing names. A command name should be short enough so that it may be conveniently typed. A two to four letter abbreviation should be selected using the first letter of the words or syllables of the name. If the command is in the tools library, it should not be supplied with an abbreviation. The system libraries should be checked to ensure that there are no conflicts with other installed command names and abbreviations. New command names should be chosen with the following distinction in mind. Commands whose names start with print should have no knowledge of the structure of the input and deal with ASCII data. Commands whose names start with display should know about the data structure of the input and produce highly structured output. Commands whose names start with dump should have little knowledge of the contents of the data, may produce octal output, and may format the output in blocks. Commands that are part of a subsystem should have the subsystem name or an abbreviation as a leading name. In general, the suffix command should be the principal command that processes a segment whose name ends in .suffix. This is particularly true for language translators, for example, the pl1 command. 2-2 Command Arguments Commands should check carefully for argument validity and warn users of possible misunderstandings. They should be consistent in behavior and interface with other commands. Commands that always require arguments should print a usage line when invoked with no arguments. Commands that require no arguments should print a usage line if arguments were given. Command arguments should be order independent unless the order dependency serves a useful purpose (e.g., -update of the bind command). Commands whose interface is simple (such as the add_name command) should accept multiple arguments if appropriate. Commands that deal with segments whose names have a fixed suffix should not force the user to type the suffix; however, they should permit the user to include the suffix as part of the name. The expand_pathname_$add_suffix subroutine performs suffix handling for such commands. A series of related commands should have a similar or parallel syntax and control arguments. Arguments for which sensible defaults exist should be allowed to be omitted, i.e., the last access name to set_acl and the working directory as a default pathname to many commands. It is desirable to check the validity of all arguments before beginning its execution or before terminating the command. Command arguments should be used, whenever appropriate, to inform the command what to do. The user should not have to type additional lines of input to control the behavior of the command. For cases where there is a great deal of input it should be possible to put the input in a control segment and to specify the pathname of the control segment as an argument to the command. The use of octal numbers is discouraged. An exception is the use of octal numbers to represent a segment number or segment offset, and in such cases it may be more appropriate to use a 2-3 virtual pointer (as interpreted by the cv_ptr_ subroutine) or a virtual entry (as interpreted by the cv_entry_ subroutine). Pathname Conventions Commands that accept pathnames as arguments should accept relative pathnames or absolute pathnames as interpreted by the procedures expand_pathname_ and absolute_pathname_. Commands that accept pathnames should honor the star convention whenever appropriate. Careful consideration of the interaction between the star convention and links must be given. Links are not chased by default when given a starname as an input * argument. | Commands that operate on branches accept the -chase and the | -no_chase control arguments. -chase, when invoked with a | starname, performs the desired operation(s) on the targets of any | links which match the starname as well as those branches which | match the starname. -no_chase, when invoked with a non-starname, | indicates that the command should not perform the desired | operation(s) if the non-starname specifies a link. The opposite | control arguments may also be used (-chase with a non-starname, | -no_chase with a starname). The defaults are: -chase if a | non-starname is given; -no_chase if a starname is present. For | example; | move ** === -chase | moves all the segments from the working directory to the | directory , and also moves all segments referenced by any | links in the working directory. Commands that accept pairs of pathnames should honor the equal convention, for example, the compare_ascii command. Commands that take segment names as arguments should accept pathnames and not reference names unless the command is dealing with reference names explicitly, such as the where command. The -name control argument should be used by commands that normally take a segment number as an argument to indicate that the argument looks like a segment number but really is a pathname. The -pathname control argument should be used by commands that normally take a pathname to distinguish pathnames beginning with a minus (-) from control arguments. 2-4 Control Argument Conventions Commands should accept control arguments that are appropriately named and that specify needed options. Similar commands should accept the same control arguments, for example, the copy and move commands. Commands that produce output should accept the control arguments -brief, -no_header, -long, and -totals, if appropriate. Invalid or inappropriate control arguments should be diagnosed and the operation of the command terminated. Entry names beginning with minus signs should be considered invalid by most commands. Any unrecognized string beginning with a minus sign should be diagnosed as an invalid control argument, rather than being treated as an entry name (even by commands that do not take control arguments). If there is a need to accept entry names with a leading minus sign, the -pathname control argument may be used. New control arguments should not be invented when there are existing ones that serve the purpose. All control arguments should be registered. (See Appendix A for a list of registered control arguments.) Control arguments that are used only by commands in the tools library should not have abbreviations. Control arguments that take arguments should do so uniformly (from one command to another) and should always take the same type of argument. Output Conventions Unless the purpose of a command is to produce output, it should not produce terminal output during its normal operation. The success of a command doing its job is indicated by the absence of output. However, a command that takes a long time to execute should print a short message to reassure the user that it has started, for example, the pl1 command. Normal output from a command should be written to the I/O switch user_output. 2-5 Error output by a command should be printed by the com_err_ subroutine. The long name of the command should be included in the com_err_ message. The com_err_ message should give additional information to resolve possible ambiguity about the source of the error. The user's argument that is in error should always be included in the call to com_err_. Calls to com_err_ should include the appropriate nonzero status code. The subroutine active_fnc_err_ should be used in a similar fashion for error reporting by active function procedures. Error messages about storage system entries should include the absolute pathname of the entry in error. Those messages concerning input arguments should include the argument as given by the user. Frivolous use of com_err_ should be avoided. It should not be used unless an error has actually occurred, as the condition command_error is signalled. Other output should be done by means of iox_$put_chars or ioa_. Red shift should not be used, since few terminals handle this mode properly. Messages with underlining should be avoided. Commands that produce a large amount of output (e.g., the PL/I compiler issuing diagnostics) should write all the messages on user_output and write a single error message with com_err_ indicating that there were errors. Commands should not write terminal-directed output to I/O switches other than user_output except when specified by control arguments. Commands that produce only one line of output should not emit blank lines. User Interaction Conventions When a command that interacts with the typist produces an error message that the typist does not expect, it should perform a resetread operation on user_input so that the user can modify his subsequent input. 2-6 Commands normally should not handle the quit condition. Commands that interact with the typist should be prepared to handle the program_interrupt condition signalled by the program_interrupt command. This is particularly important for commands that produce a large amount of output that the user might want to abort. Commands that ask questions should do so by means of the subroutine command_query_ so that the command_question condition is signalled. SUBROUTINE INTERFACE STANDARDS Subroutine Names Names of subroutines or data bases should be descriptive of the function they perform. The name should not be so long as to be inconvenient to use. Names of segments created by system programs that are to remain as segment names in a directory should end in underscore, to avoid naming conflicts with user-defined names. Names should consist only of lowercase letters, the underscore character, and the dollar sign. Subroutine names which will appear as names on segments in the system libraries should end in an underscore to avoid conflicts with user program names. Total length of subroutine names of the form a$b should not exceed 32 characters; the entry point portion of such a name should not end in an underscore. Names of subroutines or data bases belonging to a subsystem should start with the name of the subsystem or a consistent abbreviation. Argument Standards Standard status codes should always be returned if the subroutine returns an error code. Either codes in the system data base error_table_ or a registered subsystem error table should be used. 2-7 The status code should be the last argument to a subroutine. Arguments in a calling sequence should be grouped: Input, Input, ..., Output, Output. Arguments that are both input and output should be avoided. Arguments that are used for many subroutines should be declared in the same way for all such uses. Subroutines that return more than one argument or that have side effects should not be called as functions. The type of each argument should be chosen with the use and meaning of the argument in mind. Subroutines should not check the number or type of input arguments, but assume they have been called correctly. Subroutines should not validate the correctness of their input arguments, unless it is part of their intended operation. However, subroutines which accept structure arguments should | check the input structure version number for validity. Gade | targe programs have strict parameter vaildation requirements. | See "Gate Parameters: Security Considerations" in Section 13. Character string arguments should be passed instead of a ptr to a string and its length. They should be declared unaligned and usually declared char(*) unless the length is fixed. 2-8 SECTION 3 GENERAL PROGRAMMING STANDARDS This section documents conventions (to be used by system programs) that are of a general nature and do not fall within the province of the other sections of this document. COMMAND STANDARDS Commands should not call other commands. Commands that perform general purpose service functions used by other commands or subsystems should be modularized into a command and a subroutine interface that implement the service function. The subroutine usually should not print messages but should return a standard status code to indicate an error condition. Commands that accept arguments should accept a variable number of arguments and should not explicitly declare a fixed number of arguments. The subroutine cu_$arg_ptr should be used to obtain each argument and the subroutine cu_$arg_count should be used to obtain the number of arguments. Commands should invoke standard approved general purpose subroutines and internal interfaces developed specifically for the command or subsystem. They should not call internal interfaces of other commands or subsystems. Commands that are also active functions should print the results that would be returned by the active function. Active functions that would be meaningful commands should also be invokable as commands. 3-1 NAMING STANDARDS Programs that produce output in a file should name the output file in a sensible fashion. Listing output from the processing of segment xxx.suffix should be placed in xxx.list. The names of all new condition names should end in an underscore to avoid naming conflicts with user-defined names. Unless an I/O switch name is an input argument, the names of all I/O switches created for use by the program should identify the program subsystem to provide meaningful output from print_attach_table. Also, the names should include a unique string to differentiate switches used by recursive invocations of the program or subsystem. STORAGE SYSTEM CONVENTIONS Programs that require temporary segments should use the subroutines get_temp_segment_ and get_temp_segments_ to obtain them and should call release_temp_segment_ or release_temp_segments_ when they are finished. Programs should terminate any reference names that they associate with a segment. Programs generally should initiate a segment with a null reference name. System programs should not allocate storage in the user free storage area. Storage is allocated in the user free area unless an is given in the PL/I and . Therefore, s must be used. Such programs should use the area obtained by calling get_system_free_area_. Programs should have a cleanup condition handler to free allocated storage and temporary segments. The duplicate name convention implemented by the subroutine nd_handler_ should be honored by user ring programs. Programs should use the subroutine delete_ for deleting storage system entries. If a nonzero error code is returned, the subroutine dl_handler_ should be used to resolve the error. Programs should use the subroutine term_ for terminating segments that may have nonnull reference names associated with them or that may have links snapped to them. 3-2 Output Conventions Programs other than commands generally should not produce output or print error messages except for those subroutines whose explicit purpose is to perform these functions. The exact nature of the output should be documented in the interface description. If a subroutine prints an error message, it should use the com_err_ subroutine (if printing a fatal error on the caller's behalf where the caller has too little information to print a meaningful message), or the sub_err_ subroutine (if printing a nonfatal error which can be restarted selectively under control of the caller or the user). The name of the command invoking the subroutine should be given in such error messages, implying that this name must be an input argument to the subroutine. Use of On Units for the Cleanup Condition The on unit for the cleanup condition must not be a goto statement, and the on unit (or any procedure or block invoked from the on unit) must not contain a nonlocal goto statement, as this will interfere with the nonlocal transfer that originally signalled the condition. Cleanup tasks include freeing allocated storage and releasing temporary segments. Cleanup handlers should never print anything. Coding Conventions Programs should only be written in the PL/I language, except with explicit permission. Exceptions usually are made when performance is an issue. All variables should be declared. All parameter lists for external entries should be fully declared, except for those entries accepting a variable number of arguments. These should be declared as options (variable). Declarations should be grouped in a readable fashion. 3-3 All pad fields in data structures should be explicitly declared, i.e., there should be no gaps. All pad fields that are documented to be zero should be set to zero explicitly. This operation allows for future expansion of a data item. A name such as mbz1 should be used to declare pad fields to make it clear that the caller must zero such fields. Whenever possible, avoid including system parameters as constants in a program. For example, if the maximum number of words for a segment is required, the external variable sys_info$max_seg_size should be referenced. Programs should not use external state variables to pass data values between external programs. This obscures the operation of such programs. Instead, the data should be passed as arguments. 3-4 SECTION 4 MODULARITY The Multics Operating System is modularized to simplify debugging and modification and to increase reliability. In the following section, the issues and modularity which are important to designers and implementors are discussed. PROGRAM STRUCTURE Overall structure of each program component is to be designed with the newest techniques. Small parts of programs are to be as understandable as the total program. Using PL/I internal procedures is encouraged because they are almost as efficient as in-line code. COMPILABLE UNIT SIZE Programs are recommended to be no longer than a few hundred lines of executable code. Try not to combine small components into one very large program, unless performance is affected. GENERALITY OF MECHANISM Much of the uniformity of mechanism and function in the Multics system has been attained by attempting to generalize mechanisms so that they can be shared. This eliminates the need for similar facilities in distinct parts of the system that are likely to produce incompatible effects or later require unwieldy simultaneous extension. Do not generalize a mechanism if it is not justifiable, however. EXTERNAL AVAILABILITY OF MECHANISM Make each designed mechanism externally available to the rest of the system only if it is useful and there is a demand for it. Making a mechanism externally available has implications to 4-1 future changes, as compatibility must then be maintained. As a result, the designer should lean towards not making it available. 4-2 BINDING AND BINDFILES The individual program components of the Multics system are usually bound together by the Multics binder. This is done to reduce the number of separate components visible in the system, to make internal interfaces unavailable, to conserve segment numbers, and to minimize the number of linkage faults. Contents of Bound Segments Programs that are logically related should be bound together and placed in an order chosen to minimize the number of page faults taken when various subsets and usage patterns of the components within are used. Names of Bound Segments Every bound segment is named with a functionally related name starting with the string "bound_" and terminating with an underscore. The bindfile is named bound_segment_name_.bind. The bindfile and all of its components are stored in a single archive segment whose name is bound_segment_name_.archive. Bindfile Contents The contents of the bindfile should abide by the following conventions: 1. The order statement is required to specify binding order. 2. An objectname statement is required to state the name of the bound segment. 3. A global: delete; statement is required to ensure that extraneous definitions are deleted. 4. An addname statement is required to specify all names that are to be known externally. 5. Statements used only for debugging purposes are not to be used (e.g., No_link, Force_Order). 6. An objectname statement should be included for each component that has other attributes specified. Components with no attributes specified should not have a corresponding objectname statement since they will already have been named in the Order statement. 4-3 7. The retain statement is to be used only for those definitions that must be retained because they are externally available interfaces. 8. The synonym keyword is to be used to specify all synonyms for each component. Bindfile Formatting The following formatting rules are to be used for ease of reading of the bindfile: 1. Tabs should be used to separate keywords from their arguments. 2. Each objectname statement should be preceded by one blank line. 3. Synonym, delete, retain, and global statements should be indented one space with arguments lined up under the arguments of the objectname statement. 4. Comments should be included at the beginning of the bindfile that give the logical relationship of bound components, and | that state the date, author and reason for each change. The | modification history comment should be generated through use | of the history comment command described in MTB-716. 5. A comment containing the word END should be placed at the end of the bindfile. 4-4 SECTION 5 ENVIRONMENT INDEPENDENCE Subsystems, commands, and subroutines should be implemented so that they may be used in a variety of environments without other portions of the environment affecting them and without their affecting other components of the environment. This is referred to as the principle of surroundability. Surroundability is important because it makes it possible for users and subsystem designers to integrate many portions of the Multics system to compose a new subsystem without having to change any of the components they are integrating. REENTRANCY Components of the Multics Operating System should be reentrant. This is accomplished by proper use of pure procedures, the recursive nature of the PL/I language and its implementation, and careful use of static storage. If making a subsystem reentrant results in performance degradation or implemention problems, it is permissible for the subsystem to not be reentrant. In this case, checks are to be implemented to detect possible misuses of the subsystem and are to either prevent the misuse or warn the user of the possible conflict. TRANSPARENCY The operation of a program should be transparent to the environment. This is accomplished by correct storage management techniques, programs cleaning up any temporary environment changes, naming conventions, I/O attachments, and avoiding other static effects on the environment. For example, if a program changed the working directory without that being a specified property of that program, then subsequent programs would behave differently than expected. 5-1 INTERRUPTIBILITY Programs are to be implemented so their operation can be interrupted and resumed at a later time. Programs must take precautions while they are making critical modifications to the environment. They should either prevent interrupts or be prepared to recover properly if interrupted and not resumed until after other operations that also affect the environment have been performed. For example, the I/O system should mask IPS signals when modifying IOCBs so that the quit handler will not be invoked to write a message at a time when the I/O system will not work correctly. CONDITION HANDLING Programs should handle conditions that may be signalled because of their operation and pass on all other conditions that they cannot handle better than the default handler. ACCESS ASSUMPTIONS Programs should execute properly under a wide range of access conditions. Access checking and condition handlers can achieve this. Programs using privileged entry points for some functions, but that are also usable by the general user, should be prepared to handle a call by a user with insufficient access. USE OF STANDARD MECHANISMS Programs ought to use the standard mechanisms that are available in the system, not their own. This is important since these mechanisms are provided to permit surroundability and modularity. For example, if a subsystem needs to use a number of temporary segments, it should use the system-provided temporary segment manager, not any other. PATHNAMES AND SEARCH RULES Programs should not have pathnames built into them. The standard search rule mechanism should be used to find other programs and data bases, found through the linker. Commands or subsystems for data segments should use the standard search path facility. The default search paths for a subsystem should be chosen with the general user in mind and for a specific application. 5-2 SECTION 6 PROGRAM FORMAT This section gives guidelines and requirements for the format of programs. Recommendations mostly apply to any source language, but a few are specific to the indicated language. COMMENTS IN PROGRAMS All programs installed in the Multics system must have a set of comments. These comments include a copyright notice to protect the rights of the owners and sponsors of the Multics system, a journalization notice for each installation to record changes, a set of comments describing the interfaces of the program, and comments that help the reader understand the program itself. Copyright Notice Each separately compilable program must have a copyright notice. The copyright notices should be created and modified by the add_copyright command to ensure that all requirements are met. Journalization Notice Each time a program is submitted for installation to the system it must have a comment added that summarizes the reason for the change. These modification history comments should be | generated through use of the history comment command described in | MTB-716. These journalization notices are to be placed after the | copyright notice with the latest notice at the end. If a program is completely rewritten, a note should be made and all previous journalization notices deleted. Similarly, very old notices that no longer serve a useful purpose can be deleted. 6-1 Interface Descriptions Each program that is an internal interface to some portion of the Multics system should have a set of comments, written in MPM style, specifying the interface or calling sequence. (If the program is an external interface that is documented in the MPM or a PLM, no such notice is necessary. A reference to the MPM or PLM volume by name and order number should, however, be included.) Program Comments Each major block of the program has to contain comments describing its function. Comments describing important variables, particularly those whose value have a significant effect on the flow of control through the program, but whose names do not indicate the meaning, should be included. Statement-by-statement comments are discouraged if they give little or no additional information. For example, len = 0; /* set len to zero */ gives no additional information, whereas, len = 0; /* for this case we have a null string */ offers extra information that may aid the reader. Good choice of variable names eliminates the need for excessive commenting. However, if the names chosen are too long, they might not be able to fit on one line and may be hard to read. GENERAL LAYOUT OF A PL/I PROGRAM White space in the form of new pages, tabs and blank lines should separate independent sections of code. A new page should follow: 1. journalization notices 2. local declarations 3. include files Although the following is not a strict rule, a readable program might be formatted as follows: 1. the copyright notice, 6-2 2. a general description of the program followed by the journalization notice, 3. a new page, 4. the main procedure statement, 5. declarations for variables not in include files, 6. a new page, 7. an optional set of include files, 7a. a new page if include files were included, 8. the executable code for the main body of the program, 9. a new page, 10. internal procedures for the program, and 11. another optional set of include files. Declaration statements are to be grouped by storage class or function, and should rarely take up more than one line of code except for structure declarations. Comments should accompany variables whose use may not be obvious. Factoring of attributes should not be done to more than one attribute at a time. Standard Format All PL/I programs must be formatted with the standard | formatting commands,either "formatting_pl1" or "indent". The | format_pl1 command is the preferred formatting command. Programs | should be structured so that subsequent invocations of the standard formatting command, such as by installation procedures, do not destroy the format. ALM PROGRAM CONSIDERATIONS There are conventions which ALM programs should follow. These are: 1. all entry's and segdef's should be at the beginning of the program, 2. use blank lines to separate logical statements, 3. always use include files for references to variables in structured data bases, 6-3 4. segref should not be used (use |[offset]) 5. avoid VFD pseudo-ops if ALM has a cleaner way to define the data, 6. use new pages for subroutines, 7. "declarations" (equ's, temp's etc.) should be at the beginning, 8. the "push" pseudo-op should not be used with an argument, and 9. no IC references should be made when the value is greater than 2. For example: *+3 3,ic are both invalid. 6-4 SECTION 7 INCLUDE FILE FORMAT AND CONSTRAINTS INCLUDE FILE FORMAT The include files used in the Multics Operating System should be in the following form: 1. Header lines (in comments) giving the date the include file was created, dates when it was modified, as well as why, how, and by whom. This journalization comment should be | generated through the use of the history_comment command | described in MTB-716. The header should begin with: | BEGIN INCLUDE FILE xxx.incl.lang where xxx and lang are filled in appropriately. 2. The body of the include file giving declarations (or whatever). All declared variables must be commented. Any strange constructs should be clearly described. 3. The last line of an include file should be of the form: END INCLUDE FILE xxx.incl.lang commented appropriately. 4. Software Protection notices are not to be placed in include | files. | The following constraints apply to the variables and structure of include files: 1. Structures in include files should be based. 7-1 2. If a structure in an include file is based on a particular pointer, that pointer should be declared (without explicit storage class) in the include file. 3. Include files should not contain partial PL/I statements. 4. Include files should be formatted in a manner consistent with the system standards for the language in which they are written. USE OF INCLUDE FILES An include file should be used whenever more than one program references structured data. Include files can also be used to guarantee identical assumptions about naming conventions and systems of encoded values. Include files should not be used to include code that can be referenced by a subroutine call. If an include file exists that describes a given data structure, that include file should be used rather than creating a slightly different one describing the same structure. NAMING INCLUDE FILES The name of an include file is simply: xxxxx.incl.lang where xxxxx is the name used in the "include" statement and lang is the name of the language for which the include file applies. The primary name of the include file (xxxxx) should end in an underscore for externally advertised include files. Include files used by (or supporting use of) a particular subsystem should have names beginning with a prefix which identifies the subsystem. For example: iox_modes.incl.pl1 pl1_stack_frame.incl.pl1 mrds_users.incl.pl1 PL/I AND ALM INCLUDE FILES When a structure or data base is described in both PL/I and ALM include files, the include files are to make reference to each other. Also, the variable names should correspond exactly. 7-2 SECTION 8 PL/I LANGUAGE CONVENTIONS This section highlights the coding rules for system programs that are to be written in the PL/I language. Recommendations for generating efficient code are included. The rules are to be taken as guidelines; there will be rare programs that follow every rule. Refer to "Efficient PL/I Constructs" below. PL/I is the Multics Operating System programming language. However, there are several features in the language which should be avoided either because they are inefficient, they are not implemented well by our compiler, or they lead to complex coding constructs. The following language features should be avoided by subsystem programs: 1. use of PL/I input/output statements 2. aggregate expressions (except for assignment) 3. condition prefixes 4. use of "returns (char (*))" 5. use of the built-in function decat CONSTRAINTS The following list describes some general restrictions and requirements: 1. all variable names have to be declared in a declare statement 2. each reference to a member of a structure must be qualified by the name of the level-one containing structure 3. no compilation warning messages or error messages are allowed 8-1 4. implicit conversions should not be used 5. multiple block closures by an end statement should not be used 6. the default statement should not be used 7. executable statements should be used to initialize automatic variables to make the action more explicit, rather than the initial attribute. 8. no variable names should be the same as keywords in the PL/I language. EFFICIENT PL/I CONSTRUCTS This subsection is an informal guide to efficient use of the Multics PL/I compiler. It provides advice on how to take advantage of the good features of the compiler while avoiding its weaknesses. Emphasis is placed on constructs which produce more efficient code than others. The reader is assumed to be familiar with PL/I. For a semiformal definition of the language supported by the Multics PL/I compiler, see the Multics PL/I Language Specification, Order No. AG94. The Alignment Attributes The use of the aligned attribute and the unaligned attribute can have a great effect on the speed of a program and the size of its data base. Unaligned items can start on a bit boundary (character boundary for character strings, pictures, and decimal variables), aligned items must start on at least a fullword boundary and occupy an integral number of fullwords. If a value requires 72 bits or less of storage to represent it, access of the value will be faster if its generation of storage is aligned because it can be directly loaded into the aq registers. ATTRIBUTES WITH ARITHMETIC AND POINTER VARIABLES Access of aligned binary and pointer variables is usually faster than that of unaligned variables. The only exception to the above is that unaligned pointers that the compiler recognizes as aligned are accessed at speeds comparable to that of aligned pointers, but the former cannot be indirected through. You should use aligned binary and pointer variables for local scalar variables, and only use unaligned binary and pointer variables in 8-2 large data structures where size is important, but speed of access is not. The alignment attribute has no effect on the access time of decimal variables or varying strings. USE OF THE ALIGNMENT ATTRIBUTES WITH SHORT STRINGS A short string is defined to be a nonvarying string with constant extents whose length is less than or equal to 72 bits (eight characters). Access of aligned short strings is usually much faster than that of unaligned short strings. Thus, it is recommended that one use aligned short strings for local scalar variables, and restrict the use of unaligned short strings to large data structures where space is important. USE OF THE ALIGNMENT ATTRIBUTE WITH LONG STRINGS All nonvarying strings that are not short are considered to be long. Because these strings are too long to fit into the aq registers or their length is not known at compile time, the use of the aligned attribute does not speed up their access. It is recommended that one use the default alignment attribute--unaligned. USE OF UNALIGNED SHORT VARIABLES IN ARRAYS AND STRUCTURES For the purposes of this discussion, short variables are those variables which occupy no more than 72 bits (eight characters) of storage and are declared with constant extents. When accessing an element of an array of short unaligned variables, the access code is quicker if a constant subscript is used, because the compiler uses an EIS (Extended Instruction Set) instruction, when the subscript is not constant, in accessing the variable. If an unaligned short variable is contained in an array of structures, and the variable is accessed with a nonconstant subscript, access code is faster if the array is declared aligned, because the use of an EIS instruction is avoided. Use of the Precision Attribute in Offset and Length Expressions Because the Multics CPU's index registers can only hold 18 bits of information, while up to 24 bits may be needed to express the offset or length of a string for use in an EIS instruction, the compiler must make use of the precision attribute in deciding 8-3 which register to use. If a subscript expression, the second or third argument of the substr builtin, or the declared length of a string has a precision of 18 or less, it can be kept in an index register, whereas if the precision is more than 18, it must be kept in the a or q register. This means, for example, that if a user knows that he wants a substring that may be more than 262,143 items long, then the precision of the third argument of substr should reflect that fact (otherwise the high-order bits of the length may be lost). Conversely, if the user knows that a string is less than 262,144 items long, he should reflect that knowledge in the precision used for subscripts and arguments to substr. (Besides looking at the precision of the length and offset expressions, the compiler also makes use of the declared string size in cases of constant extents to determine where the offset or length may be kept.) The general guideline is to always declare variables with the correct precision. The following precisions are guidelines when a user is not sure a smaller precision will suffice. A word offset into a segment should be declared fixed bin(18). A number of words on a segment should be declared fixed bin(19). Character string indexes and lengths should be declared fixed bin(21). Bit string indexes and lengths should be declared fixed bin(24). The Use of Internal Static to Simulate Named Constants If a variable is declared to be internal static with an initial attribute and is never set within a program, the compiler will treat it as if it were a constant. (A variable is | considered set if it appears in a context in which its value | could change.) Converting an internal static variable to a constant means that more efficient code will often be generated to use the variable, sometimes avoiding storage references, and that the variable will not have to be copied into the combined linkage section upon initiation of the segment. Since passing a | variable as an argument by reference is a set context, one must enclose the variable in parentheses if it is to appear in an argument list. This will make the variable be passed by value and force a copy to be made at call time. The options(constant) attribute may be used to tell the compiler that the variable is not set even if passed as an argument. Making sure that such an internal static variable, which the user intends to use as a constant, is considered by the compiler to be a constant is worthwhile if the variable is not a long string which is only used in a few calls. This feature of the compiler is a good substitute for named constants which the PL/I language generally does not provide. When "options(constant)" is added to the declaration of an 8-4 internal static initialed variable, the variable is allocated in the text section whether or not it is set or passed as an argument. The user is responsible for ensuring that the variable is not actually set, however, as this would cause faults or other errors. Use of the Initial Attribute The compiler's implementation of the initial attribute for automatic, based, and controlled arrays is inefficient compared with the code the user can get from explicit assignment statements. Therefore, using the initial attribute in the above cases is discouraged. Since the use of the initial attribute does not generate code for static variables, the above statement does not apply in that case. Users are warned, however, that use of the initial attribute can make a program more difficult to read in some cases, and that initialization of large external static arrays this way can cause creation of a larger object segment than intended. The Assignment Operation THE MULTIPLE ASSIGNMENT STATEMENT In deciding whether or not to use a multiple assignment statement rather than separate assignment statements, it is useful to know under which circumstances multiple assignment statements produce inefficient code. A multiple assignment statement of the form: T1, T2, ---, Tn = E; where E is not a constant, is semantically equivalent to the separate statements: V = E; T1 = V; T2 = V; . . . Tn = V; 8-5 If the temporary represented by V can be kept in a machine register throughout the assignment, then the multiple assignment statement is efficient. Clearly, this implies that if E is longer than two words, the multiple assignment statement will not be efficient, since E cannot fit in a register. Thus, multiple assignment statements are not efficient when the right hand side is a long string, a varying string, an entry value, a label value, a file value, a format value, an area, a decimal value, a complex value, or an aggregate. CONVERSIONS All of the PL/I conversions are efficient, many of them producing inline code, while the others produce calls to any_to_any_. Inline code is produced for all cases where neither the source nor target are complex, decimal, character string, or picture (see the discussion of pictures below). Of the other cases, the following produces inline code: complex_float binary (precision<27) = real binary; real binary = complex_float binary (precision<27); real decimal = real decimal; complex decimal = complex decimal; real binary integer = real decimal; real decimal = real binary integer; character = real fixed decimal; character = real binary integer; All other cases produce calls to any_to_any_. The convert builtin function can be used to effect conversion between character and binary and to avoid intermediate conversions that other builtins might cause. PICTURES The use of pictures provides a convenient way to get efficient controlled conversion between arithmetic and character. When using pictures, the user can avoid PL/I's inconvenient conversion rules by specifying the desired format. 8-6 While picture unpacking (going from character to arithmetic form) is done by pl1_operators_, the most common cases of picture editing (going from arithmetic to character form) are done inline. Inline code is generated for the majority of cases of editing into real fixed pictures. The cases of editing into real fixed pictures that is done by pl1_operators_ are any of the following: o the absolute value of the number's scale is greater than 31 o a "y" picture character appears in a drifting field picture (e.g., $$$y99) o a zero suppression character or drifting character appears to the right of the "v" picture character o the inline sequence requires more than 63 micro-ops for the MVNE instruction ARITHMETIC OPERATIONS Most arithmetic operations are implemented with fast inline code. The one general exception is the power operator (e.g. **) which is sometimes implemented by pl1_operators_ or subroutine calls. Users are cautioned against using the "/" operator with fixed point operands as the PL/I precision rules may cause unexpected results. Use the divide builtin function instead. BINARY OPERATIONS Most binary arithmetic operations produce inline code. Multiplication of fixed binary (precision>36) numbers utilizes pl1_operators_ references, all fixed binary division invoked by the "/" operator causes references to slow pl1_operators_ routines. The "**" operation generates pl1_operators_ calls for real operands and full subroutine calls for complex operands. If the operands are both real, and the second operand is a positive integer constant that could be represented as a fixed bin(35) value, inline code will be generated to do the power operation as repeated multiplications. DECIMAL OPERATIONS Most decimal arithmetic operations cause efficient inline code to be generated. The major exception is the case of one or both of the operands having a scale greater than 32 or less than -31. This case will often cause additional assignments or 8-7 multiplications to be generated since the 6180 hardware only handles scales within the range -31 to 32. If the power operator has decimal operands, a conversion to and from binary and/or a subroutine call will be generated. String Operations All string operations (as opposed to builtins) cause inline code to be generated. In addition, some special cases cause better than usual code to be generated. SPECIAL CASE OF CONCATENATION Concatenation is often used in constructing varying strings. A normal concatenation of the form: a = b || c; results in three (3) moves -- b and c are moved into a temporary, and the result is moved into a. However, a concatenation of the form: vs = vs || c; where vs is a varying string, results in just one move -- c is moved to the end of vs. The latter special case can be used to great advantage in building varying strings. Consider the following example: vs = a || b || c; results in four moves and perhaps some instructions to allocate temporaries, while: vs = a; vs = vs || b; vs = vs || c; results in three moves with no temporaries allocated. OPERATIONS ON LONG STRINGS Most statements of the form: a = b c; 8-8 a = translate (b,...); a = bool (b,c,); where a, b, and c are long nonvarying strings, cause code to be generated that performs the operation in a temporary and then moves the result into a. However, if a is the same length as the temporary would be, and if the compiler believes that a could not possibly overlap with b or c, then the operation will be performed directly in a and no temporary will be allocated. In a statement of the form: if a b ... or if bool (a, b, ) ... where a and b are long strings, the compiler will attempt to do the operation without allocating a temporary, by using an SZTL instruction if the value is not needed elsewhere. AGGREGATE OPERATIONS Most aggregate operations, other than simple assignment and the use of the string and unspec builtins and pseudovariables, are relatively inefficient in the present Multics PL/I implementation and should be avoided. By simple, assignment, we mean assignment statements of the form: p -> aggregate = q -> aggregate; Use of the Builtin Functions Most of the standard PL/I builtin functions and pseudovariables are implemented efficiently in the Multics compiler. However, there are exceptions and special cases. ARITHMETIC BUILTINS With the exception of the divide builtin, all the arithmetic builtins cause efficient code to be generated. The divide builtin is inefficient only for some cases in which a fixed binary result is produced. If a fixed binary result is produced, a reference to a very slow pl1_operators_ divide routine is generated unless the result and both operands are unscaled with a precision less than or equal to 35. 8-9 STRING BUILTINS Efficient inline or out-of-line code is generated for all but one string builtin, decat. Execution of the decat builtin is about 50 times slower than might be expected. There are special cases of some of the other string builtins that cause more efficient code to be generated than is normally generated for the general case. These are: index (, ) index (, ) index (reverse(), ) index (reverse(), ) index (reverse(), reverse()) search (, ) verify (, ) search (, ) verify (, ) search (reverse(), ) verify (reverse(), ) translate (, [,]) before (, ) before (, ) after (, ) after (, ) ltrim (, ) rtrim (, ) copy (, expression) 8-10 MATHEMATICAL BUILTINS References to the mathematical builtin functions are compiled either into fast references to pl1_operators_ or into slower subroutine calls. The following math builtins are implemented in pl1_operators_ if they have real arguments: atan exp sin tand atand log sind cos log10 sqrt cosd log2 tan All other cases produce subroutine calls. The Call Statement and Function References When a call statement or function reference is executed, in the general case, an argument list must be constructed which takes 3 + 2*number_of_arguments words. When the new procedure block is entered, a new stack frame is established by a pl1_operators_ routine that takes around 30 instructions. This is a high overhead to have when using an important feature of PL/I that is necessary for good programming practice. The Multics system PL/I compiler has two optimizations which can greatly reduce this overhead. First, it can decide that an internal procedure or begin block may share the stack frame of another block rather than obtaining its own. A block that does not obtain its own stack frame is called a "quick" block or procedure. Second, the compiler can build argument lists to quick procedures at compile time, if the arguments have constant addresses known at compile time. These two optimizations greatly reduce the cost of call statements and function references. DETERMINING THE 'QUICKNESS' OF A BLOCK The Multics PL/I compiler goes through a two stage process to determine which (procedure or begin) blocks can be quick, that is, which ones need not obtain stack frames. The first stage excludes blocks from being quick because of their properties. The following properties can make a block non-quick. o it is the external procedure block o it is an ON-unit o it has I/O statements o it has format statements 8-11 o it has ON, or revert statements o it has automatic variables with expression extents o it has an entry that is assigned to an entry variable or passed as an argument o it has an entry with a star-extent return value o it has an entry with a star-extent parameter that is called with the corresponding argument being an expression whose length is non-constant o it has an entry that is referenced in the argument list of such a call after the aforementioned argument In the second stage, the compiler uses a graph of the calls between blocks, to determine which of the remaining eligible blocks can be quick. The algorithm used in this stage is an iterative one based on the constraint that a quick block may use the stack frame of one and only one non-quick block and thus may effectively be invoked from only one non-quick block. In fact, the algorithm states that a quick block may be invoked from only one stack frame, and an invocation from a quick block is considered an invocation from its owner's stack frame. A user can determine which blocks have been made quick by examining the symbols listing produced by the compiler. In the section marked, "STORAGE REQUIREMENTS FOR THIS PROGRAM" is a list of all the blocks in the program. If the line for a particular block contains the words, "shares stack frame of", that block is quick. USING CONSTANT ARGUMENT LISTS In generating a quick procedure call, the Multics PL/I compiler can often generate a constant argument list if the addresses of the arguments are known at compile time. This saves the cost of executing instructions to set up the argument list at runtime. At this time the following constraints must be satisfied for the compiler to generate a constant argument list: o the quick procedure must contain no non-quick blocks o the stack frame of the caller must be smaller than 16,384 words o the arguments must be constants, expressions with operators, builtin references, function references, or automatic variables 8-12 o all automatic arguments must be allocated in the stack frame of the caller o all automatic arguments must have constant extents o all subscripted arguments must have constant subscripts Using If Statements In handling if statements containing logical operators, such as: if x = 0 | p ^= null | x + 33 & q = null & loaded then call b; the Multics system PL/I compiler (as of MR4.0) attempts to generate code that uses the minimum number of operations to decide the result. This is a change from previous releases of the compiler that always evaluated the complete expression in the if statement. In order for this optimization to take place, the user must specify the -optimize control argument for the compilation, there must be no irreducible function references in the expression, and the expression must evaluate to a bit(1) value. Thus a user should feel free to use logical operators in if statements without worrying about their efficiency. NOTE: no program may depend on the order of evaluation of operands in the expression of an if statement. Thus, the statement: if p ^= null & p -> q = 0 then ... is illegal Any program that depends on complete or incomplete evaluation of such an expression is in error, unless the expression contains irreducible function references, in which case complete evaluation takes place. Optimization of Comparisons The Multics system PL/I compiler (as of MR4.0) remembers in its abstract machine state model the most recent comparison or indicator setting operation at any particular point in time in generating object code. This enables it to remove redundant comparisons in constructs such as the following: if a", and entrynames must not. Gate targets and trusted servers should always ensure that parameters are within the valid domain, so that later array references, arithmetic or other uses do not have unexpected, invalid results. o Security Auditing All gate targets and trusted applications must audit security-related operations. The interfaces for security auditing are maintained in MDD-011, "Security Auditing". Audit suppression is permitted only if ring 1 is auditing more abstract operations of which the ring 0 operations are parts. THE RING MODEL Multics depends on the ring model to assure system security and integrity. Rings are the system's primary integrity mechanism; they protect system databases that are shared between processes from modification by users.(1) Enforcement of the ring model depends on the correct function of the processor hardware, gate target software, and trusted servers. All three of these must make ring checks. Hardware ring checks The processor hardware makes the most fundamental ring checks. It is responsible for insuring that processes cannot read and write segments except as permitted by the ring model, and for correctly adjusting pointer register ring numbers on calls to gates. For complete details on processor ring enforcement, see The Multics Processor Manual, Order No. AL39. RING OF EXECUTION The processor maintains a current ring of execution. This can only be changed by a CALL6 call of a gate, that reduces it, and by an RTCD through a pointer with a larger ring number. The processor uses this ring number to validate read, write, and call references to data in segments.(2) _________________________________________________________________ (1) See section 6 of the Multics Reference Guide, Order No. AG91 for a complete explanation of the ring model. Also see various papers by Biba on the subject of integrity. (2) These operations are described in detail in section 6 of AG91. 13-3 RING NUMBERS IN POINTERS Each stored pointer includes a ring number. In the ring model, this represents the ring of execution of the program that created the pointer. When an inner ring program references through a pointer, the maximum of ring stored in the pointer, the write ring of the segment containing the pointer, and the current ring of execution is used as the effective ring of reference. (Packed pointers are an exception since they have contain no ring number. This is discussed later.) When a pointer reference is used to load a pointer register, the calculated ring of reference is maintained in the pointer register. If the pointer register is stored, the ring number in the pointer register is used to fill in the stored pointer ring number. Furthermore, when a CALL6 instruction is used to call a gate to an inner ring, the ring numbers in all of the pointer registers are adjusted to be at least as large as the calling ring of execution. Since the outer ring cannot store pointers in inner ring segments, any time that an inner ring program references through an outer ring pointer the effective ring of execution will be at least the outer ring's number. There are some circumstances in which gate target programs carefully construct copies of outer ring pointers which have inner ring ring numbers. This is a technique that should only be used when the program is absolutely sure, for other reasons, that no user-constructed pointer can cause it to reference data unintentionally. That is, it must positively verify that whatever accesses it makes with the constructed pointer are in fact valid given the validation level and authorization of the calling user. Any such use must be copiously commented in the source to avoid errors in the initial implementation or later maintenance. EXAMPLES OF HARDWARE RING CHECKS A user program could attempt to provoke an inner ring into referencing an inner ring segment. It would construct a pointer that had the directory's segment number as its segment number, and zero as its ring number. It could leave the pointer in a pointer register (for example, PR0, used to point to the argument list), or store it in a segment (for example, in a pointer in an argument list). If the user program puts such a pointer in a pointer register and calls ring zero, the ring number is set to the user's ring by the CALL6 instruction. When ring zero referenced 13-4 through the pointer register, that ring number is compared to the ring brackets of (0,0,0), and the access is denied. If the user program stores the pointer in a segment, it has to be a segment whose write ring is at least the user's ring of execution. A ring 4 user, for example, can only write into segments whose write ring is 4 or larger. When the user calls ring zero, and ring zero indirects through the pointer, the hardware will compare the write bracket of the segment (4 or bigger) to the ring number stored in the stored pointer. The larger (4) will replace the smaller (0) as the effective ring of reference, and the access will be denied. Note, though, that if ring zero manages to load the pointer into a pointer register without indirecting through it, the access will be permitted. In particular, if ring zero copies the pointer to the stack with ordinary instructions such as LDAQ and STAQ instead of using EPPn and SPRIn, it will circumvent the ring hardware. The PL/I compiler always uses the correct instructions to copy pointers that are declared as such. There is one other possible pathway that the hardware interdicts. A ring 4 user could try to make ring zero modify a ring 1 segment by passing a constructed pointer to it to ring 1, knowing that ring 1 will copy the pointer into ring 1 storage (i.e., the ring 1 stack) and then pass it to ring zero. However, when ring 1 loads the pointer with EPPn, the write bracket of the segment (4 or larger) will be the effective ring of reference, and will be loaded into the pointer register ring number. When the pointer register is stored in the ring 1 stack, the stored ring number will thus be 4 or larger. When ring zero references through the pointer, the 4 stored in the pointer will take precedence over the write bracket of the stack segment (1), and become the effective ring of reference. The hardware will deny the access, since 4 is larger than the write bracket of the target segment (1). Software ring checks -- the validation level The hardware checks summarized above enforce the ring model for direct references to data. They protect inner ring data from direct modification by outer ring programs, and protect inner ring programs from being "spoofed" by pointers constructed by outer ring programs. However, many inner ring operations cannot be controlled at the level of permitting or denying access to an entire segment. For example, directories are (0,0,0) segments. No program calling ring zero from a higher ring could ever pass a pointer parameter through which ring zero could reference the contents of directory segments. 13-5 A software mechanism, the validation level, is used to enforce the ring model for operations more complex than reading and writing data in segments. The validation level determines the effective ring of reference for software-defined operations. For example, when a user calls directory control to set the maximum length of a segment, directory control checks that the validation level is less than or equal to the write ring of the segment. The validation level is referenced via calls to cu_$level_get (level$get in ring 0), and changed via calls to cu_$level_set (level$set in ring zero). It may be set no lower than the current ring of execution. An attempt to set it lower produces an validation_level_error signal. A gate target, when called, assumes that the validation level represents the ring of its caller. It must use that value when making access checks on behalf of its caller. If an inner ring program performs its function by calling gates inside its ring of execution to manipulate objects in its ring of execution, the program must change the validation level to its ring of execution. Programs that lower the validation level must do so for small stretches of code whenever possible. They must have a cleanup handler to restore the validation level. Note that the system will automatically correct the validation level on return or crawlout from the inner ring if the inner ring program fails to do so using the ring alarm fault mechanism. But this is expensive and should be avoided. For example, consider the mailbox_ gate. When a user calls the mailbox_ gate, the message segment primitives must check access on behalf of the caller validation level. To perform the operation, though, they must lower the validation level to 1. When a user executing with a validation level of 4 calls mailbox_$delete, the message segment primitives check to ensure that the user has access to delete the mailbox: for example, that the modify bracket of the directory is 4 or greater. Then, they must change the validation level to 1 before calling hcs_$delentry_file to actually delete the segment. Since the segment is (1,1,1), ring zero directory control requires the validation level to be 1 or 0 to allow deletion. 13-6 GATE PARAMETERS: SECURITY CONSIDERATIONS Gate interfaces are the most sensitive areas of the system. Users pass gates arbitrary argument lists. They may pass unexpected parameter values or even invalid argument lists. Failure to follow the rules for coding gate targets can leave a penetration opportunity for a user to violate security, or crash the system. In some cases, the user can obtain complete control of the bootload. Following the rules below is essential to maintain system security and integrity. Naming Conventions for Gate Parameters Many of the coding standards for gate targets apply specifically to the handling of the formal parameters of gate target entrypoints. Therefore, programmers are required to give these variables names that are easily distinguished from all other variables. This permits auditors and programmers to verify that the special rules for gate parameters are in fact followed by a particular program. A uniform prefix naming convention must be used for all variables that are formal parameters of gate targets. There are three such naming conventions in use. In most of the hardcore, the prefix "a_" on a variable name indicates that the variable is a formal parameter. In other programs, the prefix "P_" indicates a formal parameter. Finally, in yet other programs, the capitalization of the first letter of the variable name indicates a formal parameter. o When modifying existing gate targets, the existing convention must be followed. o When creating new gate targets, one of the existing three conventions must be used. o In both cases, no variables other than formal parameters may be named according to the parameter naming convention. Rules for gate parameters -- forbidden reference patterns The hardware pointer ring number features described above prevent users from constructing ITS or ITP pointers that fool inner rings into reading or writing data that the user cannot read and write. However, there are a series of other possible user manipulations of parameters that can be used to cause incorrectly coded inner ring programs to malfunction. Parameters in user-controlled storage can change at any time, due to modifications by other processes. If an inner ring checks a 13-7 parameter for validity, and then later uses the same copy of the parameter again, the value may have changed to an invalid value. In brief, the following holds: GATE TARGETS MAY READ EACH PARAMETER ONCE AND WRITE EACH PARAMETER ONCE The following subsections provide details of and reasons for this restriction. MULTIPLE PARAMETER READ A parameter value that is read more than once can change between the two reads. A decision based on the first reference can be rendered invalid by the change, resulting in incorrect behavior. This is usually the most serious type of parameter reference error. PARAMETER WRITE, THEN READ If a parameter is written and then read, the value can be changed after the write, but before the read. If the subroutine makes a decision based on the value read, expecting it to be the same as was just written, it will behave incorrectly. This is the second most serious type of error; a common example is the status code parameter to many entrypoints. MULTIPLE PARAMETER WRITE A parameter value that is written more than once may result in providing information that should not be released. For instance, if a status code parameter is set once, and then later "censored" so that it will be less informative, it would be possible to intercept the first value and learn something that should not have been released. This is the least serious type of error. Note that this description does not apply to output parameters that are initialized to some known blank, null, or invalid value at the beginning, and later filled in with the real result, since this does not give away any information, but rather is provided as a convenience for the caller. 13-8 PASSING PARAMETER TO ANOTHER SUBROUTINE Passing any parameter directly to another subroutine, internal or external, is automatically counted both as multiple reads and multiple writes. While this is not actually true in all cases, it is unreasonable to have to inspect each subroutine's logic to ensure that it, the recipient of the parameter, also references the parameter only once. PARAMETERS IN EXPRESSIONS Use of a parameter in an arithmetic or logical expression is automatically counted as multiple reads. Again, while this is not strictly true, it is unreasonable to inspect the logic of the subroutine to ensure that the parameter is, in fact, referenced only once by the generated code. This does not apply to simple data conversions, substrings, and the like, which are equivalent to plain assignments. PACKED POINTER PARAMETERS Packed pointers do not include a ring number. If a packed pointer was passed through a gate, the outer ring could construct it to point to anything within the ring of execution of the inner ring program and the inner ring program would reference it. Packed pointers may not be used as gate parameters. IMPROPER REFERENCE TO STRUCTURE PARAMETERS All of the above restrictions apply to each of the elements of a structure pointed to by a pointer passed as a formal parameter. First, the gate target must copy the pointer. Then, each of the elements in the structure, including refer-extent bounds, must be referenced so as to respect the rules above. Further, structures that contain pointers may not be copied via structure assignment or use of the "unspec" builtin. Such copying circumvents the pointer ring number features of the hardware. Finally, structures may not be passed as formal parameters. First of all, the use of structure parameters is a non-standard Multics extension of PL/I. Secondly, the compiler does not guarantee correct references to structure parameters. The compiler may violate the parameter reference rules even while copying a structure parameter to an automatic copy. 13-9 WHEN SHOULD TCB MODULES GENERATE AN AUDIT TRAIL o At the time an access decision is made. An audit message is to be generated whether access is granted or denied. This includes decisions with respect to objects or facilities. o When objects are created or destroyed. Whenever a TCB supported object is created or deleted an audit message shall be generated. This includes objects such as segments, directories, message segments entries, RCP resources, processes, etc. o When security parameters are changed. The most obvious examples of this are the system-wide audit flags and thresholds, the per-process audit flags, per-process AIM privileges, reclassification of TCB supported objects, etc. o At the time some object is made accessible for use by a process and at the time it is made inaccessible. Some examples are: Object made accessible Object made inaccessible ---------------------- ------------------------ initiate a segment terminate a segment attach a volume detach a volume (This generates audit messages which bracket the time interval within which the object was in use by a process.) Information that is Necessary The TCB module must supply a number of data items to the access_audit_* routine. Thus, the TCB module must be structured in such a way that this data is available at the time access_audit_* is to be called. module name entry name of caller process validation level level at which request was made status whether the operation was granted or denied administrative operation whether the opeation was administrative in nature e.g. PNT updates, PDT installs, etc. privileged operation privileged gate entry or AIM privilege invoked covert channel operation is the operation potentially useful as a covert channel? 13-10 what is the bandwidth? is process a receiver or a transmitter? (see Covert Channel Analysis Report) access_operations_ entry see access_operations_.alm for entry which describes the operation (may need new one defined) name of object pathname of file system object, type and name of RCP resource, name of PNT entry, etc. access class of object AIM label of object being operated upon system status code optional value of error_table_ entry pertinent to the operation (usually upon denials) added info an ioa_ control string and optional arguments for insertion. This may be any additional information pertinent to the operation. user info for proxy operations the user_id, authorization, min and max authorization, validation_level, process_id, and process audit flags of the requesting process must be supplied (this is all available in message segment entries typically used for daemon requests) TRUSTED SERVER INTERFACES Trusted servers must be careful to make all access checks on behalf of the submitter of the request. hcs_$get_user_access_modes (or its equivalent) must be used to enforce all discretionary access control restrictions. In addition, mandatory (AIM) access checks must be imposed, as well. Note that none of the standard AIM comparison subroutines (aim_check_, read_allowed_, etc.) implement AIM system privileges. To implement privileges, the trusted server must extract the privileges from the requester via aim_util_$get_privileges and permit operations as appropriate. Note that all checks for particular privileges must be made via references to sys_info$XXXX_privilege so that they can be found in the cross reference. RING 1 CIRCUMVENTION OF AIM POLICIES Ring 1 programs are permitted to temporarily set system privileges and to suppress security auditing by ring 0. These services are requested by calls to entrypoints in admin_gate_. Ring 1 programs may make these calls if and only if they are performing the necessary access checks or auditing (or both) themselves. Privilege setting is permitted to implement complex multiclass subsystems that require multiple segments or other privileged operations. Ring one privilege settings must use the 13-11 sys_info$XXXX_privilege variables to specify privileges so that they show up in the cross reference. In all cases, ring 1 subsystems must continue to enforce system security policies as seen by outer ring users. PRIVILEGED EXEC_COMS THAT WALK THE HIERARCHY Exec_coms that walk the hierarchy and are run from privileged processes must be careful to ensure that all pathnames are requoted. Otherwise, user pathnames containing command processor special characters can be executed. For example, an entry name of "a;dd >sc1 -force", if not requoted, will be rescanned and will result in the execution of the delete_dir command in the privileged process. SYSTEM ERROR MESSAGE DOCUMENTATION All Multics system messages are documented in special comments at the end of the sources of the programs that generate them. These comments are processed once per release by a set of tools that collate them into an alphabetic listing by message text. What messages should be documented For the purposes of message documentation, system messages are those produced by calls to the following: o syserr$*, admin_gate_$syserr_*, hphcs_$syserr_* o sys_log_$*, except for the entrypoints containing the string "command" Any module that calls any of these subroutines must contain message documentation for the calls. Standard security audit messages are generated by calling access_audit_$*, access_audit_r1_$*, access_audit_gate_$*, or as_access_audit_$* entries. Although these are actually system log messages they are not to be documented within these modules nor their callers. Unlike messages logged via syserr or sys_log_ they hold a strictly enforced format. General documentation of security audit messages is available in the System Administration Procedures manual, Order No. AK50. This documentation must be updated whenever: new entries are added to the 13-12 access_operations_ table; new detailed operation codes are added; or when the possible set of "added_info" to audit messages is changed. (The standard format audit messages reserve a free-form field (called "added_info") which is supplied by the caller of access_audit_). How to document them Message documentation has the following form in PL/I sources: /* BEGIN MESSAGE DOCUMENTATION Message: activate: double uid UID. vtocx VTOCX1 on dskX_MM. vtocx VTOCX2 on dskY_QQ. S: $log T: $run M: A mismatch has been detected between the branch and the ASTE for a segment. The two segments indicated by VTOCE index and physical volume name claim to have the same file system unique identifier. A connection failure is returned to the user process. This message is logged for the use of system programmers. This error can occur if damage to a directory branch has caused its unique ID to become incorrect, and if the incorrect unique ID happens to be identical to the unique ID of a segment already active. A: $inform ... etc. ... END MESSAGE DOCUMENTATION */ In ALM sources, all lines of message documentation have a " in column 1, and no /*, */ delimiters. Otherwise, the format is the same as for PL/I. If there are multiple messages for a particular source, they are all contained within a single BEGIN and END set, and seperated by two blank lines. Each message is built of the several parts. For all except the first, there are special abbreviations that begin by "$" that expand into frequently used strings. 13-13 o Message: (The message text) The message text is terminated by a blank line. The message text should be the actual text logged and/or printed, verbatim. In the case of access_audit_ messages, the text from the access_operation_ entry should be included. Variable fields in the message text should be replaced by strings of capital letters which are defined in the "M:" section. o S: (Stream) This is the location where the message appears. Normally, this should be set to one of the standard values. The following standard values are used for syserr and access_audit_ messages: $beep System Console (sounds beeper) $beeper System Console (sounds beeper) $crash System Console (Crashes system) $info System Console. $log Logged in SYSERR log. $term System console (Terminates user process) The following standard values are used for calls to sys_log_: as (severity0) Severity zero AS messages: in AS log. as (severity1) Severity one AS messages: in AS log and printed on an AS console. as (severity2) Severity two AS messages: in AS log and printed on an AS console, with bells and asterisks. o T: (Time) This is the state of the system at time the message is generated. The following standard values are defined: $dskr During disk rebuilding. $init System Intialization. $reload During volume reloading. $run While system is running. 13-14 $shut System shutdown. o M: (Meaning) This is a detailed interpretation of the message. There are two standard values defined. In addition, it is almost always neccessary to add other text. $crash, $crashes This error crashes the system. $err This indicates a logic error in the supervisor, or CPU or memory hardware problems. o A: (Action) This is the appropriate action to be taken by site personnel on encountering this message. The following standard values are defined: $boot_tape The Multics System Tape may be incorrect. If the problem persists, try another MST. $contact Contact the system programming staff. $contact_sa Contact the system administrator. $ignore No operator action is required. $inform Contact the system programming staff. $inform_sa Contact the system administrator. $inform_ssa Contact the system security administrator. $note Note for system programmer action. $notify Contact the system programming staff. $notify_sa Contact the system administrator. $recover Follow normal recovery procedures. In the text of messages and explanations, the following compose controls are accepted: .inl, .spf, and .unl. COMMENTARY IN PROGRAMS AND INCLUDE FILES The Criteria require design documentation for the entire TCB. Design documentation for Multics is made up of two parts: Multics Design Documents (MDDs), and commentary in the code and include files. Standards for Multics Design Documents are 13-15 provided in Section 14 of this document. Standards for commentary are provided here. Commentary in Source In general, Multics programs should be commented so as to be understandable. This is a requirement for the entire system. For the TCB in particular, the following additional requirements apply: All internal entrypoints of the TCB must be completely described in comments. The comments must give the calling sequence and parameter descriptions. This requirement is only applied to internal entrypoints because all external entrypoints (those callable from outside of the TCB) are documented in subroutine descriptions maintained under configuration management. All include files describing data structures used in the TCB must be commented in detail. The comments must explain each item, not merely restate its name. 13-16 SECTION 14 WRITING AND UPDATING MULTICS DESIGN DOCUMENTS The Criteria require design documentation for the entire TCB. Design documentation for Multics is made up of two parts: Multics Design Documents (MDDs), and commentary in the code and include files. Standards for code and include files are described in Section 13 of this document. Standards for Multics Design Documents are provided here. Multics Design Documents are internal documents of Multics development, created and maintained by developers. Their purpose is to describe the design structure of the TCB, so that developers and security evaluators can understand it. Each MDD describes a subsystem or area of the system. MDDs are maintained under change control via configuration management. When developers make changes to the design of the system, they update MDDs and submit the updated versions for installation along with the code. For more information on this process, see MAB-066, "Configuration Management: Software Development Procedures". CONTENT OF AN MDD MDDs are not intended to be line-by-line guided tours of all of the programs of the Multics TCB. Such documents would be difficult to produce and impossible to maintain. Instead, MDDs take up where the commentary in the code leaves off, providing the higher level description of code structure, policy and strategy. Each MDD is structured in a common format. There is a title page, a revision history, and a table of contents. The remainder of the document is divided into sections. The first section is always an introduction to the subsystem, describing its functions and roles in the system. The second section always describes the security relevant features of the subsystem, if any. This includes the security policy implemented and the basic design strategies for implementing it. The remaining sections describe 14-1 the design of the subsystem. The design discussion will usually stay at the level of interactions between source modules. When a source module has a particularly important or complex strategy for actually implemementing its function, it is described in detail. Generally, though, the internal design of modules is left to the commentary. THE FORMAT OF AN MDD MDDs are formatted very closely to the standard format used for published manuals. They are written using compose, and use installed compose macros. This permits developers to update MDDs written by other developers. Detailed instructions for formatting an MDD can be found in two places. First, the Terminal Operator's Manual maintained by the Documentation Unit describes the standard compose macros. Second, a template MDD is kept in the online hierarchy (>security>documentation>mdd) that can be expanded to produce a new MDD. 14-2 SECTION 15 CODING STANDARDS FOR B2 FUNCTIONAL TESTS AND UTILITIES Following are the standards for coding B2 functional tests and utilities. These standards are supplementary to the other Multics coding standards in this MAB (e.g., modules compile without warning or errors, cleanup handlers work). This is not a tutorial on writing B2 functional test programs; it is a summary of the standards and should be used in conjunction with MAB-069, "Multics Configuration Management: Guidelines for Auditing Software." It is assumed the reader is familiar MDD-004 ("Functional Test Software") and MDD-014 ("Security Auditing"). In addition, creators and auditors of a functional test module should be familiar with the MDD describing the part of the system being tested (see MDD-001, "Overview and Index of Multics Design Documents"). There are two major types of functional testing modules: tests and utilities. Standards which apply to both types of modules are described first, followed by standards specific to each type. A main concern in writing functional tests is the audience who will read the test programs. These persons are not necessarily PL/I programmers (and thus, not Multics System Programmers). Therefore, programs associated with functional testing must be written as clearly as possible. Of primary importance is that the test programs themselves be very simple and exhibit similar appearance and structure. GENERAL STANDARDS This section describes program attributes which apply to both test programs and utilities. 15-1 o All modules are considered Honeywell proprietary. To do this, use the following command on each source file: add_pnotice PATH -trade_secret o All modules must use the same PL/I source format. The required format_pl1 control is "format: style4,indattr". o All internal procedures should begin on a new page. o All errors shall be reported via the sub_err_ subroutine. If the error happens in Sectest_Server.SysDaemon's process, the sub_err_ call will be automatically transferred to the test process by the daemon interface (i.e., st_process_daemon_request_). These calls to sub_err_ are not expected to happen and indicate either a system problem or failure of a functional test. o All cleanup and any setup should be implemented as internal procedures. o All include files should appear at the end of the program. o Declarations of identifiers should be grouped by the general classes of "Parameter", "Automatic", "Based", "External", "Entries", "Static", and "Misc"; each group should be labeled with a comment. Identifiers should be in alphabetical order within these groups. o Parameter names for external entrypoints must be prefixed with "P_". All parameter declarations must explicitly include the "parameter" attribute. It is recommended all general classes of identifiers explicitly include the class attribute (e.g., automatic, static, etc.) in their declarations. o Names of labels and constants should be in upper case. It is strongly recommended internal procedure names also be in upper case. TEST PROGRAM STANDARDS o Test program names will be constructed from the gate and entry being tested, as in: {GATE}_{ENTRY}_[dac | mac] For example, hcs_fs_get_mode_dac.pl1 and hcs_fs_get_mode_mac.pl1 test the hcs_$fs_get_mode gate entry in the DAC and MAC cases. Test programs may not combine DAC and MAC testing. 15-2 Those gates whose names are longer than three or four characters will be assigned an alias to be used for this naming convention (e.g., test programs for the message_segment_ gate are named ms_{ENTRY}_[dac | mac]). o Each test program will exhibit a comment header of the form: FEATURE: GATE$ENTRY SECURITY PROPERTY: (MAC DAC AUDIT LABEL I&A) TEST CASE DESCRIPTIONS: 1) (environment description) (desired system response "GRANT" or "DENY") NOTES: (exceptions, etc.) HISTORY: (date who what) o Test modules are to be constructed with setup, run, and cleanup internal procedures to execute the test cases. These procedures are to be called by the utilities tu_$map_over_DAC_cases, tu_$map_over_MAC_cases, and tu_$map_over_MAC_range_cases (as appropriate). This mechanism eliminates the need for test case definition and table programming, and thus some opportunity for error. Also, new test cases may be added to a whole set of test programs simply by changing these utilities. Should the above approach not be suitable for a particular test program, it should at least be driven by an internal table of test cases. This table contains, for each case, environment setup information and expected results. Internal routines for setup, run, check, and cleanup should be defined for use as follows (note: the calls below are not limited to just a case_index parameter depending on the test case): . . call GENERAL_SETUP (); do case_index = lbound (test_defs) to hbound (test_defs); call CASE_SETUP (case_index); call CASE_RUN (case_index); call CHECK_CASE_RESULTS (case_index); call CASE_CLEAN_UP (case_index); end; call GENERAL_CLEAN_UP (); 15-3 . . o Test cases will be coded without dependencies on previous test cases. This is done so it will be easy to later implement running a single test case or adding new cases. Each test case is responsible for leaving the system in the same state as it was when the test started. Flags should be set for the cleanup handler to work properly. o It is the responsibility of the test to call any utilities to undo any setup done by a utility call in normal operation (e.g., de-register a resource, demount a logical volume). The GENERAL_CLEAN_UP procedure is to also be called before normal exit from the test program. An example: seg_created = "0"b; /* not done */ on cleanup call GENERAL_CLEAN_UP (); call GENERAL_SETUP (); . . call GENERAL_CLEAN_UP (); return; GENERAL_SETUP: proc (); call tu_$create (....); seg_created = "1"b; end GENERAL_SETUP; GENERAL_CLEAN_UP: proc (); call CASE_CLEAN_UP (); /* in case we're in the middle of a case */ if seg_created then do; /* we created */ seg_created = "0"b; call tu_$delete (....); end; end GENERAL_CLEAN_UP; o Test programs are not to check the version of the sectest_args structure, it will be done by the utilities called. Test programs may only modify the following components of the sectest_args structure: case_start_time case_end_time case_in_progress. o All tests should check to see if the expected results were obtained. The FIRST check should be that the gate did not change any input-only parameters. The next checks are to verify the test case received the error/status code expected and the information returned is correct or that no information is returned by the gate entry when the error 15-4 code indicates that access was insuffient. The LAST check is to call one or more of the audit checking utilities once for each auditing entry expected: tu_$check_syserr_audit, tu_$check_as_audit, tu_$check_syserr_freeform_audit, and tu_$check_as_freeform_audit. UTILITY PROGRAM STANDARDS o All utilities will be referenced through the tu_.alm transfer vector. In general, the entry tu_$FOO should transfer to the program tu_FOO, with tu_FOO being shortened as necessary for the file system (e.g., tu_$rcp_register transfers to tu_rcp_register.pl1, but tu_$rcp_delete_all_other_devices actually transfers to tu_rcp_dl_other_devices.pl1). For those utilities providing a common group of functionality, the entry will be prefixed with the group's initials; thus the RCP specific utilities are tu_$rcp_FOO. RCP is the only explicitly identified group at this time. o The first argument to all utilities is a pointer to a filled-in sectest_args structure (see sectest_args.incl.pl1). The remaining arguments are utility defined. Utilities which create or manipulate objects have three pointers to properties structures as their last three arguments: security, name, and non-security properties; see the include files sectest_fs_properties.incl.pl1, and sectest_rcp_dcls.incl.pl1, and sectest_lv_properties.incl.pl1 for examples of these structures. o If a utility has parts which must run in the Sectest_Server.Daemon's process, the Daemon code is an external entry into the tu_FOO module. The Daemon's transfer vector, tdu_.alm, will contain an entry calling tu_FOO$tdu_FOO. The entry st_process_daemon_request_ is to be called by tu_FOO, passing the the full name of the utility executing (i.e., FOO, not tu_FOO). The Daemon process will construct an entry to the tdu_ transfer vector and call it. N.B., the calling utility must always set st_process_daemon_request_'s reply length parameter so the Daemon interface's error detection will work. See the documentation of st_process_daemon_request_ for more information. o In general, each type of object should have its own utility for create, delete, setting properties, etc. E.g., tu_$create_segment should not create a message segment, tu_$create_ms should be used instead. o All properties of an object need not be specified at creation time, suitable defaults are assumed by the creation 15-5 utility. The following set of utilities should exist for each class of object (e.g. directory, mailbox): create_FOO, delete_FOO, get_properties_FOO, and set_properties_FOO. o There are some utilities defined to have a status code parameter to return non-fatal information. E.g., tu_$try_to_initiate_file is contracted to try to initiate a file in the test process and it is not always a fatal error if its call to initiate_file_ returns a non-zero code. This may only be done per-process utilities (i.e., ones which do not invoke st_process_daemon_request_). As above, all "real" errors are reported via sub_err_. Some utilities accomplish the above by using sub_err_ for fatal and non-fatal errors and requiring the test program to catch the condition to examine the condition info structure for the status code. o A utility is responsible for undoing any changes to the system it has done via a cleanup condition handler. This is used to back-out a partially completed operation. For instance, if a utility is to create two objects, and fails upon creating the second, the first should be deleted. Unlike test programs, it is usually inappropriate for utilities to call the CLEAN_UP procedure before a normal return. However, a FINISH procedure should be invoked both via normal exit and within the cleanup handler to perform storage deallocations, etc. o All tu_.alm entries will have declarations in sectest_tu_dcls.incl.pl1. For type specific utilities (e.g., RCP), a special include of sectest_tu_FOO_dcls.incl.pl1 will be created (e.g., sectest_tu_rcp_dcls.incl.pl1). 15-6 APPENDIX A REGISTERED CONTROL ARGUMENTS This section lists all approved control arguments and their abbreviations. Only these control arguments should be documented and accepted by commands. This applies to all commands whether they are standard user accessible commands or special tools for a particular class of users. For reasons of compatibility with the past, many commands are permitted to accept control arguments that have been previously documented. An exception is made for commands that are of very limited interest that accept a large number of potentially obscure control arguments; these commands may have nonstandard control arguments. If these commands are upgraded for more general use, their control arguments will have to be modified. If a command needs a control argument that is not registered in this list, it and its abbreviation should be defined. If the command is a special purpose tool and the control argument itself is not of general interest, no abbreviation should be defined. Two different lists of control arguments are presented. Table A-1 consists of general purpose control arguments, which are already used by system commands and may be expected to cover most situations. System programmers should use items from this list whenever possible. Table A-2 consists of more specialized control arguments, which cover a more limited range of situations. Table A-1. Approved Standard Control Arguments -absentee -as -absolute_pathname -absp A-1 -access -ac -access_class -acc -access_name -an -account -acknowledge -ack -acl -address -addr -admin -am -after -af -alarm -al -all -a -arguments, -argument -ag -ascending -asc -ascii -assignments -asm -attributes -attr -author -at -authorization -auth -bcd -before -be -bit_count -bc -bit_count_author -bca -block -bk -branch -br -brief -bf -brief_table -bftb -call -category -cat -character -ch -chase -check -ck -comment -com * -copy -cp -copy_switch -csw -count -ct -current_length -cl -date -dt -date_time_contents_modified -dtcm -date_time_dumped -dtd -date_time_entry_modified -dtem -date_time_used -dtu -date_time_volume_dumped -dtvd -debug -db -decimal -dc -default -delete -dl -delimiter -dm -density -den -depth -dh -descending -dsc -destination -ds -device -dv -directory -dr A-2 -else -entry -et -every -ev -exclude -ex -execute -extend -field -fl -file -f -fill -fi -first -ft -force -fc -from -fm -gen_type -gt -header -he -hold -hd -home_dir -hdr -id -indent -ind -input_file -if -input_switch -isw -io_switch -iosw -label -lbl -last -lt -length -ln -level -lev -limit, -limits -li -line_length -ll -lines -link -lk -link_path -lp -list -ls -logical_volume -lv -long -lg -map -mask -match -max_length -ml -maxlines -minchars -minlines -mode -md -model -modes -multisegment_file -msf -name -nm -next -nl -nnl -no_acknowledge -nack -no_address -naddr -no_header -nhe -no_offset -nofs -no_fill -nfi A-3 -no_link_translation -nlt -no_list -nls -no_notify -nnt -no_numbers, -no_number -nnb -no_pagination -npgn -no_print -npr -no_quote -nq -no_restore -nr -no_totals, -no_total -ntt -no_update -nud -non_null_link -nnlk -notify -nt -number -nb -octal -oc -off -offset -ofs -on -optimize -ot -ordered_field -ofl -outer_module -om -output_file -of -output_switch -osw -owner -ow -page -pg -page_length -pl -parameter -pm -pass -pathname -pn -position -psn -previous -prev -primary -pri -print -pr -profile -pf -project -pj -query -queue -q -quit -quota -record -rec -records_used -ru -repeat -rpt -replace -rp -request -request_type -rqt -reservation -resr -reset -rs -resource -rsc -restart -rt -reverse -rv -revert -ring -rg -ring_brackets -rb -safety_switch -ssw A-4 -search -srh -section -scn -segment -sm -sender -severity -sv -short -sh -sort -source -sc -start -sr -stop -sp -string -str -subscriptrange -subrg -subsystem -ss -switch -symbols, -symbol -sb -system -sys -table -tb -tab -target -terminal_input -ti -terminal_type -ttp -then -time -tm -title -to -total, -totals -tt -times -track -tk -truncate -tc -type -tp -unique -uq -unique_id -uid -update -ud -user -volume -vol -wait -wt -working_dir -wd Table A-2. Approved Special Control Arguments -4bit -7punch -7p -abort -accept -access_label -albl -action -age -append -app -attached -att -attachments -atm A-5 -ball -bl -bottom_label -blbl -bottom_up -bu -brief_header -bfhe -cancel -card -cc -change_default_auth -cda -change_default_project -cdp -change_password -cpw -check_ansi -chpass -cl -class -class_indentifiers -cli -cmf -cobol_switch -cs -collection, -coll -col -compile -complete -comp -comp_volume_dump_switch -cvds -copy_release_names -crn -continue -ctu -control -ct -control_arg -ca -convert -cput -date_time -day -day_name -debug_cg -deferred_indefinitely -dfi -definition -def -defs -delay -dly -detach -det -dir_mode -dont_free -dprint -dp -dpunch -dpn -ebcdic8 -ebcdic9 -edit -ed -entry_numbers -etn -entry_point -ep -exec_com -ec -expand -expanded -files -file_input -fi -flush -fnp -fold -format -fmt A-6 -foreground -fg -free -fw -generate_password -gpw -go -govern -gv -hex8 -hex9 -hyphenate -hph -immediate -in -incremental -inccost -inc_pf -inc_volume_dump_switch -ivds -inc_vcpu -in_reply_to -irt -initial_string -istr -inout -input_description -ids -interactive -ia -interactive_message -im -interrupt -int -invisible -iv -keyed -library -lib -line_numbers -ln -lmargin -lm -log -loop -long_id -lgid -lower_case -lc -mailbox -mbx -mcc -message_id -mid -meter, -metering -mt -min -minute -month -no_abort -no_canonicalize -ncan -no_endpage -nep -no_exec_com -nec -no_freeing -no_hold -nhd -no_interactive_message -nim -no_label -nlbl -no_log -no_message_id -nmid -no_null -no_orginal -no_orig -no_preempt -np -no_print_off -nprf -no_prompt A-7 -no_request_loop -nrql -no_stop_run -nsr -no_start_up -ns -no_subject -nsj -no_symbols, -no_symbol -nsb -no_warning -nw -non_edited -ned -nogo -notape -old_original -old_orig -open -original -orig -original_path -orig_path -out -output -output_description -ods -own -pdd -prefix -print_delay -pr_dly -print_edit -pr_edit -print_linkage_fault -print_new_lines -pnl | -print_off -pf -process_overseer -po -prompt -proxy -raw -realt -relocatable -rlc -remove -rm -rename -rn -reply_to -rpt -report_reset -rr -request_loop -rql -retain -ret -retain_data -retd -return_value -rtv -runtime_check -rck -safe_optimize -safe_ot -save -sv -secondary -seg -seg_mode -separate_static -ss -set -set_bc -set_nl -single -sg -single_name -snm -size -skip -sk -sleep -sort_dir -sd A-8 -sort_file_size -sfs -source_switch -ssw -static -status -st -stop_proc -spp -stt -subject -sj -subtotal -stt -subtree -subt -sys -sys_id -sysid -tape -tape7 -tape9 -temp_dir -td -template -tmp -text -tx -time_ot -timers -top_label -tlbl -total_cost -total_mem_units -total_pf -total_vcpu -to_queue -to_q -to_request -to_rqt -trace -trace_linkage_faults -train -tn -unlabeled_common -uc -upper_case -uc -use_bc -use_count -use -use_nl -verbose -vb -warn -watch -year -zero_on_alloc -zero_on_free -zone A-9 APPENDIX B REGISTERED SUFFIXES This section lists all registered entryname suffixes and their general meaning. Programs should follow the conventions implied by these suffixes. LIST OF SUFFIXES absin absentee input segment absout absentee output segment alm ALM source program statements apl APL saved workspace archive archive segment basic BASIC source program statements bcpl BCPL source program statements bind bindfile for the bind command breaks break segment for the debug command cds cds source program statements chars auxiliary output file produced by runoff and compose ckrout output segment form the check_mst command cmdb data model source segment for the create_mrds_dv command cmdsm data submodel source segment for the create_mrds_dsm command B-1 cobol COBOL source program statements code enciphered segment produced by the encode command compin compose source statements compout primary output file produced by compose control control file for miscellaneous commands crl control segment for the cross_reference command crlout output file of the cross_reference command dict dictionary segment used by dictionary commands dir_info directory information segment output by the save_dir_info command dsm output file produced by the create_mrds_dsm command ec segment containing exec_com lines fortran FORTRAN source program statements gcos file in GCOS Standard System Format gdt graphics device table source segment input to the compile_gdt command ge input segment to the graphics_editor command | graphics suffix added to the segment created when | invoking the -output_file control argument to | the setup_graphics command header header file for MST generator incl.alm ALM include files incl.bcpl BCPL include files incl.cobol COBOL include files incl.fortran FORTRAN include files incl.lisp LISP include files B-2 incl.pl1 PL/I include files info segments formatted according to help command conventions ld source for the library descriptor command lisp LISP source program statements list listing file produced by a compiler assembler or binder lister data base used by lister commands listform control segment defining document format used by process_list command listin segment used by create_list command to input or update a lister file mail segment containing message suitable for | dprinting created by the read_mail and | send_mail commands | map map segment produced by binder or library_ map mbx ring 1 mailbox memo database used by memo command mexp mexp source program statements motd database for the print_motd command ms ring 1 message segment order control segment for the reorder_archive command pgs specifies permanent graphic segments | cpntaining structured graphic objects used by | the graphic_manipulator_ subroutine | pfd output file created by the profile command pfl listing file used by the profile command pl1 PL/I source program statements print output of the library_print command probe break segment for the probe command B-3 profile user profile used by abbrev and check_info_segs qedx qedx macro rd reduction compiler source statements runoff runoff source statements runout primary output file produced by runoff search search directories for MST generator symbols symbol dictionary used by the Speedtype commands | ta table of contents segment created and used by | the tape_archive command teco teco macro volumes output segment of the manage_volumes_pool command wl wordlist segment used by the wordlist commands B-4 APPENDIX C REGISTERED I/O SWITCH NAMES This section lists the names and meanings of all I/O switches that are used by system programs. LIST OF I/O SWITCH NAMES audit_i/o.HHMM.T switch used bu audit facility, where HHMM.T is the time switch was attached debug_input switch from which the debug command takes its input requests debug_output switch onto which the debug command writes its output ec_switch_nn switch associated with the nn switch attached by the exec_com command error_output switch onto which commands write their error messages filenn switch associated with unitnn in FORTRAN programs fo_!uniquename switch attached by file_output command fo_save_!uniquename switch used by file_output to save previous attachment graphic_input switch used for graphics input graphic_output switch used for graphics output lib_map_ switch used by library_map command lib_print_ switch used by library_print command C-1 user_i/o switch attached to interactive users primary I/O device user_input switch from which commands and the command processor take their input user_output switch onto which commands write their normal output !uniquename.lila switch name used by LINUS !uniquename.rel switch name used by LINUS !uniquename.res switch name used by LINUS C-2 APPENDIX D REGISTERED CONDITION NAMES This section lists all registered condition names. LIST OF CONDITION NAMES active_function_error alrm any_other area bad_area_assignment bad_area_format bad_area_initialization bad_dir_ bad_outward_call cleanup command_abort command_error command_query_error command_question conversion cput cross_ring_transfer db_conversion derail endfile endpage error fault_tag_1 fault_tag_3 finish fixedoverflow gate_error illegal_modifier illegal_opcode illegal_procedure illegal_return io_error ioa_error D-1 isot_fault key linkage_error listing_overflow lockup lot_fault message_segment error mme1 mme2 mme3 mme4 name no_execute_permission no_read_permission no_write_permission not_a_gate not_in_call_bracket not_in_execute_bracket not_in_read_bracket not_in_write_bracket op_not_complete out_of_bounds overflow page_fault_error parity program_interrupt quit record record_quota_overflow return_conversion_error seg_fault_error simfault_nnnnnn size stack storage store stop_run stringrange stringsize sub_error_ subscriptrange sus_ timer_manager_err trm_ transmit truncation unclaimed_signal undefinedfile underflow unwinder_error zerodivide D-2 CONTENTS Page Section 1 Introduction . . . . . . . . . . . . . . 1-1 How to Use This Document . . . . . . . 1-1 Volatility of Contents . . . . . . . . 1-1 General Issues . . . . . . . . . . . . 1-1 Registered Names . . . . . . . . . . . 1-2 Topics . . . . . . . . . . . . . . . . 1-2 Section 2 Interface Standards . . . . . . . . . . . 2-1 Command Interfaces . . . . . . . . . . 2-1 Storage System Conventions . . . . 2-1 Command Arguments . . . . . . . . . 2-3 Pathname Conventions . . . . . . . 2-4 Control Argument Conventions . . . 2-5 Output Conventions . . . . . . . . 2-5 User Interaction Conventions . . . 2-6 Subroutine Interface Standards . . . . 2-7 Subroutine Names . . . . . . . . . 2-7 Argument Standards . . . . . . . . 2-7 Section 3 General Programming Standards . . . . . . 3-1 Command Standards . . . . . . . . . . 3-1 Naming Standards . . . . . . . . . . . 3-2 Storage System Conventions . . . . . . 3-2 Output Conventions . . . . . . . . 3-3 Use of On Units for the Cleanup Condition . . . . . . . . . . . . 3-3 Coding Conventions . . . . . . . . 3-3 Section 4 Modularity . . . . . . . . . . . . . . . 4-1 Program Structure . . . . . . . . . . 4-1 Compilable Unit Size . . . . . . . . . 4-1 Generality of Mechanism . . . . . . . 4-1 External Availability of Mechanism . . 4-1 Binding and Bindfiles . . . . . . . . 4-3 Contents of Bound Segments . . . . 4-3 Names of Bound Segments . . . . . . 4-3 Bindfile Contents . . . . . . . . . 4-3 Bindfile Formatting . . . . . . . . 4-4 Section 5 Environment Independence . . . . . . . . 5-1 iii CONTENTS (cont) Page Reentrancy . . . . . . . . . . . . . . 5-1 Transparency . . . . . . . . . . . . . 5-1 Interruptibility . . . . . . . . . . . 5-2 Condition Handling . . . . . . . . . . 5-2 Access Assumptions . . . . . . . . . . 5-2 Use of Standard Mechanisms . . . . . . 5-2 Pathnames and Search Rules . . . . . . 5-2 Section 6 Program Format . . . . . . . . . . . . . 6-1 Comments in Programs . . . . . . . . . 6-1 Copyright Notice . . . . . . . . . 6-1 Journalization Notice . . . . . . . 6-1 Interface Descriptions . . . . . . 6-2 Program Comments . . . . . . . . . 6-2 General Layout of a PL/I Program . . . 6-2 Standard Format . . . . . . . . . . 6-3 ALM Program Considerations . . . . . . 6-3 Section 7 Include File Format and Constraints . . . 7-1 Include File Format . . . . . . . . . 7-1 Use of Include Files . . . . . . . . . 7-2 Naming Include Files . . . . . . . . . 7-2 PL/I and ALM Include Files . . . . . . 7-2 Section 8 PL/I Language Conventions . . . . . . . . 8-1 Constraints . . . . . . . . . . . . . 8-1 Efficient PL/I Constructs . . . . . . 8-2 The Alignment Attributes . . . . . 8-2 Attributes with Arithmetic and Pointer Variables . . . . . . . 8-2 Use of the Alignment Attributes with Short Strings . . . . . . 8-3 Use of the Alignment Attribute with Long Strings . . . . . . . 8-3 Use of Unaligned Short Variables in Arrays and Structures . . . 8-3 Use of the Precision Attribute in Offset and Length Expressions . . 8-3 The Use of Internal Static to Simulate Named Constants . . . . . 8-4 Use of the Initial Attribute . . . 8-5 The Assignment Operation . . . . . 8-5 The Multiple Assignment Statement . . . . . . . . . . . 8-5 Conversions . . . . . . . . . . 8-6 Pictures . . . . . . . . . . . . 8-6 Arithmetic Operations . . . . . . . . 8-7 Binary Operations . . . . . . . 8-7 iv CONTENTS (cont) Page Decimal Operations . . . . . . . 8-7 String Operations . . . . . . . . . 8-8 Special Case of Concatenation . 8-8 Operations on Long Strings . . . 8-8 Aggregate Operations . . . . . . 8-9 Use of the Builtin Functions . . . 8-9 Arithmetic Builtins . . . . . . 8-9 String Builtins . . . . . . . . 8-10 Mathematical Builtins . . . . . 8-10 The Call Statement and Function References . . . . . . . . . . . . 8-11 Determining the 'Quickness' of a Block . . . . . . . . . . . . . 8-11 Using Constant Argument Lists . 8-12 Using If Statements . . . . . . . . 8-13 Optimization of Comparisons . . . . 8-13 Other Constructs That Are Costly or Dangerous . . . . . . . . . . . . 8-14 Section 9 Storage Management . . . . . . . . . . . 9-1 Use of the Storage System . . . . . . 9-1 Pathnames . . . . . . . . . . . . . 9-1 Naming Conventions . . . . . . . . 9-2 Working Directory Use . . . . . . . 9-2 Access Control List Management . . 9-2 Making Segments Known and Unknown . 9-3 Pathnames vs. Segment Pointers . . 9-3 Multisegment Files . . . . . . . . 9-4 Use of the Bit Count . . . . . . . 9-5 Storage Allocation . . . . . . . . . . 9-5 Internal Static Storage . . . . . . 9-5 PL/I Areas . . . . . . . . . . . . 9-5 Temporary Segments . . . . . . . . 9-6 Section 10 Documentation Standards . . . . . . . . . 10-1 Location of Documents . . . . . . . . 10-1 Section 11 Info Segments . . . . . . . . . . . . . . 11-1 Style . . . . . . . . . . . . . . . . 11-1 Physical Appearance . . . . . . . . . 11-1 Naming Conventions . . . . . . . . . . 11-2 Syntax of Info Segments . . . . . . . 11-2 Title . . . . . . . . . . . . . . . 11-2 Paragraphs . . . . . . . . . . . . 11-3 Sections . . . . . . . . . . . . . 11-3 Command Descriptions . . . . . . . 11-3 Subroutine Descriptions . . . . . . 11-4 Other Info Segments . . . . . . . . 11-4 v CONTENTS (cont) Page Section 12 Rules for Translator Writers . . . . . . 12-1 The Command Program . . . . . . . . . 12-1 The Object Segment Created . . . . . . 12-1 Listing Output . . . . . . . . . . . . 12-2 Miscellaneous Requirements . . . . . . 12-3 Section 13 Rules for Coding Trusted Software . . . . 13-1 Trusted Software . . . . . . . . . . . 13-1 Trusted Programs and the NCSC Security Rating . . . . . . . . . . . . . . . 13-1 User interface parameters and their importance . . . . . . . . . . . . . 13-2 General rules for all trusted code . . 13-2 The ring model . . . . . . . . . . . . 13-3 Hardware ring checks . . . . . . . 13-3 Ring of execution . . . . . . . 13-3 ring numbers in pointers . . . . 13-4 Examples of Hardware Ring Checks 13-4 Software ring checks -- the validation level . . . . . . . . . 13-5 gate parameters: security considerations . . . . . . . . . . . 13-6 Naming Conventions for Gate Parameters . . . . . . . . . . . . 13-7 Rules for gate parameters -- forbidden reference patterns . . . 13-7 multiple parameter read . . . . 13-8 parameter write, then read . . . 13-8 multiple parameter write . . . . 13-8 passing parameter to another subroutine . . . . . . . . . . 13-8 parameters in expressions . . . 13-9 Packed pointer parameters . . . 13-9 Improper reference to structure parameters . . . . . . . . . . 13-9 When should TCB modules generate an audit trail . . . . . . . . . . . . . 13-10 Information that is Necessary . . . 13-10 Trusted server interfaces . . . . . . 13-11 Ring 1 circumvention of AIM policies . 13-11 Privileged exec_coms that walk the hierarchy . . . . . . . . . . . . . . 13-12 system error message documentation . . 13-12 What messages should be documented 13-12 How to document them . . . . . . . 13-13 Commentary in Programs and Include Files . . . . . . . . . . . . . . . . 13-15 Commentary in Source . . . . . . . 13-16 vi CONTENTS (cont) Page Section 14 Writing and Updating Multics Design Documents . . . . . . . . . . . . . . . 14-1 Content of an MDD . . . . . . . . . . 14-1 The format of an MDD . . . . . . . . . 14-2 Section 15 Coding Standards For B2 Functional Tests And Utilities . . . . . . . . . . . . . 15-1 General Standards . . . . . . . . . . 15-1 Test Program Standards . . . . . . . . 15-2 Utility Program Standards . . . . . . 15-5 Appendix A Registered Control Arguments . . . . . . A-1 Appendix B Registered Suffixes . . . . . . . . . . . B-1 List of Suffixes . . . . . . . . . . . B-1 Appendix C Registered I/O Switch Names . . . . . . . C-1 List of I/O Switch Names . . . . . . . C-1 Appendix D Registered Condition Names . . . . . . . D-1 List of Condition Names . . . . . . . D-1 TABLES Table A-1 Approved Standard Control Arguments . . . A-1 Table A-2 Approved Special Control Arguments . . . A-5 * vii