Scripting

The diag shell has a small scripting language: variables, integer expressions, conditions, loops and script files (rc scripts). It is the same language at the drivshell> prompt and inside scripts. How a command line is split into words, quoted and chained with ; is described in Accessing the shell.

Variables

$name or ${name} is replaced by the variable’s value. Undefined variables expand to nothing. $?name expands to 1 if name is defined and 0 if not, which is the usual test in if. Single quotes stop expansion and double quotes do not, so use single quotes when a command line is stored for later, as in for and save.

There are two kinds of variable:

  • local variables, set with local, belong to the current scope. Every rcload script gets a new scope, which disappears when it ends. The drivshell> prompt itself has no local scope, so local at the prompt, and the loop variable of a for typed there, end up as global variables.

  • global variables, set with setenv, are visible everywhere. A local variable of the same name hides a global one.

printenv lists them. Names beginning with _ are system variables and cannot be set. The shell also sets some variables itself:

  • $?: the result of the last command (0 for success; negative values are errors; expr stores its value here). It reads 0 again in the next bcmcmd call, so use it on the same line or inside a script;

  • $1, $2, …: the arguments of the running script;

  • units: the number of devices found by probe;

  • per-unit variables such as devname, and the chip names as flags (set to 1), used by Broadcom’s scripts in tests like if $?BCM56870_A0 …;

  • config_var_val and config_var_not_set, after config get.

Variables set at the prompt stay set, across bcmcmd calls and bcmsh sessions, until you remove them (local <name> or setenv <name>) or syncd restarts. printenv shows what earlier sessions left behind.

Expressions and conditions

expr evaluates C-style unsigned 32-bit integer arithmetic. Its value becomes the command’s result, and only 0 counts as success. A plain number used as a command succeeds when it is non-zero. Together that gives two rules for if:

  • if $?myvar "…" and if 1 "…" work as expected;

  • if "expr $n > 2" "…" is inverted: it runs when the comparison is false. Write if !"expr $n > 2" "…", as Broadcom’s rc.soc does.

case picks a command by exact string match.

Loops

loop repeats command lines a fixed number of times, and for counts a variable through a range. Both stop at the first failing command while the LoopError option is on.

Warning

The drivshell> prompt has no way to interrupt a running command. loop * or a long loop runs until it finishes or syncd restarts.

background runs up to two command lines in a separate thread; jobs and kill manage them.

rc scripts

An rc script is a text file of shell commands, run with rcload.

  • # starts a comment, to the end of the line, even inside quotes.

  • A line ending in \ continues on the next line.

  • Arguments of rcload become $1, $2, ….

  • When a line fails, the script stops, unless the RCError option is off. Lines starting with expr never count as failures. The error message names the file and line; RCNoPrintError suppresses it.

  • Nesting of scripts and loops is limited (recursion too deep).

A name containing / is opened as given. Any other name is looked up in the rccache first, then in each directory of the path variable, or in the working directory if path is unset. Typing an unknown command word makes the shell try rcload word.soc in the same way while the RCLoad option is on.

Scripts live in the syncd container. save can write a one-line script there; copy longer ones in from the host as described in Files inside the syncd container (copy them to /root; docker cp into /tmp does not work). ls, more, cd and pwd help to find them. On SONiC the working directory is / and path is . /, so names without a / are looked up in the container’s root directory.

Example: a script that prints the status of one port every second, three times:

# /tmp/watch.soc  -- usage: rcload /tmp/watch.soc <port>
if !$?1 "echo usage: rcload watch.soc <port>; exit"
loop 3 "ps $1" "sleep quiet 1"

Unvalidated

drivshell> rcload /tmp/watch.soc ce0

A one-line version can be made without leaving the shell:

Hardware-validated

drivshell> save /tmp/watch.soc 'loop 3 "ps $1" "sleep quiet 1"'
drivshell> rcload /tmp/watch.soc ce0
                 ena/        speed/ link auto    STP                  lrn  inter   max   cut   loop
           port  link  Lns   duplex scan neg?   state   pause  discrd ops   face frame  thru?  back   encap
       ce0(  1)  !ena   4  100G  FD   SW  No   Forward         Untag    F    CR4  9122    No          IEEE
                 ena/        speed/ link auto    STP                  lrn  inter   max   cut   loop
           port  link  Lns   duplex scan neg?   state   pause  discrd ops   face frame  thru?  back   encap
       ce0(  1)  !ena   4  100G  FD   SW  No   Forward         Untag    F    CR4  9122    No          IEEE
                 ena/        speed/ link auto    STP                  lrn  inter   max   cut   loop
           port  link  Lns   duplex scan neg?   state   pause  discrd ops   face frame  thru?  back   encap
       ce0(  1)  !ena   4  100G  FD   SW  No   Forward         Untag    F    CR4  9122    No          IEEE

Shell options

set shows and changes the options that control error handling (IFError, LoopError, RCError, RCNoPrintError), the WORD.soc lookup (RCLoad), the test framework (RCTest, ReportStatus, ReportTime) and paging in more (MoreLines). The defaults are listed in Accessing the shell.

Diagnostic tests

The shell includes Broadcom’s diagnostic test suite. testlist lists the tests, testselect chooses which ones a bare testrun runs, testparameters sets their arguments, testmode sets how they run and testclear resets the statistics. Tests reprogram the chip. Run them only on a switch taken out of service.