gendoc.pl revision 115619
1233294Sstas#!/usr/bin/perl -w
2178825Sdfr#-
3178825Sdfr# Copyright (c) 2002-2003 Networks Associates Technology, Inc.
4178825Sdfr# All rights reserved.
5233294Sstas#
6233294Sstas# This software was developed for the FreeBSD Project by ThinkSec AS and
7178825Sdfr# Network Associates Laboratories, the Security Research Division of
8178825Sdfr# Network Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
9178825Sdfr# ("CBOSS"), as part of the DARPA CHATS research program.
10178825Sdfr#
11178825Sdfr# Redistribution and use in source and binary forms, with or without
12178825Sdfr# modification, are permitted provided that the following conditions
13178825Sdfr# are met:
14178825Sdfr# 1. Redistributions of source code must retain the above copyright
15178825Sdfr#    notice, this list of conditions and the following disclaimer.
16178825Sdfr# 2. Redistributions in binary form must reproduce the above copyright
17178825Sdfr#    notice, this list of conditions and the following disclaimer in the
18233294Sstas#    documentation and/or other materials provided with the distribution.
19178825Sdfr# 3. The name of the author may not be used to endorse or promote
20233294Sstas#    products derived from this software without specific prior written
21178825Sdfr#    permission.
22233294Sstas#
23178825Sdfr# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24178825Sdfr# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25178825Sdfr# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26233294Sstas# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27178825Sdfr# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28233294Sstas# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29178825Sdfr# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30178825Sdfr# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31178825Sdfr# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32178825Sdfr# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33178825Sdfr# SUCH DAMAGE.
34178825Sdfr#
35178825Sdfr# $P4: //depot/projects/openpam/misc/gendoc.pl#25 $
36178825Sdfr#
37178825Sdfr
38178825Sdfruse strict;
39178825Sdfruse Fcntl;
40178825Sdfruse Getopt::Std;
41178825Sdfruse POSIX qw(strftime);
42178825Sdfruse vars qw($COPYRIGHT $TODAY %FUNCTIONS %PAMERR);
43178825Sdfr
44178825Sdfr$COPYRIGHT = ".\\\"-
45178825Sdfr.\\\" Copyright (c) 2001-2003 Networks Associates Technology, Inc.
46178825Sdfr.\\\" All rights reserved.
47178825Sdfr.\\\"
48178825Sdfr.\\\" This software was developed for the FreeBSD Project by ThinkSec AS and
49178825Sdfr.\\\" Network Associates Laboratories, the Security Research Division of
50233294Sstas.\\\" Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
51178825Sdfr.\\\" (\"CBOSS\"), as part of the DARPA CHATS research program.
52178825Sdfr.\\\"
53178825Sdfr.\\\" Redistribution and use in source and binary forms, with or without
54178825Sdfr.\\\" modification, are permitted provided that the following conditions
55178825Sdfr.\\\" are met:
56178825Sdfr.\\\" 1. Redistributions of source code must retain the above copyright
57178825Sdfr.\\\"    notice, this list of conditions and the following disclaimer.
58178825Sdfr.\\\" 2. Redistributions in binary form must reproduce the above copyright
59178825Sdfr.\\\"    notice, this list of conditions and the following disclaimer in the
60178825Sdfr.\\\"    documentation and/or other materials provided with the distribution.
61178825Sdfr.\\\" 3. The name of the author may not be used to endorse or promote
62178825Sdfr.\\\"    products derived from this software without specific prior written
63178825Sdfr.\\\"    permission.
64178825Sdfr.\\\"
65233294Sstas.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
66178825Sdfr.\\\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
67178825Sdfr.\\\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
68178825Sdfr.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
69178825Sdfr.\\\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
70178825Sdfr.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
71178825Sdfr.\\\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
72178825Sdfr.\\\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
73178825Sdfr.\\\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
74178825Sdfr.\\\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
75178825Sdfr.\\\" SUCH DAMAGE.
76178825Sdfr.\\\"
77178825Sdfr.\\\" \$" . "P4" . "\$
78178825Sdfr.\\\"";
79233294Sstas
80233294Sstas%PAMERR = (
81233294Sstas    PAM_SUCCESS			=> "Success",
82233294Sstas    PAM_OPEN_ERR		=> "Failed to load module",
83233294Sstas    PAM_SYMBOL_ERR		=> "Invalid symbol",
84233294Sstas    PAM_SERVICE_ERR		=> "Error in service module",
85178825Sdfr    PAM_SYSTEM_ERR		=> "System error",
86178825Sdfr    PAM_BUF_ERR			=> "Memory buffer error",
87178825Sdfr    PAM_CONV_ERR		=> "Conversation failure",
88178825Sdfr    PAM_PERM_DENIED		=> "Permission denied",
89178825Sdfr    PAM_MAXTRIES		=> "Maximum number of tries exceeded",
90178825Sdfr    PAM_AUTH_ERR		=> "Authentication error",
91178825Sdfr    PAM_NEW_AUTHTOK_REQD	=> "New authentication token required",
92233294Sstas    PAM_CRED_INSUFFICIENT	=> "Insufficient credentials",
93178825Sdfr    PAM_AUTHINFO_UNAVAIL	=> "Authentication information is unavailable",
94178825Sdfr    PAM_USER_UNKNOWN		=> "Unknown user",
95178825Sdfr    PAM_CRED_UNAVAIL		=> "Failed to retrieve user credentials",
96178825Sdfr    PAM_CRED_EXPIRED		=> "User credentials have expired",
97178825Sdfr    PAM_CRED_ERR		=> "Failed to set user credentials",
98233294Sstas    PAM_ACCT_EXPIRED		=> "User accound has expired",
99178825Sdfr    PAM_AUTHTOK_EXPIRED		=> "Password has expired",
100178825Sdfr    PAM_SESSION_ERR		=> "Session failure",
101178825Sdfr    PAM_AUTHTOK_ERR		=> "Authentication token failure",
102178825Sdfr    PAM_AUTHTOK_RECOVERY_ERR	=> "Failed to recover old authentication token",
103233294Sstas    PAM_AUTHTOK_LOCK_BUSY	=> "Authentication token lock busy",
104233294Sstas    PAM_AUTHTOK_DISABLE_AGING	=> "Authentication token aging disabled",
105178825Sdfr    PAM_NO_MODULE_DATA		=> "Module data not found",
106178825Sdfr    PAM_IGNORE			=> "Ignore this module",
107178825Sdfr    PAM_ABORT			=> "General failure",
108178825Sdfr    PAM_TRY_AGAIN		=> "Try again",
109233294Sstas    PAM_MODULE_UNKNOWN		=> "Unknown module type",
110233294Sstas    PAM_DOMAIN_UNKNOWN		=> "Unknown authentication domain",
111233294Sstas);
112233294Sstas
113178825Sdfrsub parse_source($) {
114233294Sstas    my $fn = shift;
115233294Sstas
116233294Sstas    local *FILE;
117178825Sdfr    my $source;
118178825Sdfr    my $func;
119178825Sdfr    my $descr;
120178825Sdfr    my $type;
121178825Sdfr    my $args;
122178825Sdfr    my $argnames;
123178825Sdfr    my $man;
124178825Sdfr    my $inlist;
125178825Sdfr    my $inliteral;
126178825Sdfr    my %xref;
127178825Sdfr    my @errors;
128233294Sstas
129233294Sstas    if ($fn !~ m,\.c$,) {
130233294Sstas	warn("$fn: not C source, ignoring\n");
131233294Sstas	return undef;
132233294Sstas    }
133233294Sstas
134233294Sstas    sysopen(FILE, $fn, O_RDONLY)
135233294Sstas	or die("$fn: open(): $!\n");
136233294Sstas    $source = join('', <FILE>);
137233294Sstas    close(FILE);
138233294Sstas
139233294Sstas    return undef
140233294Sstas	if ($source =~ m/^ \* NOPARSE\s*$/m);
141233294Sstas
142233294Sstas    $func = $fn;
143233294Sstas    $func =~ s,^(?:.*/)?([^/]+)\.c$,$1,;
144233294Sstas    if ($source !~ m,\n \* ([\S ]+)\n \*/\n\n([\S ]+)\n$func\((.*?)\)\n\{,s) {
145233294Sstas	warn("$fn: can't find $func\n");
146233294Sstas	return undef;
147233294Sstas    }
148233294Sstas    ($descr, $type, $args) = ($1, $2, $3);
149178825Sdfr    $descr =~ s,^([A-Z][a-z]),lc($1),e;
150178825Sdfr    $descr =~ s,[\.\s]*$,,;
151178825Sdfr    while ($args =~ s/^((?:[^\(]|\([^\)]*\))*),\s*/$1\" \"/g) {
152178825Sdfr	# nothing
153178825Sdfr    }
154178825Sdfr    $args =~ s/,\s+/, /gs;
155178825Sdfr    $args = "\"$args\"";
156178825Sdfr
157178825Sdfr    %xref = (
158233294Sstas	"pam 3" => 1
159233294Sstas    );
160178825Sdfr
161178825Sdfr    if ($type eq "int") {
162178825Sdfr	foreach (split("\n", $source)) {
163178825Sdfr	    next unless (m/^ \*\s+(!?PAM_[A-Z_]+|=[a-z_]+)\s*$/);
164178825Sdfr	    push(@errors, $1);
165233294Sstas	}
166233294Sstas	$xref{"pam_strerror 3"} = 1;
167178825Sdfr    }
168178825Sdfr
169178825Sdfr    $argnames = $args;
170233294Sstas    $argnames =~ s/\"[^\"]+\*?\b(\w+)\"/\"$1\"/g;
171178825Sdfr    $argnames =~ s/([\|\[\]\(\)\.\*\+\?])/\\$1/g;
172178825Sdfr    $argnames =~ s/\" \"/|/g;
173178825Sdfr    $argnames =~ s/^\"(.*)\"$/($1)/;
174178825Sdfr    $inliteral = $inlist = 0;
175178825Sdfr    foreach (split("\n", $source)) {
176233294Sstas	s/\s*$//;
177178825Sdfr	if (!defined($man)) {
178178825Sdfr	    if (m/^\/\*\*$/) {
179233294Sstas		$man = "";
180178825Sdfr	    }
181178825Sdfr	    next;
182178825Sdfr	}
183178825Sdfr	last if (m/^ \*\/$/);
184233294Sstas	s/^ \* ?//;
185233294Sstas	s/\\(.)/$1/gs;
186233294Sstas	if (m/^$/) {
187178825Sdfr	    if ($man ne "" && $man !~ m/\.Pp\n$/s) {
188178825Sdfr		if ($inliteral) {
189178825Sdfr		    $man .= "\0\n";
190178825Sdfr		} elsif ($inlist) {
191178825Sdfr		    $man .= ".El\n.Pp\n";
192233294Sstas		    $inlist = 0;
193178825Sdfr		} else {
194178825Sdfr		    $man .= ".Pp\n";
195178825Sdfr		}
196178825Sdfr	    }
197178825Sdfr	    next;
198178825Sdfr	}
199233294Sstas	if (m/^>(\w+)(?:\s+(\d))?$/) {
200233294Sstas	    ++$xref{$2 ? "$1 $2" : "$1 3"};
201178825Sdfr	    next;
202178825Sdfr	}
203233294Sstas	if (s/^\s+(=?\w+):\s*/.It $1/) {
204178825Sdfr	    if ($inliteral) {
205178825Sdfr		$man .= ".Ed\n";
206178825Sdfr		$inliteral = 0;
207178825Sdfr	    }
208178825Sdfr	    if (!$inlist) {
209233294Sstas		$man =~ s/\.Pp\n$//s;
210178825Sdfr		$man .= ".Bl -tag -width 18n\n";
211178825Sdfr		$inlist = 1;
212178825Sdfr	    }
213178825Sdfr	    s/^\.It =([A-Z][A-Z_]+)$/.It Dv $1/gs;
214178825Sdfr	    $man .= "$_\n";
215178825Sdfr	    next;
216178825Sdfr	} elsif ($inlist && m/^\S/) {
217178825Sdfr	    $man .= ".El\n.Pp\n";
218178825Sdfr	    $inlist = 0;
219178825Sdfr	} elsif ($inliteral && m/^\S/) {
220178825Sdfr	    $man .= ".Ed\n";
221178825Sdfr	    $inliteral = 0;
222178825Sdfr	} elsif ($inliteral) {
223178825Sdfr	    $man .= "$_\n";
224178825Sdfr	    next;
225178825Sdfr	} elsif ($inlist) {
226178825Sdfr	    s/^\s+//;
227178825Sdfr	} elsif (m/^\s+/) {
228178825Sdfr	    $man .= ".Bd -literal\n";
229178825Sdfr	    $inliteral = 1;
230178825Sdfr	    $man .= "$_\n";
231178825Sdfr	    next;
232178825Sdfr	}
233233294Sstas	s/\s*=$func\b\s*/\n.Nm\n/gs;
234178825Sdfr	s/\s*=$argnames\b\s*/\n.Va $1\n/gs;
235178825Sdfr	s/\s*=(struct \w+(?: \*)?)\b\s*/\n.Vt $1\n/gs;
236233294Sstas	s/\s*:([a-z_]+)\b\s*/\n.Va $1\n/gs;
237178825Sdfr	s/\s*;([a-z_]+)\b\s*/\n.Dv $1\n/gs;
238178825Sdfr	while (s/\s*=([a-z_]+)\b\s*/\n.Xr $1 3\n/s) {
239178825Sdfr	    ++$xref{"$1 3"};
240178825Sdfr	}
241178825Sdfr	s/\s*\"(?=\w)/\n.Do\n/gs;
242178825Sdfr	s/\"(?!\w)\s*/\n.Dc\n/gs;
243178825Sdfr	s/\s*=([A-Z][A-Z_]+)\b\s*(?![\.,:;])/\n.Dv $1\n/gs;
244178825Sdfr	s/\s*=([A-Z][A-Z_]+)\b([\.,:;]+)\s*/\n.Dv $1 $2\n/gs;
245178825Sdfr	s/\s*{([A-Z][a-z] .*?)}\s*/\n.$1\n/gs;
246178825Sdfr	$man .= "$_\n";
247178825Sdfr    }
248178825Sdfr    if (defined($man)) {
249178825Sdfr	if ($inlist) {
250178825Sdfr	    $man .= ".El\n";
251178825Sdfr	}
252178825Sdfr	if ($inliteral) {
253178825Sdfr	    $man .= ".Ed\n";
254233294Sstas	}
255233294Sstas	$man =~ s/(\n\.[A-Z][a-z] [\w ]+)\n([\.,:;-]\S*)\s*/$1 $2\n/gs;
256178825Sdfr	$man =~ s/\s*$/\n/gm;
257178825Sdfr	$man =~ s/\n+/\n/gs;
258178825Sdfr	$man =~ s/\0//gs;
259178825Sdfr	$man =~ s/\n\n\./\n\./gs;
260178825Sdfr	chomp($man);
261178825Sdfr    } else {
262178825Sdfr	$man = "No description available.";
263178825Sdfr    }
264178825Sdfr
265178825Sdfr    $FUNCTIONS{$func} = {
266178825Sdfr	'source'	=> $fn,
267178825Sdfr	'name'		=> $func,
268178825Sdfr	'descr'		=> $descr,
269178825Sdfr	'type'		=> $type,
270178825Sdfr	'args'		=> $args,
271233294Sstas	'man'		=> $man,
272178825Sdfr	'xref'		=> \%xref,
273178825Sdfr	'errors'	=> \@errors,
274233294Sstas    };
275178825Sdfr    if ($source =~ m/^ \* NODOC\s*$/m) {
276178825Sdfr	$FUNCTIONS{$func}->{'nodoc'} = 1;
277178825Sdfr    }
278178825Sdfr    if ($source !~ m/^ \* XSSO \d/m) {
279233294Sstas	$FUNCTIONS{$func}->{'openpam'} = 1;
280178825Sdfr    }
281233294Sstas    expand_errors($FUNCTIONS{$func});
282233294Sstas    return $FUNCTIONS{$func};
283233294Sstas}
284178825Sdfr
285233294Sstassub expand_errors($);
286178825Sdfrsub expand_errors($) {
287233294Sstas    my $func = shift;		# Ref to function hash
288233294Sstas
289178825Sdfr    my %errors;
290178825Sdfr    my $ref;
291178825Sdfr    my $fn;
292178825Sdfr
293178825Sdfr    if (defined($func->{'recursed'})) {
294233294Sstas	warn("$func->{'name'}(): loop in error spec\n");
295178825Sdfr	return qw();
296178825Sdfr    }
297233294Sstas    $func->{'recursed'} = 1;
298233294Sstas
299233294Sstas    foreach (@{$func->{'errors'}}) {
300233294Sstas	if (m/^(PAM_[A-Z_]+)$/) {
301178825Sdfr	    if (!defined($PAMERR{$1})) {
302233294Sstas		warn("$func->{'name'}(): unrecognized error: $1\n");
303178825Sdfr		next;
304178825Sdfr	    }
305233294Sstas	    $errors{$1} = 1;
306233294Sstas	} elsif (m/^!(PAM_[A-Z_]+)$/) {
307178825Sdfr	    # treat negations separately
308178825Sdfr	} elsif (m/^=([a-z_]+)$/) {
309178825Sdfr	    $ref = $1;
310178825Sdfr	    if (!defined($FUNCTIONS{$ref})) {
311178825Sdfr		$fn = $func->{'source'};
312178825Sdfr		$fn =~ s/$func->{'name'}/$ref/;
313178825Sdfr		parse_source($fn);
314178825Sdfr	    }
315178825Sdfr	    if (!defined($FUNCTIONS{$ref})) {
316178825Sdfr		warn("$func->{'name'}(): reference to unknown $ref()\n");
317178825Sdfr		next;
318178825Sdfr	    }
319178825Sdfr	    foreach (@{$FUNCTIONS{$ref}->{'errors'}}) {
320178825Sdfr		$errors{$_} = 1;
321178825Sdfr	    }
322178825Sdfr	} else {
323178825Sdfr	    warn("$func->{'name'}(): invalid error specification: $_\n");
324233294Sstas	}
325178825Sdfr    }
326233294Sstas    foreach (@{$func->{'errors'}}) {
327233294Sstas	if (m/^!(PAM_[A-Z_]+)$/) {
328178825Sdfr	    delete($errors{$1});
329233294Sstas	}
330178825Sdfr    }
331178825Sdfr    delete($func->{'recursed'});
332178825Sdfr    $func->{'errors'} = [ sort(keys(%errors)) ];
333178825Sdfr}
334178825Sdfr
335178825Sdfrsub gendoc($) {
336178825Sdfr    my $func = shift;		# Ref to function hash
337178825Sdfr
338178825Sdfr    local *FILE;
339178825Sdfr    my $mdoc;
340178825Sdfr    my $fn;
341178825Sdfr
342178825Sdfr    return if defined($func->{'nodoc'});
343178825Sdfr
344178825Sdfr    $mdoc = "$COPYRIGHT
345178825Sdfr.Dd $TODAY
346178825Sdfr.Dt " . uc($func->{'name'}) . " 3
347178825Sdfr.Os
348178825Sdfr.Sh NAME
349178825Sdfr.Nm $func->{'name'}
350178825Sdfr.Nd $func->{'descr'}
351178825Sdfr.Sh LIBRARY
352178825Sdfr.Lb libpam
353178825Sdfr.Sh SYNOPSIS
354178825Sdfr.In sys/types.h
355178825Sdfr.In security/pam_appl.h
356178825Sdfr";
357178825Sdfr    if ($func->{'name'} =~ m/_sm_/) {
358178825Sdfr	$mdoc .= ".In security/pam_modules.h\n"
359178825Sdfr    }
360178825Sdfr    if ($func->{'name'} =~ m/openpam/) {
361178825Sdfr	$mdoc .= ".In security/openpam.h\n"
362178825Sdfr    }
363178825Sdfr    $mdoc .= ".Ft $func->{'type'}
364178825Sdfr.Fn $func->{'name'} $func->{'args'}
365178825Sdfr.Sh DESCRIPTION
366178825Sdfr$func->{'man'}
367178825Sdfr";
368178825Sdfr    if ($func->{'type'} eq "int") {
369178825Sdfr	$mdoc .= ".Sh RETURN VALUES
370233294SstasThe
371178825Sdfr.Nm
372178825Sdfrfunction returns one of the following values:
373233294Sstas.Bl -tag -width 18n
374178825Sdfr";
375178825Sdfr	my @errors = @{$func->{'errors'}};
376233294Sstas	warn("$func->{'name'}(): no error specification\n")
377233294Sstas	    unless(@errors);
378233294Sstas	foreach (@errors) {
379233294Sstas	    $mdoc .= ".It Bq Er $_\n$PAMERR{$_}.\n";
380178825Sdfr	}
381178825Sdfr	$mdoc .= ".El\n";
382178825Sdfr    } else {
383178825Sdfr	if ($func->{'type'} =~ m/\*$/) {
384233294Sstas	    $mdoc .= ".Sh RETURN VALUES
385178825SdfrThe
386178825Sdfr.Nm
387178825Sdfrfunction returns
388178825Sdfr.Dv NULL
389178825Sdfron failure.
390178825Sdfr";
391233294Sstas	}
392178825Sdfr    }
393178825Sdfr    $mdoc .= ".Sh SEE ALSO\n";
394178825Sdfr    my @xref = sort(keys(%{$func->{'xref'}}));
395178825Sdfr    while (@xref) {
396178825Sdfr	$mdoc .= ".Xr " . shift(@xref) . (@xref ? " ,\n" : "\n");
397178825Sdfr    }
398233294Sstas    $mdoc .= ".Sh STANDARDS\n";
399178825Sdfr    if ($func->{'openpam'}) {
400178825Sdfr	$mdoc .= "The
401178825Sdfr.Nm
402178825Sdfrfunction is an OpenPAM extension.
403178825Sdfr";
404178825Sdfr    } else {
405178825Sdfr	$mdoc .= ".Rs
406178825Sdfr.%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
407178825Sdfr.%D \"June 1997\"
408178825Sdfr.Re
409178825Sdfr";
410178825Sdfr    }
411233294Sstas    $mdoc .= ".Sh AUTHORS
412178825SdfrThe
413178825Sdfr.Nm
414178825Sdfrfunction and this manual page were developed for the FreeBSD Project
415233294Sstasby ThinkSec AS and Network Associates Laboratories, the Security
416178825SdfrResearch Division of Network Associates, Inc.  under DARPA/SPAWAR
417178825Sdfrcontract N66001-01-C-8035
418178825Sdfr.Pq Dq CBOSS ,
419178825Sdfras part of the DARPA CHATS research program.
420178825Sdfr";
421178825Sdfr
422178825Sdfr    $fn = "$func->{'name'}.3";
423178825Sdfr    if (sysopen(FILE, $fn, O_RDWR|O_CREAT|O_TRUNC)) {
424233294Sstas	print(FILE $mdoc);
425233294Sstas	close(FILE);
426178825Sdfr    } else {
427178825Sdfr	warn("$fn: open(): $!\n");
428178825Sdfr    }
429178825Sdfr}
430233294Sstas
431178825Sdfrsub readproto($) {
432178825Sdfr    my $fn = shift;		# File name
433178825Sdfr
434233294Sstas    local *FILE;
435178825Sdfr    my %func;
436178825Sdfr
437178825Sdfr    sysopen(FILE, $fn, O_RDONLY)
438178825Sdfr	or die("$fn: open(): $!\n");
439233294Sstas    while (<FILE>) {
440233294Sstas	if (m/^\.Nm ((?:open)?pam_.*?)\s*$/) {
441178825Sdfr	    $func{'Nm'} = $func{'Nm'} || $1;
442178825Sdfr	} elsif (m/^\.Ft (\S.*?)\s*$/) {
443178825Sdfr	    $func{'Ft'} = $func{'Ft'} || $1;
444233294Sstas	} elsif (m/^\.Fn (\S.*?)\s*$/) {
445233294Sstas	    $func{'Fn'} = $func{'Fn'} || $1;
446233294Sstas	}
447178825Sdfr    }
448178825Sdfr    close(FILE);
449178825Sdfr    if ($func{'Nm'}) {
450178825Sdfr	$FUNCTIONS{$func{'Nm'}} = \%func;
451178825Sdfr    } else {
452178825Sdfr	warn("No function found\n");
453178825Sdfr    }
454178825Sdfr}
455178825Sdfr
456178825Sdfrsub gensummary($) {
457178825Sdfr    my $page = shift;		# Which page to produce
458178825Sdfr
459178825Sdfr    local *FILE;
460178825Sdfr    my $upage;
461178825Sdfr    my $func;
462178825Sdfr    my %xref;
463178825Sdfr
464233294Sstas    sysopen(FILE, "$page.3", O_RDWR|O_CREAT|O_TRUNC)
465178825Sdfr	or die("$page.3: $!\n");
466178825Sdfr
467178825Sdfr    $upage = uc($page);
468233294Sstas    print FILE "$COPYRIGHT
469233294Sstas.Dd $TODAY
470233294Sstas.Dt $upage 3
471233294Sstas.Os
472233294Sstas.Sh NAME
473233294Sstas";
474233294Sstas    my @funcs = sort(keys(%FUNCTIONS));
475233294Sstas    while ($func = shift(@funcs)) {
476233294Sstas	print FILE ".Nm $FUNCTIONS{$func}->{'Nm'}";
477233294Sstas	print FILE " ,"
478233294Sstas		if (@funcs);
479233294Sstas	print FILE "\n";
480233294Sstas    }
481233294Sstas    print FILE ".Nd Pluggable Authentication Modules Library
482233294Sstas.Sh LIBRARY
483233294Sstas.Lb libpam
484233294Sstas.Sh SYNOPSIS\n";
485233294Sstas    if ($page eq 'pam') {
486233294Sstas	print FILE ".In security/pam_appl.h\n";
487233294Sstas    } else {
488233294Sstas	print FILE ".In security/openpam.h\n";
489178825Sdfr    }
490178825Sdfr    foreach $func (sort(keys(%FUNCTIONS))) {
491178825Sdfr	print FILE ".Ft $FUNCTIONS{$func}->{'Ft'}\n";
492233294Sstas	print FILE ".Fn $FUNCTIONS{$func}->{'Fn'}\n";
493233294Sstas    }
494233294Sstas    while (<STDIN>) {
495233294Sstas	if (m/^\.Xr (\S+)\s*(\d)\s*$/) {
496233294Sstas	    $xref{$1} = $2;
497233294Sstas	}
498233294Sstas	print FILE $_;
499178825Sdfr    }
500178825Sdfr
501233294Sstas    if ($page eq 'pam') {
502233294Sstas	print FILE ".Sh RETURN VALUES
503233294SstasThe following return codes are defined by
504233294Sstas.Aq Pa security/pam_constants.h :
505233294Sstas.Bl -tag -width 18n
506233294Sstas";
507233294Sstas	foreach (sort(keys(%PAMERR))) {
508178825Sdfr	    print FILE ".It Bq Er $_\n$PAMERR{$_}.\n";
509178825Sdfr	}
510178825Sdfr	print FILE ".El\n";
511178825Sdfr    }
512178825Sdfr    print FILE ".Sh SEE ALSO
513178825Sdfr";
514178825Sdfr    print FILE ".Xr openpam 3\n"
515178825Sdfr	if ($page eq 'pam');
516178825Sdfr    foreach $func (keys(%FUNCTIONS)) {
517178825Sdfr	$xref{$func} = 3;
518233294Sstas    }
519233294Sstas    my @refs = sort(keys(%xref));
520233294Sstas    while ($_ = shift(@refs)) {
521233294Sstas	print FILE ".Xr $_ $xref{$_}";
522233294Sstas	print FILE " ,"
523233294Sstas	    if (@refs);
524233294Sstas	print FILE "\n";
525233294Sstas    }
526233294Sstas    print FILE ".Sh STANDARDS
527233294Sstas.Rs
528233294Sstas.%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
529233294Sstas.%D \"June 1997\"
530233294Sstas.Re
531233294Sstas.Sh AUTHORS
532178825SdfrThe OpenPAM library and this manual page were developed for the
533233294SstasFreeBSD Project by ThinkSec AS and Network Associates Laboratories,
534233294Sstasthe Security Research Division of Network Associates, Inc.  under
535233294SstasDARPA/SPAWAR contract N66001-01-C-8035
536233294Sstas.Pq Dq CBOSS ,
537233294Sstasas part of the DARPA CHATS research program.
538178825Sdfr";
539178825Sdfr    close(FILE);
540233294Sstas}
541233294Sstas
542233294Sstassub usage() {
543233294Sstas
544233294Sstas    print(STDERR "usage: gendoc [-s] source [...]\n");
545178825Sdfr    exit(1);
546178825Sdfr}
547233294Sstas
548233294SstasMAIN:{
549233294Sstas    my %opts;
550233294Sstas
551233294Sstas    usage()
552178825Sdfr	unless (@ARGV && getopts("op", \%opts));
553178825Sdfr    $TODAY = strftime("%B %e, %Y", localtime(time()));
554178825Sdfr    $TODAY =~ s,\s+, ,g;
555178825Sdfr    if ($opts{'o'} || $opts{'p'}) {
556178825Sdfr	foreach my $fn (@ARGV) {
557178825Sdfr	    readproto($fn);
558233294Sstas	}
559178825Sdfr	gensummary('openpam')
560178825Sdfr	    if ($opts{'o'});
561233294Sstas	gensummary('pam')
562233294Sstas	    if ($opts{'p'});
563233294Sstas    } else {
564233294Sstas	foreach my $fn (@ARGV) {
565233294Sstas	    my $func = parse_source($fn);
566233294Sstas	    gendoc($func)
567233294Sstas		if (defined($func));
568233294Sstas	}
569233294Sstas    }
570233294Sstas    exit(0);
571233294Sstas}
572233294Sstas