• This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn more.

HowTo: Create a manpage from scratch.

fbsd1

Active Member

Thanks: 50
Messages: 215

#1
Creating a manpage from scratch.


What is a manpage?
The FreeBSD documentation manuals system is comprised on many manuals that
are intended to by displayed on-line from the command line using the
“man” command. Every Base RELEASE command has it’s own manual as well as
the commands introduced by the ports system. The layout of the manual is
standardized by the use of groff_mdoc(7) documentation macro markup
language. The files containing the source for each manual are located in
the /usr/share/man/manX/ directory tree, where the X of manX is one of
the following sections.


Code:
    Under FreeBSD 8.0, the following sections are defined:

		   1	    FreeBSD General Commands Manual
		   2	    FreeBSD System Calls Manual
		   3	    FreeBSD Library Functions Manual
		   4	    FreeBSD Kernel Interfaces Manual
		   5	    FreeBSD File Formats Manual
		   6	    FreeBSD Games Manual
		   7	    FreeBSD Miscellaneous Information Manual
		   8	    FreeBSD System Manager's Manual
                   9        FreeBSD Kernel Developer's Manual
So you would see this

Code:
               /usr/share/man/man1/
               /usr/share/man/man2/
               /usr/share/man/man3/
               /usr/share/man/man4/
               /usr/share/man/man5/
               /usr/share/man/man6/
               /usr/share/man/man7/
               /usr/share/man/man8/
               /usr/share/man/man9/

Manual File Naming Standard.
Code:
There is a standardized naming convention in place for manpage files:
       name.X.gz

Where name = the name of the command being documented.
       X   = the manual section its in from the above path list.
       gz  = means the file has been compress with gzip(1) command.
The file itself is a text file with the documentation being prefixed and
sometimes enclosed with formatting macros from groff_mdoc(7) markup language.
Take note; The macro text file should contain no blank lines in it.


Creating The Manual Source File.
The best way to get started is to just copy a man page from the base system
and edit it to taste. As the system administrator I always login as user
root so the following command examples and manual sample are developed in /root.

The manual for the jail(8) command will be used as the template for my new manual ezjail.

Code:
 cd /root
 cp /usr/share/man/man8/jail.8.gz /root/   # get my own copy of file.
 mv jail.8.gz ezjail.8.gz                  # rename the file.

 gunzip ezjail.8.gz                        # unzip the file.
 ee ezjail.8                               # edit the text file.
The start of the text file has the standard FreeBSD copyright comments. Delete all
these comments. All groff_mdoc(7) documentation line macros begin with an period “.”
Then an uppercase letter followed by a lowercase letter. The following discussion
has comments to the right and these comments are not part of the macro command syntax,
but put here to explain what’s happening. So starting the new ezjail manpage text file is;


# Setup the manual format section.
Code:
.Dd July 22, 2010       # Date displayed on center of last line.
.Dt EZJAIL 8            # Name and section of this manpage, 
                        # has to be in uppercase letters,
                        # displays left & right corners of top line.
.Os                     # Displays RELEASE version in left & right
                        # corners of last line.

# This is how the man command displays the first and last lines.

Code:
EZJAIL(8)      FreeBSD System Manager's Manual       EZJAIL(8)

FreeBSD 8.0               July 22, 2010            FreeBSD 8.0
# Setup the highlighted first two lines you see.
Code:
.Sh NAME                # Section header name in uppercase letters.
.Nm ezjail              # Name to display.
.Nd “description”       # short description of command.

# This is what is displayed by the man command
Code:
[B]NAME[/B]
     [B]ezjail[/B] -- description
# Setup the command syntax section
Code:
.Sh SYNOPSIS            # Section header name in uppercase letters.
.Nm                     # Display saved name.
# The following macros format the flags in bold and/or with brackets
# and with white background / black letters. 
.Op Fl dhi              
.Op Fl J Ar jid_file
.Op Fl l u Ar username | Fl U Ar username
.Op Fl c | m
.Br
.Nm
.Op Fl hi
.Op Fl n Ar jailname
.Op Fl J Ar jid_file
.Op Fl s Ar securelevel
.Op Fl l u Ar username | Fl U Ar username
.Op Ar path hostname [ip[,..]] command ...
# This is what is displayed by the man command
Code:
[B]SYNOPSIS[/B]
     [B]jail[/B] [-dhi] [-J jid_file] [-l -u username | -U username] [-c | -m]
     [B]jail[/B] [-hi] [-n jailname] [-J jid_file] [-s securelevel]
          [-l -u username | -U username] [path hostname [ip[,..]]

# This is a real pain to play with. So I used the short method like this.
It displays the text just as written with no bold and no white boxes.
This method is simpler and makes the manpage easier to read without all
those white-boxed words. The layout will be the same as what is shown above.


Code:
.Sh SYNOPSIS            
.Nm                       
[-dhi] [-J jid_file] [-l -u username | -U username] [-c | -m]
.Nm
[-hi] [-n jailname] [-J jid_file] [-s securelevel]
.Br                              # this means next line
[-l -u username | -U username] [path hostname [ip[,..]]

# The description section with the meaning of the flags comes next.
Code:
.Sh DESCRIPTION
The jail utility creates a new jail or modifies an existing jail, 
imprisoning the current process (and future descendants) inside it.
.Pp                            # blank line position holder.
The options are as follows:
.Bl -tag -width indent         # indent everything that follows.
.It Fl d                       # adds the dash and bolds them both.
Allow making changes to a dying jail.
.It Fl h                       # adds the dash and bolds them both.
Resolve the host.hostname parameter (or hostname) and add
all IP addresses returned by the resolver to the list of
ip addresses for this jail.  
.El                             # end the indented section.

# This is what is displayed by the man command
Code:
[B]DESCRIPTION[/B]
     The jail utility creates a new jail or modifies an existing jail,
     optionally imprisoning the current process (and future
     descendants) inside it.

     The options are as follows:

     [B]-d[/B]      Allow making changes to a dying jail.

     [B]-h[/B]      Resolve the host.hostname parameter (or hostname) and add
             all IP addresses returned by the resolver to the list of
             ip addresses for this jail.

# The short method I used like this.
Code:
.Sh DESCRIPTION
The jail utility creates a new jail or modifies an existing jail, 
imprisoning the current process (and future descendants) inside it.
.Pp                            # blank line position holder
The options are as follows:
.Bl -tag -width indent         # indent everything that follows
.It \fB-d\fR                   # adds the bold 
Allow making changes to a dying jail.
.It \fB-h\fR                   # adds the bold 
Resolve the host.hostname parameter (or hostname) and add
all IP addresses returned by the resolver to the list of
ip addresses for this jail
.El                            # End the indented section.
# This is an example of the special enclosure macro that bolds any word
or words its wrapped around. \fB 10.0.10.2 \fR will display as 10.0.10.2


General format notes.
The manual standards specify the following sections as mandatory.

Code:
.Sh NAME
.Sh SYNOPSIS
.Sh DESCRIPTION
Which have been covered all ready. At the end of the manpage there are a
few more mandatory sections required in all manpages.

Code:
.Sh FILES           # Section header name in uppercase letters.
/usr/local/etc/ezjail.conf
.br
/usr/local/bin/ezjail

.Sh SEE ALSO        # Section header name in uppercase letters.
.Xr killall 1 ,
.Xr lsvfs 1 ,
.Xr newaliases 1 ,
# or you could just say
killall(1), lsvfs(1), newaliases(1) 


.Sh AUTHORS         # Section header name in uppercase letters.
.An Tom Jones
.Aq tjones@home.com
# or you could just use
Tom Jones  tjones@home.com
Now in between the Description section and the FILES section you can make
as many sections as you want by using the .Sh macro. Example

Code:
.Sh USAGE EXAMPLES
.Sh HISTORY
.Sh BACKGROUND
 

fbsd1

Active Member

Thanks: 50
Messages: 215

#2
Testing method.
I have found it convenient to use 2 sessions for testing.
In the F1 session I cycle through these commands

Code:
gunzip ezjail.8.gz
ee ezjail.8
gzip ezjail.8
cp ezjail.8.gz /usr/local/man/man8/
And then from the F2 session I issue
Code:
man 8 ezjail
I can then read my new manpage looking for format, word spacing, sentence
wrapping, errors and verifying that all special bolding is working.
Swapping between the edit of the manpage text source on the F1 session
and the view of the displayed manpage on the F2 session making any changes
to the source as necessary. Then ending the edit, gziping the file and
coping it to it’s running location. Where in the F2 session I enter ctlr-c
to close the old manpage view and then man 8 ezjail again to view the
just update version.

I have found that sometimes it’s convenient to render the groff source as
pure ascii text. Groff will complain if the raw macro source has blank
lines in it and gives you the line number of macros with syntax errors.

Code:
groff -mdoc -Tascii ezjail.8 | more  

groff -mdoc -Tascii ezjail.8 > ezjail.raw.text

gzcat ezjail.8.gz | groff -mdoc -Tascii | less
 

carlton_draught

Well-Known Member

Thanks: 30
Messages: 288

#3
I'm about halfway through creating a man page of my own. (No laughing at the back!) Some really good suggestions here. The process of personally writing a man page makes man pages in general much less cryptic and hence, more useful. I'd strongly recommend also doing the following:

# man mdoc

I struggled with the synopsis for quite a while until I started to make sense of the syntax. Good luck. Do read that man page on how to create man pages, it's long but helpful. There is some rhyme and reason to the synopsis. gunzip as many man pages as it takes to see how they work; some are better examples than others.

I took the suggestions of fbsd1 and in one terminal I edited the file and on the other I ran the following script to view the man page as man sees it:
Code:
#!/bin/sh
# This tests a manpage
manpage=$1
manpageno=$2
gzip -f "$manpage"."$manpageno"
cp "$manpage"."manpageno".gz /usr/local/man/man"$manpageno"/
man "$manpage"
Name the script as test_manpage. To run it, have your prototype man page named something like mymanpage.8 and type something like the following to view it:

# ./test_manpage mymanpage 8

Good luck.
 

ckester

Well-Known Member

Thanks: 38
Messages: 288

#4
Be aware that there is a plan underway to move groff to ports and put textproc/mdocml in base instead. (The reason is that groff -- like gcc, for which clang is a planned replacement -- is GPLv3-licensed.)

This won't affect most of the advice given in this thread, but it does mean you should probably avoid using any groff-specific tricks in your manpage.

mdocml has its own manpages documenting the man and mdoc macros. If you use these instead of the groff manpages, you'll avoid any surprises when the switch is finally made.
 

wblock@

Administrator
Staff member
Administrator
Moderator
Developer

Thanks: 3,558
Messages: 13,856

#5
carlton_draught said:
...
I took the suggestions of fbsd1 and in one terminal I edited the file and on the other I ran the following script to view the man page as man sees it:
Rather than actually install the file each time for testing, you can just directly process it:
# groff -Tascii -mdoc mymanpage | less
 

carlton_draught

Well-Known Member

Thanks: 30
Messages: 288

#6
ckester said:
This won't affect most of the advice given in this thread, but it does mean you should probably avoid using any groff-specific tricks in your manpage.
Thanks for the heads up. I did read something about groff being replaced, but didn't know what the practical ramifications of that were. Is primarily using the mdoc man page as a source for writing mine ok? I just installed mdocml from ports and it doesn't seem to come with a man page. I figured that whoever was writing a replacement would try their hardest to make it as compatible as possible with the existing man page base rather than make 100 times as much work for everyone.

Edit: nevermind, I see you've linked to some man pages for me to read, thanks.
 

carlton_draught

Well-Known Member

Thanks: 30
Messages: 288

#8
Carpetsmoker said:
There is also txt2tags, which can generate manpages
http://txt2tags.sourceforge.net/

IMHO it works better than the awkward troff syntax. It's also easier to convert to other formats such as text/html/pdf.
I haven't yet tried the text2tags program. Like probably everyone else, I was put off at first by the somewhat awkward syntax. And it is still difficult to find your place in it due to all the newlines, without using the search function in your text editor. But now I'm getting more comfortable with it I find that there is a method to the madness, similar to the concepts behind Latex as opposed to a WYSIWYG word processor. If each man page writer is forced to concentrate on the content of what they write rather than the presentation, consistent formatting is possible for all man pages. With consistent formatting, it should be easier to understand any given man page.

It's kind of similar to the advice here. Rather than everyone try to create their own crappy standard for denoting files, code, output from code and commands, use the forum standard ones which have had more time devoted to devising them.

On another note (not directed to you), probably my best advice to making your man pages more useful is to include as many examples as you can of how you would use your program - lots of people (myself included) find it easier to begin with an actual working example to hack than attempt to figure out how to do something from scratch. So make it easy for those people by including lots of useful examples in an examples or usage section. Just because man pages have a reputation for being inscrutable doesn't mean yours has to be.
 

ckester

Well-Known Member

Thanks: 38
Messages: 288

#9
carlton_draught said:
Thanks for the heads up. I did read something about groff being replaced, but didn't know what the practical ramifications of that were. Is primarily using the mdoc man page as a source for writing mine ok? I just installed mdocml from ports and it doesn't seem to come with a man page. I figured that whoever was writing a replacement would try their hardest to make it as compatible as possible with the existing man page base rather than make 100 times as much work for everyone.

Edit: nevermind, I see you've linked to some man pages for me to read, thanks.
The mdocml manpages include a COMPATIBILITY section which is definitely pertinent.

The groff manpages usually call out groff-specific stuff as a "GNU troff extension".

As far as I know, if you write to mdocml's spec for mdoc, your manpage will still work with groff. Hence my recommendation that any new manpages be written for it rather than groff.
 

wblock@

Administrator
Staff member
Administrator
Moderator
Developer

Thanks: 3,558
Messages: 13,856

#11
killasmurf86 said:
or even more simply $ man ./manpage.1 works just as fine, and easier to remember
That's so simple that it didn't occur to me! In my defense, sometimes it's useful to know how groff is called by man.
 

kristaps

New Member

Thanks: 5
Messages: 1

#12
Hi,

Many parts of this "Howto" are flat-out wrong. For example:

- Macros `Br' and `br' should not be used: they're not standard mdoc macro (they're not even necessary in the SYNOPSIS).
- The \f escapes should not be used: they are troff escapes that should be semantic mdoc macros instead.
- Blank lines are not allowed in mdoc documents.
- The hash `#' is NOT a comment token (that would be \").
- Not all man(1) utilities support "man ./somefile".
- Using flat "ref1(1), ref2(1), ref3(1)" in SEE ALSO is horrendously wrong. Use `Xr'.

Most of all, please DO NOT use txt2tags and DO NOT try to style your manual. A manual consists of semantically-meaningful terms, such as function names or variable types. Your job, as a manual writer, is to encode these. Not to style your manual with colours and fancy fonts. txt2tags and other systems (perlpod, etc.) produce pretty-printed documents, not manuals. By using these and similar tools, or "styling" as you see fit, you're screwing readers who want consistent, machine-parsable manuals.

If you'd like to help produce quality "howto" materials for UNIX manuals, please jump over to manpages.bsd.lv and read and/or contribute to the ones there.
 

estrabd

Active Member

Thanks: 6
Messages: 171

#13
ckester said:
Be aware that there is a plan underway to move groff to ports and put textproc/mdocml in base instead. (The reason is that groff -- like gcc, for which clang is a planned replacement -- is GPLv3-licensed.)

This won't affect most of the advice given in this thread, but it does mean you should probably avoid using any groff-specific tricks in your manpage.

mdocml has its own manpages documenting the man and mdoc macros. If you use these instead of the groff manpages, you'll avoid any surprises when the switch is finally made.
Whoa, this affects my port, www/vee, which assumes groff is in base. Thanks!
 

UNIXgod

Daemon

Thanks: 199
Messages: 1,089

#14
estrabd said:
Whoa, this affects my port, www/vee, which assumes groff is in base. Thanks!
It looks like textproc/mdocml includes roff(7) so hopefully there shouldn't be much of a migration for your port if there is any at all. I don't know if it will be a classical runoff or one with extensions.
 

sko

Well-Known Member

Thanks: 131
Messages: 296

#15
As I just dipped my toes into modifying a manpage, I'd like to update this thread with the notes of what I discovered/learned in the process and to account for some changes that have been made in the toolchain.

At first, the markup language used in current BSD (and illumos) manual pages is mdoc(7) and groff has been replaced in the base system with mandoc(1).
However, I also found it helpful (and kind of interesting) to at least get a rough overview of groff and how it processes text by glancing over the groff(1) man page.
Although not necessary, I can really recommend the roff(7) man page for some historical background in the HISTORY section, which is a really refreshing read after wrapping your head around the mdoc syntax and macros. Kudos to the authors of this manual page :)

There are also some example manuals in /usr/share/examples/mdoc which can be used as templates or just to get a condensed overview of how mdoc markup is used in a manpage and how they are structured.

In the following examples I'm going to use the mpt(4) manual page, as this is what I was just working on. Always copy the manual page you'd like to edit to a folder in your home directory - never edit the original files in /usr/share/man/man[1-9] !

For a preview of manual pages (regardless if they are gzip'ed or not), the easiest way is the already mentioned man ./mpt.4.gz, which also automagically uses the pager defined in your .profile.

However, other ways I discovered to preview manual pages and might be useful are:

gzcat mpt.4.gz | groff -mdoc -Tutf8 | less -r
This unzips the manpage, runs it through groff and sends it to less(1).
For old/legacy manpages use the man(7) macros for groff with -man or use -mandoc to let groff decide whether it needs the man or mdoc macros.

mandoc mpt.4 mpt.4.gz | less
mandoc can be used either on the plaintext or gzip'ed file. This is equivalinet to using man ./mpt.4.gz with the PAGER environment variable set to 'less'.

Especially gzcat can be very helpful for on-the-fly modifications of manual pages, e.g. to correct a misspelling with sed:
gzcat mpt.4.gz | sed 's/foo/bar/g' | gzip - > mpt.4.gz
or just to get a manual page directly into the editor:
gzcat mpt.4.gz | vim -


When updating an already existing manual page, a diff(1) file has to be created to submit the changes. By convention, this diff should be a unified diff, which is created with the -u flag:
diff -u mpt.4 mpt.4.new > mpt.4.diff

The mpt.4.diff can now be attached to a PR (Problem Report) in the FreeBSD bugzilla bugtracker by selecting "New" -> "Documentation" after registration, reading through the guidelines and searching if this correction has already been submitted and has an open PR.
PRs which already include a diff for patching should be prefixed with "[patch]" in the summary field.
 

ekingston

Active Member

Thanks: 39
Messages: 144

#16
I only have one question as it relates to created my own man pages.

What WYSIWYG GUI tools can I use that will save in the appropriate format for maintaining/editing my own man pages? (for my needs this can be a tool that runs on X11 (on FreeBSD) or on Windows 10.
 

sko

Well-Known Member

Thanks: 131
Messages: 296

#17
For vim there are syntax files and various helper scripts available, like e.g. automatically updating the date or linking common macros to shortcuts. With one of the various shell integrations you can also get realtime-preview of the file you're editing.

Emacs has an Nroff-mode, but I've never used the emacs OS editor, so I really can't give any comment on that.

However, both scenarios are only for highlighting/previewing the markup file - WYSIWYG editors are very uncommon in the UNIX world, as for almost all use cases these editors don't generate what you want and impose much more work for cleanup and correction to *really* get what you see/want, so it is usually much faster to just writing in markup directly.

The mdoc syntax is _very_ simple and lean. From what I've discovered the last 2 days, with about 15 of the mdoc macros you should have 95% of what you need for manual pages covered. The remaining 5% are looked up as-needed from the mdoc manpage or the markup source of another manual page.
All the boilerplate stuff that is needed for every manpage can be covered with a simple template derived from the ones provided in /usr/share/examples/mdoc/.

Markup really is far from being as "complicated" as HTML (which is still very crude), let alone any "real" programming/scripting language. It was designed for typists/typesetters which didn't have any programming background, so it was designed from the start to be simple and easy to grasp.

TBH, for my modifications to the mpt manpage I didn't even read a full intro or "how to" to markup language - after I glanced over some of the manpages I've mentioned, I just looked at the original file and shamelessly copied the markup from another part of the manpage that fitted my needs :rolleyes:
Only after I practically finished my modifications I started to play around with the markup language a bit more and also started to read the tutorial previously mentioned intro on (which is actually pretty nice).