A Menu Solution for Users and Admins Alike
Graphical user interfaces (GUIs) have become the norm for system administration tools and utilities over the last few years. These GUIs take the form of X Window applications, Web browser-based forms, and Microsoft Windows programs and can provide a richer interface than is possible with a character-cell interface such as a serial terminal or telnet connection. However, such character-cell interfaces are still a fact of life for many admins. Serial terminals continue to be a common interface for many users simply because of a terminal's low cost and because thousands of applications in production are still character based.
I explored the differences between a GUI and a character-cell interface when the requirement for developing a menu-driven front-end for a group of operators fell to the sys admin staff. These operators needed the ability run various UNIX commands, scripts, and utilities to manage backups and to monitor the health of the systems. However, these individuals were not sys admins, and a menu-driven interface would allow them to quickly and safely run the various commands.
The directives were:
- Low (or no) cost
- Quick development
- Robust and flexible
In other words, cheap, fast, and good.
The initial preference was to develop a custom, graphical application using Tcl/Tk. This choice had the advantage of no cost (from the standpoint of not having to purchase a product), but the speed with which a solution could be delivered and the robustness of the final product depended on many factors. This option was ultimately discarded because the operator staff's only access was via the system consoles which, at the time, were serial terminals. Because of this limitation, a graphical interface was ruled out.
The next option was to develop a custom character-cell application and use shell, Perl, or another interpreted or compiled language. Although this option supported the hardware configuration, it suffered from similar disadvantages due to the requirements for in-house development. It was also discarded as an unfeasible solution.
The next option was the purchase of a commercial menu-builder utility. Flipping through the pages of recent issues of Sys Admin turned up several vendors of such tools. These tools certainly satisfied our requirements for fast deployment and, according to the advertising, provided robust and flexible menus. If we had not needed an inexpensive solution, one of these commercial products would have been our choice, especially given the advantage of technical support from the vendor.
So, with no clear solution, we turned to the resources of the Internet. Our searches turned up many hits, but a solution that fit all three original requirements was eventually found: Menu by Paul J. Condie.
Menu is a utility written in C that has been successfully compiled in my workplace on systems running Solaris 2.x, Digital UNIX 3.x and above, and HP-UX 9.x and above. Menu provides fast development of custom menus that can allow easy, controlled execution of any program, utility, or command on the system. Menu also supports multi-level menus and dialog boxes to allow user input that can then be fed to an external utility or program as command-line arguments. The menus themselves are defined in menufiles, which are simply text files containing Menu commands and keywords.
Installing Menu and its Components
Menu can be downloaded from ftp.mfi.com in /pub/sysadmin. After successfully compiling Menu (See the README in the kit), the Menu executable is placed in a directory common to all users' PATH (e.g., /usr/local/bin). Additionally, there are several ancillary files: a global configuration file and a help file. These files should be placed in a common menu directory (e.g., /usr/local/menu), along with locally developed menu script files. This directory is referenced by Menu via the environmental variable MENUDIR, which should be set for all users who will be running Menu. Also, since Menu uses curses(3), the TERM environmental variable must be set correctly.
The global Menu configuration file is .menuinit (Listing 1) and contains initialization commands that primarily specify which keys do what. This configuration file is optional. See the menu(1) man page for all defined options and their default values.
The default help file is menu.hlp and contains general menu navigation and command help. This file can easily be customized to fit your needs and the menu(1) man page details the help file format.
Menu is started by specifying a menu script file as a command-line argument to the Menu executable:
$ menu main.m
Menu searches for menu script files first in the current directory, then in the directory referenced by the variable MENUDIR. If a menu script file cannot be found, Menu exits with an error message and a return code of 1. Always specify the menu script file in basename format.
When Menu is first started, the global configuration file (.menuinit) is searched for first in the current directory, then the user's HOME directory, and finally in the directory referenced by the variable MENUDIR.
Menu can not only be started from the command line, but can also be invoked when a user logs into a system. This approach may be appropriate for a novice or casual user. Instead of specifying Menu as the login shell in the password file for such users, I recommend running Menu from the user's shell startup file. This provides for the setting of important shell environmental variables, such as PATH, TERM, and MENUDIR, before executing Menu. An example Bourne/Korn shell profile (Listing 2) sets these variables, then executes Menu. Menu uses the shell's built-in exec for two reasons: The login shell process exits and is replaced by the Menu process conserving system resources, and, when the user exits from Menu, s/he is logged out.
Because each user's MENUDIR can be unique, different classes of users can be accommodated by separating sets of menu script files into distinct MENUDIRs and assigning the MENUDIR variable appropriately. This allows menus to be organized and managed more effectively.
The Menu Script Files
The heart of the menu program is the menu script files. These script files have, by convention, a .m extension. Figure 1 is a sample menu produced by the example menu script file, sample.m, in Listing 3. The syntax for running this menu is menu sample.m. Obviously, this sample menu is very basic, and in fact the menu developed for our environment consists of a main menu script that calls nine submenu script files, each with a different function, such as backups, system health, etc.
The menu script files can be quickly written and edited without concern for the mechanics of laying out the menu itself. Menu automatically numbers and formats the menu choices, validates user input, and executes the command(s) assigned to a menu choice. A menu choice can run one or more UNIX commands or call a submenu.
There are two types of menu script keywords: those dealing with the menu's format and appearance, and those that specify actions to be taken upon selection of a particular menu choice. All Menu keywords start with a period and are capitalized.
In the sample.m script, the following format and appearance keywords are used:
.TITLE - This keyword specifies a title line at the top of the menu. Multiple title lines can be specified, up to a maximum of six.
.LINE - This keyword draws a line underneath the last title line to split the menu choices portion of the screen from the title portion. Place after the last .TITLE.
.BOX - This keyword draws a box around the entire menu.
.TEXT - This keyword displays a text string at a specified row and column on the screen.
.SPACE - This keyword is placed between .SYSTEM keywords (see below) to insert a space in the menu layout.
The action keywords are the meat of the menu script as they actually define what each menu option does.
.SYSTEM - This keyword specifies both the text of the menu option and which command(s) to execute when the menu option is selected. Separate multiple commands with semicolons and backslashes (;\). The maximum length of the command(s) under a particular .SYSTEM is 1024 characters. This limitation can be overcome by simply calling a shell script, which can be as long as necessary.
.EXIT - This keyword is used to exit the menu script file and is used to provide a user selectable Exit option. There should be only one .EXIT per menu script file.
The menu(1) man page details the syntax of these and other format/appearance and action keywords.
Benefits of Menu
Menu quickly became indispensable due to the speed with which we could roll a set of menus for any given application or situation. The initial requirement was to produce a menu-driven front-end for a group of operators, but we have subsequently created a set of menus for novice UNIX users that "shelter" them from UNIX and allow them to become productive immediately. In addition, the sys admin staff can quickly generate extremely robust menu solutions, freeing them to concentrate on more demanding tasks.
An additional advantage of using Menu has been the ability to change the underlying programs that Menu calls without changing the interface, thus preventing additional training. During the past year, the backup utilities have been upgraded several times, and, after the required menu script file adjustments were made to accommodate new and changed commands and arguments, the menus themselves continue to look and function as before. The operators remain blissfully unaware that these major upgrades even took place.
I have, by no means, covered all the features of Menu; instead I hope I have interested you enough to download and install Menu, read the man page, and begin creating menus. I hope you find Menu as useful as I have.
Finally, credit for this wonderful tool goes to Paul Condie, the author of Menu. I was unable to locate Mr. Condie to determine the present status of Menu and would be interested in hearing from him or any other reader who might have information on Menu.
About the Author
Matt Cheek has been a UNIX system admin since 1988 and currently works for MCI Telecommunications in Colorado Springs, CO where he supports a variety of mission-critical systems both in development and production. He can be reached at firstname.lastname@example.org.