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 :
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.
&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.
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 "
$text{'list_user'}
\n";
print "
$text{'list_real'}
\n";
print "
\n";
@users = &list_users();
foreach $u (@users) {
print "
\n":
print "
<a href='edit.cgi?user=",
&urlize($u->{'user'}),"'>$u->{'user'}
\n";
print "
$u->{'real'}
\n";
print "
\n";
}
print "
\n";
print "\n";
&footer("", $text{'index_return'});
The important lines in the example above are :
#!/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.
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.
&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.
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.
@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.
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.
print "
\n"; These lines produce the HTML for the end of the table and the traditional final horizontal line.
&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
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:
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.
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.
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 "
Foo
Bar
\n"; print "
some value
another value
\n";
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.
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.
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.
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 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.