Webmin Module Development

This chapter should be read if you are planning to write your own Webmin module, as it explains all the requirements for creating a usable module.

Introduction

Webmin is designed to allow the easy addition of new modules without changing any of the existing code. A module can be thought of as something like a Netscape or Photoshop plugin - it can be written by someone other than the developers of Webmin, and distributed under a and license the developer chooses.

A module should be written to administer one service or server, such as the Unix password file or the Apache web server. Some complex system functions may even be split over several modules - for example, disk partitioning, mounting disks and disk quota management are 3 separate modules in the standard Webmin distribution.

Modules can theoretically be written in any language. However, to make use of the Webmin API Perl version 5.002 or above should be used. A module should be written entirely in Perl, with no C functions or external binary programs. The aim is for modules to be as portable as possible across different Unix systems and CPU types.

Modules written in other languages will not be displayed using the default theme included with recent versions of Webmin. This theme replaces the standard Perl header function with its own that displays category icons at the top of every page. For this reason, using Perl is strongly recommended.

At their simplest, modules are really just directories of CGI programs that Webmin's web server runs. However, there are certain rules that should be followed to make sure that they work with the Webmin API, main menu and access control system. Even though you can just stick any existing CGI script into a module directory, this is not a good idea.

Required Files

Every module has its own directory under the Webmin base directory, in which all the module's CGI programs and configuration files must be stored. For example, if the Webmin base was /usr/local/webmin-1.060, a module called foobar would be installed in /usr/local/webmin-1.060/foobar.

For a module to be displayed on the main Webmin menu, it should contain at least the following files. Only module.info is mandatory though.

images/icon.gif The icon displayed on the main menu for this module. The icon should be 48x48 pixels, and should use the same colour scheme as the other icons on the main menu.

module.info This file contains information about the module and the operating systems it runs under. Each line of the file is in the format _name_=_value. _Required names and their values
are
name A short name for this module, such as FooAdmin.

desc A longer description for the module, such as Foo Web Server. This is the text that will appear below the icon on the main menu.

os_support A space-separated list of operating systems that this module supports. The module will only be displayed on the main menu if the OS Webmin is running on is in the list, or if there is no os_support line at all. Unless your module configures some service that only exists on a few operating systems (such as XFree86), this line should be omitted instead of trying to list all of those supported by Webmin. The actual operating system codes used in this line can be see in the third column of the os_list.txt file in the Webmin root directory, and are the same as those that can be appended to the names of config- files, as explained in the "Module Configuration" section. To specify only a certain version of some OS, add it to the OS name after a slash. For example, a module.info file might contain : os_support=redhat-linux open-linux suse-linux/8.1 If your module supports all Linux distributions both no other operating systems, you can use the OS code *-linux in this line.

lang/en The text strings used by this module, as explained in the "Internationalization" section in chapter 56.

Each icon on the main menu is a link to the module directory. Thus you must have an index.cgi or index.html file to be displayed when the user clicks on the icon. A typical module contains many .cgi programs that are linked to from index.cgi, each of which performs some function such as displaying a form or saving inputs from a form.

When you first create a new module, it will not be in the ACL of any Webmin user and so you will not be able to see it in the main menu. You must first delete the file /etc/webmin/module.infos.cache to clear the cache of known modules. Then to make your module visible, either edit the file /etc/webmin/webmin.acl, or use the Webmin Users module to grant yourself access.

Module CGI Programs

The Webmin web server treats files with the extension .cgi as CGI programs, just like most other web servers. All the forms, menus and other pages in your module will be generated by CGI programs, so knowledge of the basic concepts of CGI programming and HTML is necessary for writing a module.

All CGI programs are run with root privileges, which is generally necessary for them to be able to edit configuration files. In some cases your code may drop those privileges by switching to another user, for example if the module's access control settings for some Webmin user specify it.

Assuming your module is being written in Perl, you should begin by writing a Perl script that contains functions used by the CGI programs in your module. This script is usually called something like lib.pl or foobar-lib.pl. A minimal example of such a script might look like :

# foobar-lib.pl

# Common functions used for managing the foobar user list

do '../web-lib.pl';

&init_config();

# list_users()

# Returns a list of all foobar users

sub list_users

{

...

}

The 3 important lines in the example above are :

  1. do '../web-lib.pl'; The file web-lib.pl in the Webmin root directory contains a large number of functions that are useful for developing Webmin modules. All CGI programs should indirectly or directly require this module. You should use do instead of require, as the latter statement will not re-read a file that has already been read in the same Perl program. This causes problems if your module is called from some other module with the foreign_require function.
  2. &init_config(); This function (defined in web-lib.pl) initializes the following global variables : %config Contains the current configuration for this module. This typically is used to store user editable options and operating system specific information. Module config files are described in more detail below. %gconfig Contains the global Webmin configuration. See below for more details. $module_name The name of this module, which is just the name of the directory the module is in. $module_config_directory The directory in which this module's config file is stored. If your module creates permanent files or programs for some reason (such as print driver scripts), they should be created in or under this directory. $tb The background colour for table headers. $cb The background colour for table bodies. $scriptname The name of the CGI program currently being run, relative to the directory it is in (such as save_foo.cgi). $remote_user The username that the current user logged into Webmin with. $base_remote_user The username whose permissions are currently in effect. Most of the time this will be the same as $remote_user, but if you have the Configure Unix user authentication option setup in the Webmin Users module, this will be set to the name of the user whose permissions are used. $current_theme The name of theme in effect for the current user. $root_directory The root directory of the Webmin install, such as /usr/libexec/webmin. $module_root_directory The root directory of the current module, such as /usr/libexec/webmin/modulename. %module_info Information about the current module, from its module.info file. $current_lang The short code for the language currently being used, such as en or de. %current_lang_info A hash containing information about the current language, with keys like desc for the language name and titles indicating if graphical titles can be used. Mostly useful to theme developers.
  3. The list_users function This is an example of a function that might be used by various CGI programs in this module. Some module library files may also include another file containing functions specific to the current operating system or configuration. See the proc-lib.pl in the proc module as an example.

A CGI program called list.cgi in this same module might look something like :

#!/usr/bin/perl

# list.cgi

# Display the list of foobar users

require './foobar-lib.pl'

&header($text{'list_title'}, "");

print "
\n";

print "\n";

print "
\n";

print "
\n";

print "
\n";

print "
\n";

@users = &list_users();

foreach $u (@users) {

print "
\n":

print "
\n";

print "
\n";

print "
\n";

}

print "
$text{'list_user'} $text{'list_real'}
<a href='edit.cgi?user=",

&urlize($u->{'user'}),"'>$u->{'user'}
$u->{'real'}
\n";

print "
\n";

&footer("", $text{'index_return'});

The important lines in the example above are :

  1. #!/usr/bin/perl All CGI programs must start with a #! line containing the path to the Perl interpreter on your system. This should be the same as the path that Webmin itself uses, found in the /etc/webmin/perl-path file.
  2. require './foobar-lib.pl'; CGI programs should include the module's library with a line like this, so that init_config is called and functions defined in the library are available.
  3. &header($text{'list_title'}, ""); Any CGI that is going to produce HTML output should called the header function to produce a page title. In this case, the actual title is coming from a file in the lang directory which has been read into %text. Traditionally a horizontal line is output directly after the header as well, as in this example. Only programs that are going to later call redirect should not call header, or produce any HTML with print statements.
  4. The five lines starting with print "\n"; These lines output the HTML for the header of the table that the CGI is going to generate.
  5. @users = &list_users(); This line is a call to the list_users function defined in foobar-lib.pl, which presumable returns an array of users.
  6. The seven lines starting with foreach $u (@users) { This loop outputs the table rows, each of which contains a link to another CGI program in the module. Note the use of the urlize function to convert the username into a form suitable for a URL parameter.
  7. print "
  8. \n"; These lines produce the HTML for the end of the table and the traditional final horizontal line.
  9. &footer("", $text{'index_return'}); Every CGI program that calls header must call footer as well, which generates the HTML needed to properly finish the page.

The corresponding parts of the lang/en file for this CGI program might look like :

list_title=Foobar User List

list_user=Username

list_real=Real name

All modules that use internationalization must include a lang/en file, and can also include other files in lang for other languages. Of course, there is no requirement that you actually make use of Webmin's internationalization features – you can just put hard-coded text strings into the code instead.

Module Configuration

Almost all modules have a set of configuration parameters, available to module CGI programs in the %config array which is set by the init_config function. When Webmin or a module is installed, a configuration file appropriate for the chosen operating system is copied from the module directory to the Webmin configuration directory for that module, typically something like /etc/webmin/foobar/config.

The associative array %gconfig contains global configuration options, typically from the file /etc/webmin/config. Some useful entries are :

os_type The operating system type selected in setup.sh or automatically at install time, such as solaris or redhat-linux.

os_version The operating system version selected at installation, such as 2.5 or 5.1

path The Unix path for this operating system, as a colon separated list of directories. This is also available in $ENV{'PATH'}, as thus to any programs that you module runs.

Many modules deal with the configuration of some service that is mostly the same on different operating systems. Apache for example works exactly the same under Solaris and Redhat Linux - the only difference is the standard location of the Apache configuration files. In the Webmin Apache module the Apache config file directory is itself a configurable parameter that is initially set based on the operating system chosen.

Configuration parameters can also be used for options that the user may want to occasionally change. For example, the BIND module has a parameter that controls for format of new DNS zone serial numbers. When the 4th parameter of the header function is set, a link will be generated to a CGI program that allows the user to edit the configuration of the current module. This program reads the file config.info in the module directory to determine the possible values for each configuration parameter. A typical config.info file might look like :

foobar_path=Path to foobar config file,0

display_mode=Index page display mode,1,0-Long,1-Medium,2-Short

password_file=Foobar server users file,3,None

file_user=Config files are owned by user,5

Each line is in the format config_name_=_description,_type_[,_values_]. The meanings of the parts of each line are :

config_name The name of a parameter in the module configuration that this line will apply to.

description A description of this parameter for the user.

type A number that determines how this parameter can be chosen. Possible values are : 0 Free text. Any value can be entered by the user 1 One of many. The user can choose one of several options. For this type, the values part of the line is a comma-separated list of value_-_display pairs. The value part of each pair is what gets stored in the config file, while the display part is what is shown to the user. 2 Many of many. The user can choose zero of more of several options. Available options are specified in the same way as type 2. 3 Optional free text. The user can either select the default option, or enter some value. The values part of the line is the description of the default option (typically something like 'None' or 'Default mode') 4 One of many. The same as type 1, but uses a menu instead of a row of radio buttons 5 Unix user. Displays a list of users from the host Webmin is running on. 6 Unix group. Displays a list of groups from the host Webmin is running on. 7 Directory. Like the free text input, but with a directory chooser next to it. 8 File. Like the free text input, but with a file chooser next to it. 9 Multiline free text. The first value after the type is the width of the input, and the second the height. 10 Like type 1, but with an additional option for entering free text of the user's choice. 11 A parameter of this type does not allow the user to enter anything, but instead puts a section header row containing the description into the configuration form at this point. 12 A field for entering a password, without actually displaying the current value.

Not every configurable parameter needs an entry in config.info - only those that the user may want to edit.

When a module is installed (either as part of a Webmin distribution or separately) a configuration file appropriate to the OS being used is copied from the module directory to the configuration directory (usually under /etc/webmin). To decide which base configuration file to use, Webmin uses the OS name and version chosen when setup.sh was run at installation time to look for the following files

config-_osname_-_osversion_

config-_osname_

config

Where osname is something like redhat-linux or solaris, and osversion is something like 2.6 or 5.0. A typical module might have the following configuration files :

config-redhat-linux

config-redhat-linux-5.0

config-slackware-linux

config-debian-linux

config-solaris

Webmin treats each of the Linux distributions as a different OS, as each has different locations for things like the Apache configuration file, crontab files and bootup scripts. The OS version number for Linux should be the distribution version (such as 4.1 or 5.0) rather than the kernel version.

On Linux systems, the file config-*-linux will be used if no specific file exists for the Linux distribution installed. This can be useful if you want to create settings for all variants of Linux, without having to define a file for each individually. However, actually creating such a file can be a bit tricking in most shells, as * is the wildcard character. Just precede it with a backslash to escape it.

Look and Feel

All Webmin modules should have the same general color scheme, look and feel as defined by the following rules:

  1. All pages should be viewable on any browser that supports images, tables and forms. Browser features such as frames, DHTML, Javascript or Java should not be used unless there is no other option. It should be possible to use Webmin from browsers such as Netscape 1.1 or Pocket IE.
  2. All CGI programs that generate HTML output should call the header function. This ensures that a standard page heading is generated, according to the theme in use. The only exception is a CGI that does not want any heading at all, such as one used in a pop-up selection window.
  3. The header function outputs HTML tags setting the background, text and link colors for the generated page based on the chosen theme and color scheme. The init_config function sets the global variables $tb and $cb which should be used as the background color for table headers and body rows respectively, as in this example : print "\n"; print "\n"; print "\n";
  4. Try to avoid generating HTML forms that contain a large number of input fields. Some browsers (particularly Netscape on Unix) slow down when rendering such pages.
  5. Your module's main page (usually index.cgi) should set the config and noindex parameters of the header function to 1, assuming that the module does have a config.info file. This ensures that a Module Config link appears on the main page, and that the Module Index link does not.
  6. Other pages in the module should call header with the title parameter of set to the title that you want to appear, and the image parameter to an empty string. This ensures that a conventional title is displayed, and that a Module Config link back to the main page appears.
  7. Design Goals

    A typical Webmin module is written to configure some Unix service, such as Apache, Squid or NFS exports. Most Unix servers are normally configured by editing some text file, which may have a complex format. Any Webmin module that modifies some configuration file must be able to parse all possible options in such a configuration file - even if not all options are presented to the user.

    No module should ever corrupt a service configuration file or remove options that it does not understand. Modules should be able to parse any valid configuration without requiring special comments or a special format. If your module cannot deal with some option in a file, it should be left alone.

    Webmin modules should be designed to be easy for novices to use, but still allow the user to do almost everything that could be done by editing the configuration file directly. However, in some cases configurations options will exist that very few users will need to edit, or that do not lend themselves to be edited through a GUI. These kind of settings should be left out of your Webmin module if they would clutter up the user interface with' their presence.

    Online Help

    Webmin versions 0.63 and above have support for context-sensitive help. The hlink function outputs HTML for a link to a CGI program that processes and displays a given help page. Help pages are stored in the help subdirectory under the module directory, and are named simply page.html for those in English. So a call to hlink like

    print &hlink("Enter username:", "name"),

    "

    \n";

    would output a link to display the help page help/name.html.

    If the help parameter to the header function is set, a link labeled Help to the specified help page is included in the heading. This can be useful if you have created some documentation that explains what the entire page does in general, instead of or as well as documenting fields individually. The same rules about help HTML file selection apply.

    Even though online help is not mandatory (or even common) in Webmin modules, it can useful to provide additional information to users about what a field really means or what the purpose of a page is. In many cases inputs are not self-explanatory and need additional documentation, so why not make it available from the page itself?

    As the "Internationalization" section of chapter 56 explains, Webmin modules can support multiple languages through the use of alternative translation files in the lang subdirectory. Help pages can exist if more than one language as well, by creating files named like page._language_.html in the help subdirectory. If such a file exists, it will be used in preference to page.html, which is assumed to be in English. For example, to add a German version of an existing name.html page you would need to create name.de.html.

    Module Packaging

    The Webmin Configuration module allows the user to add a new module to their existing setup. Modules must be packaged as an optionally compressed Unix TAR file containing one or more modules. Each module in the TAR file must have all its files in one subdirectory - for example, a module TAR file might look like :

    drwxrwxr-x 3001/10 0 Aug 12 21:53 1998 dfsadmin/

    drwxrwxr-x 3001/10 0 Nov 7 01:10 1997 dfsadmin/images/

    -rw-rw-r-- 3001/10 245 Aug 1 23:41 1998 dfsadmin/images/icon.gif

    -rw-rw-r-- 3001/10 1438 Aug 1 23:41 1998 dfsadmin/images/dfsadmin.gif

    -rw-rw-r-- 3001/10 1541 Aug 1 23:41 1998 dfsadmin/images/create_share.gif

    -rw-rw-r-- 3001/10 1265 Aug 1 23:41 1998 dfsadmin/images/edit_share.gif

    drwxrwxr-x 3001/10 0 May 16 18:32 1997 dfsadmin/test/

    -rw-r--r-- 3001/10 493 May 16 18:32 1997 dfsadmin/test/dfstab

    -rw-r--r-- 3001/10 483 May 16 18:15 1997 dfsadmin/test/dfstab.bak

    -rw-rw-r-- 3001/10 2774 Jul 29 22:22 1998 dfsadmin/dfs-lib.pl

    -rwxr-xr-x 3001/10 1582 Mar 31 15:45 1998 dfsadmin/index.cgi.bak

    -rw-rw-r-- 3001/10 49 Aug 12 21:53 1998 dfsadmin/module.info

    -rwxr-xr-x 3001/10 1596 Mar 31 15:45 1998 dfsadmin/index.cgi

    -rw-rw-r-- 3001/10 2775 Jul 29 22:22 1998 dfsadmin/dfs-lib.pl.bak

    -rw-rw-r-- 3001/10 199 Mar 5 19:30 1998 dfsadmin/help.html

    -rw-rw-r-- 3001/10 175 Mar 5 19:30 1998 dfsadmin/config.info

    -rw-r--r-- 3001/10 140 Mar 5 19:30 1998 dfsadmin/config-solaris

    -rwxr-xr-x 3001/10 142 Mar 5 19:30 1998 dfsadmin/delete_share.cgi

    -rwxr-xr-x 3001/10 4842 Mar 5 19:30 1998 dfsadmin/edit_share.cgi

    -rwxr-xr-x 3001/10 657 Jun 8 15:02 1998 dfsadmin/restart_sharing.cgi.bak

    -rwxr-xr-x 3001/10 3000 Mar 5 19:30 1998 dfsadmin/save_share.cgi

    -rw-rw-r-- 3001/10 57 Aug 12 21:53 1998 dfsadmin/module.info.bak

    -rwxr-xr-x 3001/10 573 Jun 8 15:02 1998 dfsadmin/restart_sharing.cgi

    The standard extension for Webmin modules is .wbm, but any filename can be used. If you compress the module, it can have a .wbm.gz or .wbm.Z extension instead.

    Webmin modules can also be packaged as RPMs, which are suitable for installing on servers on which the RPM version of Webmin itself is already installed. You can download a script called makemodulerpm.pl from http://www.webmin.com/makemodulerpm.pl that can package up an module directory into an RPM by creating the spec file automatically.

    Learning more

    The information and examples in this chapter should be all you need to know to start writing your own modules. Chapter 56 explains some of the more advanced possibilities in module development such as logging, locking and access control. Chapter 60 lists all of the functions that are available in web-lib.pl to module writers, which can be used to give your module a similar look and feel to standard modules, simply the process of editing configuration files and much more.

    The best source of information about module development is the source code of Webmin itself. Have a look at it to see how the standard modules are written, and read chapter 57 which takes you though the Scheduled Cron Jobs module.

    For information on creating themes, which are similar to modules in many ways, read chapters 58 and 59. These cover the basics of theme creation, and the implementation of the default MSC theme respectively.


    Doxfer is docs for...anything!Copyright © by the contributing authors. All material on Doxfer is the property of the contributing authors.
    Ideas, requests, problems regarding Doxfer? Send feedback

    Foo Bar
    some value another value