source: openpam/trunk/misc/gendoc.pl @ 545

Last change on this file since 545 was 545, checked in by des, 2 years ago

More cases in which Fn should be used instead of Nm.

  • Property svn:keywords set to Id
File size: 17.7 KB
Line 
1#!/usr/bin/perl -w
2#-
3# Copyright (c) 2002-2003 Networks Associates Technology, Inc.
4# Copyright (c) 2004-2011 Dag-Erling Smørgrav
5# All rights reserved.
6#
7# This software was developed for the FreeBSD Project by ThinkSec AS and
8# Network Associates Laboratories, the Security Research Division of
9# Network Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
10# ("CBOSS"), as part of the DARPA CHATS research program.
11#
12# Redistribution and use in source and binary forms, with or without
13# modification, are permitted provided that the following conditions
14# are met:
15# 1. Redistributions of source code must retain the above copyright
16#    notice, this list of conditions and the following disclaimer.
17# 2. Redistributions in binary form must reproduce the above copyright
18#    notice, this list of conditions and the following disclaimer in the
19#    documentation and/or other materials provided with the distribution.
20# 3. The name of the author may not be used to endorse or promote
21#    products derived from this software without specific prior written
22#    permission.
23#
24# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34# SUCH DAMAGE.
35#
36# $Id$
37#
38
39use strict;
40use locale;
41use Fcntl;
42use Getopt::Std;
43use POSIX qw(locale_h strftime);
44use vars qw($COPYRIGHT %AUTHORS $TODAY %FUNCTIONS %PAMERR);
45
46$COPYRIGHT = ".\\\"-
47.\\\" Copyright (c) 2001-2003 Networks Associates Technology, Inc.
48.\\\" Copyright (c) 2004-2011 Dag-Erling Smørgrav
49.\\\" All rights reserved.
50.\\\"
51.\\\" This software was developed for the FreeBSD Project by ThinkSec AS and
52.\\\" Network Associates Laboratories, the Security Research Division of
53.\\\" Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
54.\\\" (\"CBOSS\"), as part of the DARPA CHATS research program.
55.\\\"
56.\\\" Redistribution and use in source and binary forms, with or without
57.\\\" modification, are permitted provided that the following conditions
58.\\\" are met:
59.\\\" 1. Redistributions of source code must retain the above copyright
60.\\\"    notice, this list of conditions and the following disclaimer.
61.\\\" 2. Redistributions in binary form must reproduce the above copyright
62.\\\"    notice, this list of conditions and the following disclaimer in the
63.\\\"    documentation and/or other materials provided with the distribution.
64.\\\" 3. The name of the author may not be used to endorse or promote
65.\\\"    products derived from this software without specific prior written
66.\\\"    permission.
67.\\\"
68.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
69.\\\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
70.\\\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
71.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
72.\\\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
73.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
74.\\\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
75.\\\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
76.\\\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
77.\\\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
78.\\\" SUCH DAMAGE.
79.\\\"
80.\\\" \$" . "Id" . "\$
81.\\\"";
82
83%AUTHORS = (
84    THINKSEC => "ThinkSec AS and Network Associates Laboratories, the
85Security Research Division of Network Associates, Inc.\\& under
86DARPA/SPAWAR contract N66001-01-C-8035
87.Pq Dq CBOSS ,
88as part of the DARPA CHATS research program.",
89    DES => ".An Dag-Erling Sm\\(/orgrav Aq des\@FreeBSD.org .",
90);
91
92%PAMERR = (
93    PAM_SUCCESS                 => "Success",
94    PAM_OPEN_ERR                => "Failed to load module",
95    PAM_SYMBOL_ERR              => "Invalid symbol",
96    PAM_SERVICE_ERR             => "Error in service module",
97    PAM_SYSTEM_ERR              => "System error",
98    PAM_BUF_ERR                 => "Memory buffer error",
99    PAM_CONV_ERR                => "Conversation failure",
100    PAM_PERM_DENIED             => "Permission denied",
101    PAM_MAXTRIES                => "Maximum number of tries exceeded",
102    PAM_AUTH_ERR                => "Authentication error",
103    PAM_NEW_AUTHTOK_REQD        => "New authentication token required",
104    PAM_CRED_INSUFFICIENT       => "Insufficient credentials",
105    PAM_AUTHINFO_UNAVAIL        => "Authentication information is unavailable",
106    PAM_USER_UNKNOWN            => "Unknown user",
107    PAM_CRED_UNAVAIL            => "Failed to retrieve user credentials",
108    PAM_CRED_EXPIRED            => "User credentials have expired",
109    PAM_CRED_ERR                => "Failed to set user credentials",
110    PAM_ACCT_EXPIRED            => "User account has expired",
111    PAM_AUTHTOK_EXPIRED         => "Password has expired",
112    PAM_SESSION_ERR             => "Session failure",
113    PAM_AUTHTOK_ERR             => "Authentication token failure",
114    PAM_AUTHTOK_RECOVERY_ERR    => "Failed to recover old authentication token",
115    PAM_AUTHTOK_LOCK_BUSY       => "Authentication token lock busy",
116    PAM_AUTHTOK_DISABLE_AGING   => "Authentication token aging disabled",
117    PAM_NO_MODULE_DATA          => "Module data not found",
118    PAM_IGNORE                  => "Ignore this module",
119    PAM_ABORT                   => "General failure",
120    PAM_TRY_AGAIN               => "Try again",
121    PAM_MODULE_UNKNOWN          => "Unknown module type",
122    PAM_DOMAIN_UNKNOWN          => "Unknown authentication domain",
123);
124
125sub parse_source($) {
126    my $fn = shift;
127
128    local *FILE;
129    my $source;
130    my $func;
131    my $descr;
132    my $type;
133    my $args;
134    my $argnames;
135    my $man;
136    my $inlist;
137    my $intaglist;
138    my $inliteral;
139    my $customrv;
140    my %xref;
141    my @errors;
142    my $author;
143
144    if ($fn !~ m,\.c$,) {
145        warn("$fn: not C source, ignoring\n");
146        return undef;
147    }
148
149    open(FILE, "<", "$fn")
150        or die("$fn: open(): $!\n");
151    $source = join('', <FILE>);
152    close(FILE);
153
154    return undef
155        if ($source =~ m/^ \* NOPARSE\s*$/m);
156
157    $author = 'THINKSEC';
158    if ($source =~ s/^ \* AUTHOR\s+(.*?)\s*$//m) {
159        $author = $1;
160    }
161
162    $func = $fn;
163    $func =~ s,^(?:.*/)?([^/]+)\.c$,$1,;
164    if ($source !~ m,\n \* ([\S ]+)\n \*/\n\n([\S ]+)\n$func\((.*?)\)\n\{,s) {
165        warn("$fn: can't find $func\n");
166        return undef;
167    }
168    ($descr, $type, $args) = ($1, $2, $3);
169    $descr =~ s,^([A-Z][a-z]),lc($1),e;
170    $descr =~ s,[\.\s]*$,,;
171    while ($args =~ s/^((?:[^\(]|\([^\)]*\))*),\s*/$1\" \"/g) {
172        # nothing
173    }
174    $args =~ s/,\s+/, /gs;
175    $args = "\"$args\"";
176
177    %xref = (
178        3 => { 'pam' => 1 },
179    );
180
181    if ($type eq "int") {
182        foreach (split("\n", $source)) {
183            next unless (m/^ \*\s+(!?PAM_[A-Z_]+|=[a-z_]+)\s*$/);
184            push(@errors, $1);
185        }
186        ++$xref{3}->{'pam_strerror'};
187    }
188
189    $argnames = $args;
190    # extract names of regular arguments
191    $argnames =~ s/\"[^\"]+\*?\b(\w+)\"/\"$1\"/g;
192    # extract names of function pointer arguments
193    $argnames =~ s/\"([\w\s\*]+)\(\*?(\w+)\)\([^\)]+\)\"/\"$2\"/g;
194    # escape metacharacters (there shouldn't be any, but...)
195    $argnames =~ s/([\|\[\]\(\)\.\*\+\?])/\\$1/g;
196    # separate argument names with |
197    $argnames =~ s/\" \"/|/g;
198    # and surround with ()
199    $argnames =~ s/^\"(.*)\"$/$1/;
200    # $argnames is now a regexp that matches argument names
201    $inliteral = $inlist = $intaglist = 0;
202    foreach (split("\n", $source)) {
203        s/\s*$//;
204        if (!defined($man)) {
205            if (m/^\/\*\*$/) {
206                $man = "";
207            }
208            next;
209        }
210        last if (m/^ \*\/$/);
211        s/^ \* ?//;
212        s/\\(.)/$1/gs;
213        if (m/^$/) {
214            # paragraph separator
215            if ($inlist || $intaglist) {
216                # either a blank line between list items, or a blank
217                # line after the final list item.  The latter case
218                # will be handled further down.
219                next;
220            }
221            if ($man =~ m/\n\.Sh [^\n]+\n$/s) {
222                # a blank line after a section header
223                next;
224            }
225            if ($man ne "" && $man !~ m/\.Pp\n$/s) {
226                if ($inliteral) {
227                    $man .= "\0\n";
228                } else {
229                    $man .= ".Pp\n";
230                }
231            }
232            next;
233        }
234        if (m/^>(\w+)(\s+\d)?$/) {
235            # "see also" cross-reference
236            my ($page, $sect) = ($1, $2 ? int($2) : 3);
237            ++$xref{$sect}->{$page};
238            next;
239        }
240        if (s/^([A-Z][0-9A-Z -]+)$/.Sh $1/) {
241            if ($1 eq "RETURN VALUES") {
242                $customrv = $1;
243            }
244            $man =~ s/\n\.Pp$/\n/s;
245            $man .= "$_\n";
246            next;
247        }
248        if (s/^\s+-\s+//) {
249            # item in bullet list
250            if ($inliteral) {
251                $man .= ".Ed\n";
252                $inliteral = 0;
253            }
254            if ($intaglist) {
255                $man .= ".El\n.Pp\n";
256                $intaglist = 0;
257            }
258            if (!$inlist) {
259                $man =~ s/\.Pp\n$//s;
260                $man .= ".Bl -bullet\n";
261                $inlist = 1;
262            }
263            $man .= ".It\n";
264            # fall through
265        } elsif (s/^\s+(\S+):\s*/.It $1/) {
266            # item in tag list
267            if ($inliteral) {
268                $man .= ".Ed\n";
269                $inliteral = 0;
270            }
271            if ($inlist) {
272                $man .= ".El\n.Pp\n";
273                $inlist = 0;
274            }
275            if (!$intaglist) {
276                $man =~ s/\.Pp\n$//s;
277                $man .= ".Bl -tag -width 18n\n";
278                $intaglist = 1;
279            }
280            s/^\.It =([A-Z][A-Z_]+)$/.It Dv $1/gs;
281            $man .= "$_\n";
282            next;
283        } elsif (($inlist || $intaglist) && m/^\S/) {
284            # regular text after list
285            $man .= ".El\n.Pp\n";
286            $inlist = $intaglist = 0;
287        } elsif ($inliteral && m/^\S/) {
288            # regular text after literal section
289            $man .= ".Ed\n";
290            $inliteral = 0;
291        } elsif ($inliteral) {
292            # additional text within literal section
293            $man .= "$_\n";
294            next;
295        } elsif ($inlist || $intaglist) {
296            # additional text within list
297            s/^\s+//;
298        } elsif (m/^\s+/) {
299            # new literal section
300            $man .= ".Bd -literal\n";
301            $inliteral = 1;
302            $man .= "$_\n";
303            next;
304        }
305        s/\s*=($func)\b\s*/\n.Fn $1\n/gs;
306        s/\s*=($argnames)\b\s*/\n.Fa $1\n/gs;
307        s/\s*=(struct \w+(?: \*)?)\b\s*/\n.Vt $1\n/gs;
308        s/\s*:([a-z_]+)\b\s*/\n.Va $1\n/gs;
309        s/\s*;([a-z_]+)\b\s*/\n.Dv $1\n/gs;
310        s/\s*=!([a-z_]+)\b\s*/\n.Xr $1 3\n/gs;
311        while (s/\s*=([a-z_]+)\b\s*/\n.Xr $1 3\n/s) {
312            ++$xref{3}->{$1};
313        }
314        s/\s*\"(?=\w)/\n.Do\n/gs;
315        s/\"(?!\w)\s*/\n.Dc\n/gs;
316        s/\s*=([A-Z][A-Z_]+)\b\s*(?![\.,:;])/\n.Dv $1\n/gs;
317        s/\s*=([A-Z][A-Z_]+)\b([\.,:;]+)\s*/\n.Dv $1 $2\n/gs;
318        s/\s*{([A-Z][a-z] .*?)}\s*/\n.$1\n/gs;
319        $man .= "$_\n";
320    }
321    if (defined($man)) {
322        if ($inlist || $intaglist) {
323            $man .= ".El\n";
324            $inlist = $intaglist = 0;
325        }
326        if ($inliteral) {
327            $man .= ".Ed\n";
328            $inliteral = 0;
329        }
330        $man =~ s/\%/\\&\%/gs;
331        $man =~ s/(\n\.[A-Z][a-z] [\w ]+)\n([.,:;-])\s+/$1 $2\n/gs;
332        $man =~ s/\s*$/\n/gm;
333        $man =~ s/\n+/\n/gs;
334        $man =~ s/\0//gs;
335        $man =~ s/\n\n\./\n\./gs;
336        chomp($man);
337    } else {
338        $man = "No description available.";
339    }
340
341    $FUNCTIONS{$func} = {
342        'source'        => $fn,
343        'name'          => $func,
344        'descr'         => $descr,
345        'type'          => $type,
346        'args'          => $args,
347        'man'           => $man,
348        'xref'          => \%xref,
349        'errors'        => \@errors,
350        'author'        => $author,
351        'customrv'      => $customrv,
352    };
353    if ($source =~ m/^ \* NODOC\s*$/m) {
354        $FUNCTIONS{$func}->{'nodoc'} = 1;
355    }
356    if ($source !~ m/^ \* XSSO \d/m) {
357        $FUNCTIONS{$func}->{'openpam'} = 1;
358    }
359    expand_errors($FUNCTIONS{$func});
360    return $FUNCTIONS{$func};
361}
362
363sub expand_errors($);
364sub expand_errors($) {
365    my $func = shift;           # Ref to function hash
366
367    my %errors;
368    my $ref;
369    my $fn;
370
371    if (defined($func->{'recursed'})) {
372        warn("$func->{'name'}(): loop in error spec\n");
373        return qw();
374    }
375    $func->{'recursed'} = 1;
376
377    foreach (@{$func->{'errors'}}) {
378        if (m/^(PAM_[A-Z_]+)$/) {
379            if (!defined($PAMERR{$1})) {
380                warn("$func->{'name'}(): unrecognized error: $1\n");
381                next;
382            }
383            $errors{$1} = 1;
384        } elsif (m/^!(PAM_[A-Z_]+)$/) {
385            # treat negations separately
386        } elsif (m/^=([a-z_]+)$/) {
387            $ref = $1;
388            if (!defined($FUNCTIONS{$ref})) {
389                $fn = $func->{'source'};
390                $fn =~ s/$func->{'name'}/$ref/;
391                parse_source($fn);
392            }
393            if (!defined($FUNCTIONS{$ref})) {
394                warn("$func->{'name'}(): reference to unknown $ref()\n");
395                next;
396            }
397            foreach (@{$FUNCTIONS{$ref}->{'errors'}}) {
398                $errors{$_} = 1;
399            }
400        } else {
401            warn("$func->{'name'}(): invalid error specification: $_\n");
402        }
403    }
404    foreach (@{$func->{'errors'}}) {
405        if (m/^!(PAM_[A-Z_]+)$/) {
406            delete($errors{$1});
407        }
408    }
409    delete($func->{'recursed'});
410    $func->{'errors'} = [ sort(keys(%errors)) ];
411}
412
413sub dictionary_order($$) {
414    my ($a, $b) = @_;
415
416    $a =~ s/[^[:alpha:]]//g;
417    $b =~ s/[^[:alpha:]]//g;
418    $a cmp $b;
419}
420
421sub genxref($) {
422    my $xref = shift;           # References
423
424    my $mdoc = '';
425    my @refs = ();
426    foreach my $sect (sort(keys(%{$xref}))) {
427        foreach my $page (sort(dictionary_order keys(%{$xref->{$sect}}))) {
428            push(@refs, "$page $sect");
429        }
430    }
431    while ($_ = shift(@refs)) {
432        $mdoc .= ".Xr $_" .
433            (@refs ? " ,\n" : "\n");
434    }
435    return $mdoc;
436}
437
438sub gendoc($) {
439    my $func = shift;           # Ref to function hash
440
441    local *FILE;
442    my $mdoc;
443    my $fn;
444
445    return if defined($func->{'nodoc'});
446
447    $mdoc = "$COPYRIGHT
448.Dd $TODAY
449.Dt " . uc($func->{'name'}) . " 3
450.Os
451.Sh NAME
452.Nm $func->{'name'}
453.Nd $func->{'descr'}
454.Sh LIBRARY
455.Lb libpam
456.Sh SYNOPSIS
457.In sys/types.h
458.In security/pam_appl.h
459";
460    if ($func->{'name'} =~ m/_sm_/) {
461        $mdoc .= ".In security/pam_modules.h\n"
462    }
463    if ($func->{'name'} =~ m/openpam/) {
464        $mdoc .= ".In security/openpam.h\n"
465    }
466    $mdoc .= ".Ft \"$func->{'type'}\"
467.Fn $func->{'name'} $func->{'args'}
468.Sh DESCRIPTION
469$func->{'man'}
470";
471    my @errors = @{$func->{'errors'}};
472    if ($func->{'customrv'}) {
473        # leave it
474    } elsif ($func->{'type'} eq "int" && @errors) {
475        $mdoc .= ".Sh RETURN VALUES
476The
477.Fn $func->{'name'}
478function returns one of the following values:
479.Bl -tag -width 18n
480";
481        foreach (@errors) {
482            $mdoc .= ".It Bq Er $_\n$PAMERR{$_}.\n";
483        }
484        $mdoc .= ".El\n";
485    } elsif ($func->{'type'} eq "int") {
486        $mdoc .= ".Sh RETURN VALUES
487The
488.Fn $func->{'name'}
489function returns 0 on success and -1 on failure.
490";
491    } elsif ($func->{'type'} =~ m/\*$/) {
492        $mdoc .= ".Sh RETURN VALUES
493The
494.Fn $func->{'name'}
495function returns
496.Dv NULL
497on failure.
498";
499    } elsif ($func->{'type'} ne "void") {
500        warn("$func->{'name'}(): no error specification\n");
501    }
502    $mdoc .= ".Sh SEE ALSO\n" . genxref($func->{'xref'});
503    $mdoc .= ".Sh STANDARDS\n";
504    if ($func->{'openpam'}) {
505        $mdoc .= "The
506.Fn $func->{'name'}
507function is an OpenPAM extension.
508";
509    } else {
510        $mdoc .= ".Rs
511.%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
512.%D \"June 1997\"
513.Re
514";
515    }
516    $mdoc .= ".Sh AUTHORS
517The
518.Fn $func->{'name'}
519function and this manual page were developed for the
520.Fx
521Project by\n" . $AUTHORS{$func->{'author'} // 'THINKSEC_DARPA'} . "\n";
522    $fn = "$func->{'name'}.3";
523    if (open(FILE, ">", $fn)) {
524        print(FILE $mdoc);
525        close(FILE);
526    } else {
527        warn("$fn: open(): $!\n");
528    }
529}
530
531sub readproto($) {
532    my $fn = shift;             # File name
533
534    local *FILE;
535    my %func;
536
537    open(FILE, "<", "$fn")
538        or die("$fn: open(): $!\n");
539    while (<FILE>) {
540        if (m/^\.Nm ((?:open)?pam_.*?)\s*$/) {
541            $func{'Nm'} = $func{'Nm'} || $1;
542        } elsif (m/^\.Ft (\S.*?)\s*$/) {
543            $func{'Ft'} = $func{'Ft'} || $1;
544        } elsif (m/^\.Fn (\S.*?)\s*$/) {
545            $func{'Fn'} = $func{'Fn'} || $1;
546        }
547    }
548    close(FILE);
549    if ($func{'Nm'}) {
550        $FUNCTIONS{$func{'Nm'}} = \%func;
551    } else {
552        warn("No function found\n");
553    }
554}
555
556sub gensummary($) {
557    my $page = shift;           # Which page to produce
558
559    local *FILE;
560    my $upage;
561    my $func;
562    my %xref;
563
564    open(FILE, ">", "$page.3")
565        or die("$page.3: $!\n");
566
567    $page =~ m/(\w+)$/;
568    $upage = uc($1);
569    print FILE "$COPYRIGHT
570.Dd $TODAY
571.Dt $upage 3
572.Os
573.Sh NAME
574";
575    my @funcs = sort(keys(%FUNCTIONS));
576    while ($func = shift(@funcs)) {
577        print FILE ".Nm $FUNCTIONS{$func}->{'Nm'}";
578        print FILE " ,"
579                if (@funcs);
580        print FILE "\n";
581    }
582    print FILE ".Nd Pluggable Authentication Modules Library
583.Sh LIBRARY
584.Lb libpam
585.Sh SYNOPSIS\n";
586    if ($page eq 'pam') {
587        print FILE ".In security/pam_appl.h\n";
588    } else {
589        print FILE ".In security/openpam.h\n";
590    }
591    foreach $func (sort(keys(%FUNCTIONS))) {
592        print FILE ".Ft $FUNCTIONS{$func}->{'Ft'}\n";
593        print FILE ".Fn $FUNCTIONS{$func}->{'Fn'}\n";
594    }
595    while (<STDIN>) {
596        if (m/^\.Xr (\S+)\s*(\d)\s*$/) {
597            ++$xref{int($2)}->{$1};
598        }
599        print FILE $_;
600    }
601
602    if ($page eq 'pam') {
603        print FILE ".Sh RETURN VALUES
604The following return codes are defined by
605.In security/pam_constants.h :
606.Bl -tag -width 18n
607";
608        foreach (sort(keys(%PAMERR))) {
609            print FILE ".It Bq Er $_\n$PAMERR{$_}.\n";
610        }
611        print FILE ".El\n";
612    }
613    print FILE ".Sh SEE ALSO
614";
615    if ($page eq 'pam') {
616        ++$xref{3}->{'openpam'};
617    }
618    foreach $func (keys(%FUNCTIONS)) {
619        ++$xref{3}->{$func};
620    }
621    print FILE genxref(\%xref);
622    print FILE ".Sh STANDARDS
623.Rs
624.%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
625.%D \"June 1997\"
626.Re
627.Sh AUTHORS
628The OpenPAM library and this manual page were developed for the
629.Fx
630Project by ThinkSec AS and Network Associates Laboratories, the
631Security Research Division of Network Associates, Inc.\\& under
632DARPA/SPAWAR contract N66001-01-C-8035
633.Pq Dq CBOSS ,
634as part of the DARPA CHATS research program.
635";
636    close(FILE);
637}
638
639sub usage() {
640
641    print(STDERR "usage: gendoc [-op] source [...]\n");
642    exit(1);
643}
644
645MAIN:{
646    my %opts;
647
648    usage()
649        unless (@ARGV && getopts("op", \%opts));
650    setlocale(LC_ALL, "en_US.UTF-8");
651    $TODAY = strftime("%B %e, %Y", localtime(time()));
652    $TODAY =~ s,\s+, ,g;
653    if ($opts{'o'} || $opts{'p'}) {
654        foreach my $fn (@ARGV) {
655            readproto($fn);
656        }
657        gensummary('openpam')
658            if ($opts{'o'});
659        gensummary('pam')
660            if ($opts{'p'});
661    } else {
662        foreach my $fn (@ARGV) {
663            my $func = parse_source($fn);
664            gendoc($func)
665                if (defined($func));
666        }
667    }
668    exit(0);
669}
Note: See TracBrowser for help on using the repository browser.