The devio command language is extremely cryptic; this makes it easy to parse but difficult to understand. Nevertheless the syntax is very simple – every command consists of just two characters, is followed by set of arguments which can only be a single string or a numeric expression and is terminated by a the end of the line.
Space and tab characters are ignored. The line is ended by the end of the argument string, end of line or by a ; character.
A string may be included in quotes, but need not be – it just consists of the rest of the line!
Numeric expressions are the most complex aspect because devio uses postfix operands - RPN (“Reverse Polish Notation” after the nationality of the inventor, Jan Lukasiewicz). In the manner of HP’s implementation of this notation devio accumulates numbers on a stack then combines the numbers according to the supplied operators.
The commands to open files for reading and writing are almost always required. These commands use the character > to indicate a write file and < for a read file. This mimics the redirection operators used in shell scripts. To open the device /dev/foo for read the following command would be used:
Many lexical variations are possible – for example the space after the << command is not necessary, the device name could be enclosed in quotes and the line may end with a ; character.
Initially devio will read from the start of the device, however this can be changed:
This sets the input file pointer (the “from” pointer) to point after byte 1000 in the device – the next byte read will be the 1001st.
The operators used in devio’s numeric expressions are always a single character. Thus a numeric expression consists of numbers – formatted in any way acceptable to the strtoul(3) C library function – followed by single character operators. Spaces are not necessary except to separate adjacent numbers.
The character “,” (comma) may be used interchangeably with a space – it has no significance beyond terminating a prior numeric value. In the following examples the comma is used to separate expressions that evaluate to separate command arguments, but this is just to make it easier to see which parts of the expression form which argument for a command.
The >= command sets the output position, where the next write command will write. The character “#” is an operator that returns the length of the current output device. Thus the following command positions the output pointer 256 bytes before the end of the device:
>= # 256 –
The expression pushes the length of the output (#) to the stack then pushes 256 and finally the subtraction operator “-” takes the two top elements from the stack, subtracts the last one from the previous and pushes the result back onto the stack. It is convenient to call the last value pushed to the stack “right” and the one before “left” as though the stack grows from left to right – this corresponds to both the order the values appear in the command line and to the conventional nomenclature for the operands of dyadic operators.
The fb command fills a given number of bytes in the output with a given byte value. So to fill the last 256 bytes of the device with 0 the previous command would be followed by:
fb 256, 0
In both of these commands all the operands for the command are provided on the command line. This need not be the case – the stack is retained between commands for all commands except the formatted print command pf which clears the stack. Suppose the final bytes of the device are to be filled with 0, but the number of bytes to fill is the result of a complex calculation and that this number is on the top of the stack. Then the following commands might be used:
>= # s –
The .= command does nothing – it is used to evaluate an expression which will be used later. In this case the expression is just the operator “.” which duplicates the top element of the stack. The >= command is as before except that the distance from the end is already on the stack, therefore is before (below, to the left of) the length (#). The “s” operator is used to swap the top two elements of the stack, so that the subtraction gives the correct result.
Finally the fb command only requires the byte value (0) on its own command line because the length to fill is already on the stack.
On the LinkSys NSLU2 the second flash partition, /dev/mtdblock1, contains textual system configuration information. Unfortunately this information, being in a raw flash device, has to be preceded by the length of the data and this is stored as a big-endian binary value. The following devio command extracts the textual information (alone):
devio ‘<</dev/mtdblock1; cp b’
This uses the cp command which copies the given number of bytes from the current input to the current output. The argument to cp is a single operator “b” which reads four bytes from the current input and interprets them as a big-endian value, pushing the result to the stack.
Consequently the command reads the first four bytes in the device then copies that number of bytes to the output. Because no output was specified the program standard output is used.