# EMUX - Error Message Utility for OS-9 and POSIX

Frans Meijers - meijers@cernvm

Translated to HTML by Norman Gee - c.n.p.gee@rl.ac.uk

## Introduction

EMU is a utility for error reporting. It allows selective message routing at run time.

EMU was developed in the context of MODEL and the first implementation was based on ADA and VAX/VMS. Extensive documentation is available[1]. The complete EMU system, including compilers and some message display programs was ported to OS-9 by OPAL. All programs were rewritten in C using the UNIX tools Lex and Yacc to develop the decoder/router table "compilers".

A request for a version for UNIX-like platforms initiated the development of a new version. In order to make the OS-9 and POSIX flavour as similar as possible it relies only on the file system including named pipes. At the same time, some features introduced since 1987 in the VMS version were added and the raw message format was made identical.

History:
Version 1   dec-87 initial version for OS-9
Version 2.0 jan-92 version for OS-9 and POSIX


### Overview of EMU

Message injection , the EMU Decoder , Router, and Destination Modules..

### Decoder and Router details

Message Decoding: Message File Format, Syntax, and Parsing Rules.

Message Destinations: Router Router Use and Notes

## Examples

### Overview of EMU

In EMU messages are injected from user programs and pass down a pipeline for processing. The four common stages are as follows:

#### Message injection.

The user program makes EMU injection calls. They inject a message code (identifier) plus any parameters into the EMU subsystem.

#### The EMU decoder.

The EMU decoder retrieves message text for each message from a local table (message file) and substitutes any supplied parameter value into that text. The decoder also interrogates the message file for any properties that are to be associated with the message. A property is a tag string which can be used to decide on subsequent routing of the message.

#### The EMU router.

The EMU router receives messages and delivers them to one or more destinations (or none) according to routing instructions in a local table (routing file). Valid routings are to display devices (consoles), log file or to other message processing programs (externals).

#### Destination modules.

Facilities for sending messages to consoles and to log files are built into the router. Other destinations could be written to e.g. provide automatic feedback or to inject the message in the router of another EMU system.

### The EMUX Implementation

All stages, described above, are implemented for OS-9 and POSIX 1003.1.

It is aimed to be compatible with the VAX/VMS version for the calling sequences of the message injection functions and the format of the message and rout map files. However, the current decoder and the router are, unlike the VAX/VMS implementation, case sensitive.

EMUX is written in C. For OS-9, the injection routines can also be called from RTF.

The EMU system consists of a set of processes communicating via named pipes. Firstly, one or more user programs, with appropriate calls to the injection functions, write messages into the decoder input pipe (/pipe/emu2deco for OS-9 and /tmp/emu2deco for POSIX). The decoder process (emudeco) reads every message from the input pipe, decodes it and writes the decoded message into the router input pipe (/pipe/emu2rout for OS-9 and /tmp/emu2deco for POSIX). The router process (emurout), subsequently, reads the decoded message from the input pipe, determines whether this message should be forwarded to a specific destination and if so, writes the message record (possibly formatted) to the path corresponding to this destination.

The information needed by the decoder from the message file and by the router from the routing file is read at initialisation time from the compiled message file (deco.map) and compiled routing file (rout.map). This 'compilation' step is done with the programs ecdeco and ecrout, respectively.

## Message Injection

Messages are injected into the EMU pipeline by appropriate EMU calls from the user program.

### Calling Sequences

The injection call arguments are the message code and possibly additional parameters. The calling sequence for these calls is given below in the form of C function prototypes.

The standard functions are :

int emu_init (void) ;
int emu_close_down (void) ;

int emu_int  (char msgcode[], int arg) ;
int emu_real (char msgcode[], double arg) ;
int emu_str  (char msgcode[], char arg[]) ;
int emu      (char msgcode[]) ;

int emu_set_param_str (char arg[]) ;
int emu_erase_all_params (void) ;

int emu_str_package (char msgcode[], char arg[], char package[]) ;
int emu_package     (char msgcode[], char package[]) ;

int emu_set_program_name (char name[]) ;
int emu_set_machine_name (char name[]) ;
int emu_set_instance_name (char name[]) ;


The non-standard functions:

int emu_prop (char arg[]) ;
int emu_erase_all_props(void) ;

int emu_pre_init (char prefix[]) ;


For RTF programs under OS-9, a set of corresponding subroutines (or functions) is defined with calling sequences natural for FORTRAN.

### Function Description

Every program using EMU must call emu_init() in the initialisation phase and certainly before any other emu...() call. At the program termination phase a call to emu_close_down() should be made.

For injecting a message without a parameter one calls emu(), whose only argument is the string msgcode[], the message code.

For injecting a message with a single parameter one calls emu_int(), emu_real() or emu_str(). They will inject a message of code msgcode[] and with parameter of type integer, real or string, respectively.

For messages with two or more parameters emu_set_param_str() needs to be called once for each parameter. These parameters are stored internally. Finally, a call to emu() (or emu_int(), emu_real(), emu_str()) causes the message with all stored parameters to be injected and the locally stored parameters are cleared.

emu_erase_all_params() may be called to erase all parameters previously stored with emu_set_param_str(). Note that a call to emu() (or emu_int(), emu_real(), emu_str()) implicitely calls emu_erase_all_params() as all locally stored parameters are erased once a message has been injected.

For use with packages of library routines emu_package() and emu_str_package() are available. They are similar to the normal injection routines but take one extra string parameter package[], to identify the name of the library package.

The calls emu_set_program_name(), emu_set_instance_name() and emu_set_machine_name() are provided to set the program name (default is the process name for OS-9), instance name (default is the process number for OS-9 and POSIX) and machine name (default is the nodename for POSIX), respectively. These calls are optional.

In the VAX/VMS implementation properties are added to the message by the EMU decoder. Here it is possible to generate them at the injection level, as well. The routine emu_prop() needs to be called once for each property string before the message is injected (like emu_set_param_str()).

So far, it is assumed that the user programs run on the same CPU as the EMU decoder and router. For OS-9 it is useful to inject messages generated in different CPUs to the same EMU decoder process using OS9Net. This can be done by calling at initialisation eg emu_pre_init("/vnet/cpu0"). The function emu_pre_init() is optional, but if called must proceed emu_init(). It prefixes the pathname of the injection output.

Notes All injection functions return 0 on success and -1 on error. In practice, the return values are not checked. The function emu_init() performs a program exit in case of fatal error.

The string type arguments may NOT contain embedded tick () characters. Also, newline characters (\n) are filtered out by the injection functions.

For C programs the header emu.h with definition of the injection functions (ANSI C and K&R C) can be included. The EMU injection functions are provided in the library emulib.l for OS-9 and libemu.a for POSIX. For OS-9, the jacket functions for RTF programs are included in the library.

## Message Decoding

### The Message File Format

The text of an individual message is stored in the message file as a sequence of substrings

<text1> <text2> . . etc.


At run time, the final message text is constructed by inserting the first parameter after the first substring, the second after the second substring and so on:

<text1> <param1> <text2> <param2> . . etc.


### Message File Syntax

Each line of the message file begins with -- or a keyword for indentification. There are six line types as follows:

     -- comments please


A line starting -- is treated as a comment and may be used anywhere in the file.

     PROGRAM
PACKAGE


A line starting PROGRAM (PACKAGE) identifies the () to which subsequent messages belong. There may be more than one PROGRAM (PACKAGE) line in a file, and hence messages for more than one program (package). The () identifiers must be unique. The PROGRAM (PACKAGE) line is a compulsary line and must preceed all other lines in the file except comment lines.

     MESSAGE


A line starting MESSAGE introduces successive lines whose information refer to . One MESSAGE line is compulsory to introduce each new message. should be unique for a given or .

     PROPERTY , etc.


The keyword PROPERTY introduces lines declaring properties to be associated with a message or messages. No PROPERTY line may occur before the PROGRAM (PACKAGE) line in the file. PROPERTY lines occuring after the PROGRAM (PACKAGE) line but before the first MESSAGE line are taken to refer to all messages in that program (package). PROPERTY lines occuring after a MESSAGE specifically refer to that one particular message. All property lines are optional.

     TEXT


The text substrings are used to build up the message text. Note that a quoted substring is required whenever leading or trailing spaces form a part of the substring. TEXT lines are always optional. A MESSAGE with no TEXT line will be understood to comprise just parameters.

### Message File Parsing Rules

Any individual line is parsed into tokens. Each token consists of a sequence of text characters. The letters of the alphabet (a-z,A-Z), digits (0-9), underscore (_) and period(.) are always text characters. Any character different from these to be used as text character, should be in a token enclosed by matching quotes. Either single (') or double (") quotes are accepted. The quotes do not form part of the token.

Reserved tokens are --, and the keywords PROGRAM PACKAGE MESSAGE PROPERTY PROPERTIES TEXT. These keywords may be truncated to the first four characters and can be in lower or upper case. The reserved tokens are not interpreted as such when the appear insides quotes.

Using the Decoder Compilation of a message file is done with the command

     ecdeco <message file> [-m=]


If successful, it will write the (binary) output file deco.map in the current directory. With the -m option additional memory can be requested (size is in kbytes).

The EMU decoder is started in the background, eg as

     emudeco >>>-/r0/emudeco.log &


At initialisation the file deco.map is read. To update the message file one needs to kill the emudeco process, recompile the message file with ecdeco and start the emudeco process again.

There is no default machine name set for OS-9. One could call emu_set_machine_name() at the injection level. Another possibility (recommended) is to start the EMU decoder with the option -m=MYMACHINE . Then all messages that pass through (also from the other CPUs over OS9Net) get that machine name. (-m keeps machine name if set on input, whereas -M overrules also those.)

Decoder Notes It is possible to generate the error messages (text and properties) in the user programs (with emu_prop() and emu_str()) and leave the decoder table largely dummy.

Note that the EMU decoder is case sensitive, eg the message code MESS1 injected with emu(MESS1) will {\bf not} match with the message line

     MESSAGE mess1


in the decoder file.

## Message Routing

The EMU router accepts messages from the EMU decoder and forwards them to as many destinations as required according to instructions in a routing file.

The routing file provides the following information to the EMU router:

• It declares all destinations that will be used.
• It indicates the type of each destination, ie what, if any formatting should be performed.
• It indicates the selection criteria according to which individual message are routed to one or more of the different possible destinations.

### Syntax

A line starting -- is treated as a comment and may be used anywhere in the file.

A destination is declared as follows:

     destination_name : type := pathname ;


The destination_name may be freely chosen. The type is restricted to one of those types already known to EMU namely CONSOLE, LOGFILE, EXTERNAL or FIFO. The pathname is the corresponding OS-9 or POSIX pathname. Any number of destinations may be declared.

Message routing pivots on the destination, ie each destination is listed in turn with message selection criteria grouped alongside. A message selection statement takes the form:

      destination_name => expression ;


where destination_name is one of the destination already declared and expression is an expression which evaluates to TRUE or FALSE. The expression is evaluated for every message arriving. If the expression is true for a particular message, then the message is forwarded to this destination. An expression will typically contain items (leaves) of the form


KEYWORD = value


A leaf is a Boolean expression that is evaluated in the context of the message currently being routed. The selection keywords most frequently referenced during routing are probably PROGRAM, MESSAGE and PROPERTY. Other possible selection keywords are MACHINE, INSTANCE, PACKAGE, and TEXT.

The inverse comparison is also available, ie KEYWORD /= value (or !=). Longer expressions using (with increasing precendence) OR, AND, NOT and brackets () may be constructed in the usual way, eg

     alarm_console => PROP = alarm OR
PROP = warning AND (PROG = scan OR PROG = monitor) ;


A destination_name may be repeated. This repetition is always equivalent to using the OR operator. One of the simplest routing files would be (for OS-9)

     emu_console : CONSOLE := '/t1' ;
emu_console => ALL ;


which would cause to forward all messages in console format to path /t1.

In order to improve for complex message selections efficiency and readability it is possible to define synonyms. A synonym statement takes the form

     synonym_name := expression ;


The synonyms may be used anywhere the full expression may be used. Note that synonym is NOT a variable. Once assigned, it may not be reassigned.

### Parsing Rules

These rules are the same as those for the message file except for that the reserved tokens are -- : ; := => ( ) = /= != and the keywords AND OR NOT CHOOSE ALL MESSAGE MACHINE PROGRAM PACKAGE INSTANCE PROPERTY DATE TIME TEXT CONSOLE LOGFILE EXTERNAL FIFO. The keywords MESSAGE to TEXT and CONSOLE to FIFO may be truncated to four and three characters, respectively. All keywords can be in lower or upper case. The reserved tokens are not interpreted as such when they appear inside quotes.

Message Destinations Currently four types of destinations are defined, CONSOLE, LOGFILE and EXTERNAL and FIFO. An output stream of type CONSOLE is formatted in a manner appropriate to a simple scrolling device. LOGFILE output is meant for accumulating messages into a log file. EXTERNAL output allows a user to obtain a message stream for further processing.

The CONSOLE line format is




A bell (ASCII 7) is added. The LOGFILE, FIFO and EXTERNAL lines are in the basic EMU record format (see Appendix). The LOGFILE destinations are opened in update mode. For EXTERNAL destinations the path needs to exist before the router is started. The FIFO destinations will be created as named pipes in case not yet existing.

Router Use Compilation of a routing file is done with the command

     ecrout  [-m=]


If successful, it will write the (binary) output file rout.map in the current directory. With the -m option additional memory can be requested (size is in kbytes).

The EMU router is started in the background, eg as

     emurout >>>-/r0/emurout.log &


At initialisation the file rout.map is read and a path to all specified destinations is opened. To update the routing file one needs to kill the emurout process, recompile the routing file with ecrout and start the emurout process again.

Router Notes Error messages directed towards the CONSOLE are output on a local terminal. Under OS-9 this would typically be '/t1' with the terminal monitor program (tsmon) disabled.

The EMU router is case sensitive, eg


PROP = FATAL


will evaluate to FALSE in case the message property is fatal.

### Example User Program


/* emudemo.c -- program to demonstrate EMU */

#include "emu.h"

main (argc,argv)
int argc; char *argv[] ;
{
emu_init() ;                            /* initialise */
emu_set_program_name (argv[0]) ;        /* set program name */

emu("noprm") ;                          /* no parameter */

emu_set_program_name ("demo") ;         /* simulate other program */

emu_int("HV",4711) ;                    /* integer parameter */

emu_prop("WARN")  ;
emu_real("a1",19.59) ;                  /* real parameter */

emu_str("temp","hotter") ;              /* string parameter */

emu_set_param_str("red") ;              /* many parameters .. */
emu_set_param_str("yellow") ;
emu_set_param_str("blue") ;
emu("colors") ;                         /* inject many parameters */

emu_str_package("fun0","calling: ","some_lib") ;  /* package */

emu_close_down() ;                      /* close */
}


### Example Message File


-- file: demo.deco  / message file for demonstration program
-- note the use of truncation and quotes.
--

--
PROGRAM emudemo
PROP language, test
MESSAGE noprm
TEXT    'this is the first message from "emudemo"'
--
PROG    demo
MESS  HV
TEXT  "The High Voltage is raised to "
TEXT  " Volts"
MESS  a1
PROP  gas
PROP  alarm
TEXT  "LEAK RATE is "," l/hour "
MESS  temp
TEXT  "It's getting "
MESS  colors
TEXT  "who's afraid of "
TEXT  ", "
TEXT  " and "
--
package some_lib

MESSAGE fun0
TEXT "package ",'fun0'



### Example Route Map File


-- file : demo.rout  / routing file for demonstration program
--
-- declare destinations
emu_console     : CONSOLE := 't1' ;
all_log         :LOGFILE := './emu_logall' ;
main_log        :LOG     := './emu_logmain' ;

-- define synonyms
warning := PROP = WARN ;
debug := PROP = test ;
syno1 := PROP /= not_existing ;
difficult_all := syno1 AND true ;

-- routing selection
emu_console => ALL AND PROP /= NOconsole AND PROP /= SUPPRESS;
all_log  => (PROG = demortf OR PROG=democ OR difficult_all) AND PROP /= SUPPRESS ;
main_log => NOT warning AND PROP /= SUPPRESS ;


## Appendix. The EMU message record format

The EMU message record is a sequence of ASCII characters. The record is internally composed of an unspecified number of strings, each delimited by the character . is defined to be tick () character. The message record for is organised as:


MESS
PROG
MACH
INST
DATE
TIME
[PACK   ]
{PROP   }
{PARA   }
[TEXT   ]
EOR


where [] denotes zero or once and {} zero or more times. The decoder input has PARA fields but no TEXT fields, whereas the decoder output has no PARA fields but one TEXT field with the decoded text string.

In the current implementation, the record is terminated with a \n character. (ASCII 10 for OS-9 and ASCII 13 for UNIX).

## References

[1] P.C.Burkimsher, EMU, the MODEL Error message Utility, version 2.1 (Dec.1990)

 This page was last updated on 16 December, 2013 Comments and requests for clarification may be sent to E-mail: Telephone: