gendoc.pl revision 1.2.8.1 1 #!/usr/bin/perl -w
2 #-
3 # Copyright (c) 2002-2003 Networks Associates Technology, Inc.
4 # Copyright (c) 2004-2011 Dag-Erling Smrgrav
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: gendoc.pl 599 2012-04-14 15:06:41Z des
37 #
38
39 use strict;
40 use locale;
41 use Fcntl;
42 use Getopt::Std;
43 use POSIX qw(locale_h strftime);
44 use 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 Smrgrav
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 => "developed for the
85 .Fx
86 Project by ThinkSec AS and Network Associates Laboratories, the
87 Security Research Division of Network Associates, Inc.\\& under
88 DARPA/SPAWAR contract N66001-01-C-8035
89 .Pq Dq CBOSS ,
90 as part of the DARPA CHATS research program.",
91 DES => "developed by
92 .An Dag-Erling Sm\\(/orgrav Aq des\@des.no .",
93 );
94
95 %PAMERR = (
96 PAM_SUCCESS => "Success",
97 PAM_OPEN_ERR => "Failed to load module",
98 PAM_SYMBOL_ERR => "Invalid symbol",
99 PAM_SERVICE_ERR => "Error in service module",
100 PAM_SYSTEM_ERR => "System error",
101 PAM_BUF_ERR => "Memory buffer error",
102 PAM_CONV_ERR => "Conversation failure",
103 PAM_PERM_DENIED => "Permission denied",
104 PAM_MAXTRIES => "Maximum number of tries exceeded",
105 PAM_AUTH_ERR => "Authentication error",
106 PAM_NEW_AUTHTOK_REQD => "New authentication token required",
107 PAM_CRED_INSUFFICIENT => "Insufficient credentials",
108 PAM_AUTHINFO_UNAVAIL => "Authentication information is unavailable",
109 PAM_USER_UNKNOWN => "Unknown user",
110 PAM_CRED_UNAVAIL => "Failed to retrieve user credentials",
111 PAM_CRED_EXPIRED => "User credentials have expired",
112 PAM_CRED_ERR => "Failed to set user credentials",
113 PAM_ACCT_EXPIRED => "User account has expired",
114 PAM_AUTHTOK_EXPIRED => "Password has expired",
115 PAM_SESSION_ERR => "Session failure",
116 PAM_AUTHTOK_ERR => "Authentication token failure",
117 PAM_AUTHTOK_RECOVERY_ERR => "Failed to recover old authentication token",
118 PAM_AUTHTOK_LOCK_BUSY => "Authentication token lock busy",
119 PAM_AUTHTOK_DISABLE_AGING => "Authentication token aging disabled",
120 PAM_NO_MODULE_DATA => "Module data not found",
121 PAM_IGNORE => "Ignore this module",
122 PAM_ABORT => "General failure",
123 PAM_TRY_AGAIN => "Try again",
124 PAM_MODULE_UNKNOWN => "Unknown module type",
125 PAM_DOMAIN_UNKNOWN => "Unknown authentication domain",
126 );
127
128 sub parse_source($) {
129 my $fn = shift;
130
131 local *FILE;
132 my $source;
133 my $func;
134 my $descr;
135 my $type;
136 my $args;
137 my $argnames;
138 my $man;
139 my $inlist;
140 my $intaglist;
141 my $inliteral;
142 my $customrv;
143 my $deprecated;
144 my $experimental;
145 my %xref;
146 my @errors;
147 my $author;
148
149 if ($fn !~ m,\.c$,) {
150 warn("$fn: not C source, ignoring\n");
151 return undef;
152 }
153
154 open(FILE, "<", "$fn")
155 or die("$fn: open(): $!\n");
156 $source = join('', <FILE>);
157 close(FILE);
158
159 return undef
160 if ($source =~ m/^ \* NOPARSE\s*$/m);
161
162 $author = 'THINKSEC';
163 if ($source =~ s/^ \* AUTHOR\s+(\w*)\s*$//m) {
164 $author = $1;
165 }
166
167 if ($source =~ s/^ \* DEPRECATED\s*(\w*)\s*$//m) {
168 $deprecated = $1 // 0;
169 }
170
171 if ($source =~ s/^ \* EXPERIMENTAL\s*$//m) {
172 $experimental = 1;
173 }
174
175 $func = $fn;
176 $func =~ s,^(?:.*/)?([^/]+)\.c$,$1,;
177 if ($source !~ m,\n \* ([\S ]+)\n \*/\n\n([\S ]+)\n$func\((.*?)\)\n\{,s) {
178 warn("$fn: can't find $func\n");
179 return undef;
180 }
181 ($descr, $type, $args) = ($1, $2, $3);
182 $descr =~ s,^([A-Z][a-z]),lc($1),e;
183 $descr =~ s,[\.\s]*$,,;
184 while ($args =~ s/^((?:[^\(]|\([^\)]*\))*),\s*/$1\" \"/g) {
185 # nothing
186 }
187 $args =~ s/,\s+/, /gs;
188 $args = "\"$args\"";
189
190 %xref = (
191 3 => { 'pam' => 1 },
192 );
193
194 if ($type eq "int") {
195 foreach (split("\n", $source)) {
196 next unless (m/^ \*\s+(!?PAM_[A-Z_]+|=[a-z_]+)\s*$/);
197 push(@errors, $1);
198 }
199 ++$xref{3}->{'pam_strerror'};
200 }
201
202 $argnames = $args;
203 # extract names of regular arguments
204 $argnames =~ s/\"[^\"]+\*?\b(\w+)\"/\"$1\"/g;
205 # extract names of function pointer arguments
206 $argnames =~ s/\"([\w\s\*]+)\(\*?(\w+)\)\([^\)]+\)\"/\"$2\"/g;
207 # escape metacharacters (there shouldn't be any, but...)
208 $argnames =~ s/([\|\[\]\(\)\.\*\+\?])/\\$1/g;
209 # separate argument names with |
210 $argnames =~ s/\" \"/|/g;
211 # and surround with ()
212 $argnames =~ s/^\"(.*)\"$/$1/;
213 # $argnames is now a regexp that matches argument names
214 $inliteral = $inlist = $intaglist = 0;
215 foreach (split("\n", $source)) {
216 s/\s*$//;
217 if (!defined($man)) {
218 if (m/^\/\*\*$/) {
219 $man = "";
220 }
221 next;
222 }
223 last if (m/^ \*\/$/);
224 s/^ \* ?//;
225 s/\\(.)/$1/gs;
226 if (m/^$/) {
227 # paragraph separator
228 if ($inlist || $intaglist) {
229 # either a blank line between list items, or a blank
230 # line after the final list item. The latter case
231 # will be handled further down.
232 next;
233 }
234 if ($man =~ m/\n\.Sh [^\n]+\n$/s) {
235 # a blank line after a section header
236 next;
237 }
238 if ($man ne "" && $man !~ m/\.Pp\n$/s) {
239 if ($inliteral) {
240 $man .= "\0\n";
241 } else {
242 $man .= ".Pp\n";
243 }
244 }
245 next;
246 }
247 if (m/^>(\w+)(\s+\d)?$/) {
248 # "see also" cross-reference
249 my ($page, $sect) = ($1, $2 ? int($2) : 3);
250 ++$xref{$sect}->{$page};
251 next;
252 }
253 if (s/^([A-Z][0-9A-Z -]+)$/.Sh $1/) {
254 if ($1 eq "RETURN VALUES") {
255 $customrv = $1;
256 }
257 $man =~ s/\n\.Pp$/\n/s;
258 $man .= "$_\n";
259 next;
260 }
261 if (s/^\s+-\s+//) {
262 # item in bullet list
263 if ($inliteral) {
264 $man .= ".Ed\n";
265 $inliteral = 0;
266 }
267 if ($intaglist) {
268 $man .= ".El\n.Pp\n";
269 $intaglist = 0;
270 }
271 if (!$inlist) {
272 $man =~ s/\.Pp\n$//s;
273 $man .= ".Bl -bullet\n";
274 $inlist = 1;
275 }
276 $man .= ".It\n";
277 # fall through
278 } elsif (s/^\s+(\S+):\s*/.It $1/) {
279 # item in tag list
280 if ($inliteral) {
281 $man .= ".Ed\n";
282 $inliteral = 0;
283 }
284 if ($inlist) {
285 $man .= ".El\n.Pp\n";
286 $inlist = 0;
287 }
288 if (!$intaglist) {
289 $man =~ s/\.Pp\n$//s;
290 $man .= ".Bl -tag -width 18n\n";
291 $intaglist = 1;
292 }
293 s/^\.It =([A-Z][A-Z_]+)$/.It Dv $1/gs;
294 $man .= "$_\n";
295 next;
296 } elsif (($inlist || $intaglist) && m/^\S/) {
297 # regular text after list
298 $man .= ".El\n.Pp\n";
299 $inlist = $intaglist = 0;
300 } elsif ($inliteral && m/^\S/) {
301 # regular text after literal section
302 $man .= ".Ed\n";
303 $inliteral = 0;
304 } elsif ($inliteral) {
305 # additional text within literal section
306 $man .= "$_\n";
307 next;
308 } elsif ($inlist || $intaglist) {
309 # additional text within list
310 s/^\s+//;
311 } elsif (m/^\s+/) {
312 # new literal section
313 $man .= ".Bd -literal\n";
314 $inliteral = 1;
315 $man .= "$_\n";
316 next;
317 }
318 s/\s*=($func)\b\s*/\n.Fn $1\n/gs;
319 s/\s*=($argnames)\b\s*/\n.Fa $1\n/gs;
320 s/\s*=(struct \w+(?: \*)?)\b\s*/\n.Vt $1\n/gs;
321 s/\s*:([a-z_]+)\b\s*/\n.Va $1\n/gs;
322 s/\s*;([a-z_]+)\b\s*/\n.Dv $1\n/gs;
323 s/\s*=cleanup\s*/\n.Ar cleanup\n/gs;
324 s/\s*=!([a-z_]+)\b\s*/\n.Xr $1 3\n/gs;
325 while (s/\s*=([a-z_]+)\b\s*/\n.Xr $1 3\n/s) {
326 ++$xref{3}->{$1};
327 }
328 s/\s*\"(?=\w)/\n.Do\n/gs;
329 s/\"(?!\w)\s*/\n.Dc\n/gs;
330 s/\s*=([A-Z][A-Z_]+)\b\s*(?![\.,:;])/\n.Dv $1\n/gs;
331 s/\s*=([A-Z][A-Z_]+)\b([\.,:;]+)\s*/\n.Dv $1 $2\n/gs;
332 s/\s*{([A-Z][a-z] .*?)}\s*/\n.$1\n/gs;
333 $man .= "$_\n";
334 }
335 if (defined($man)) {
336 if ($inlist || $intaglist) {
337 $man .= ".El\n";
338 $inlist = $intaglist = 0;
339 }
340 if ($inliteral) {
341 $man .= ".Ed\n";
342 $inliteral = 0;
343 }
344 $man =~ s/\%/\\&\%/gs;
345 $man =~ s/(\n\.[A-Z][a-z] [\w ]+)\n([.,:;-])\s+/$1 $2\n/gs;
346 $man =~ s/\s*$/\n/gm;
347 $man =~ s/\n+/\n/gs;
348 $man =~ s/\0//gs;
349 $man =~ s/\n\n\./\n\./gs;
350 chomp($man);
351 } else {
352 $man = "No description available.";
353 }
354
355 $FUNCTIONS{$func} = {
356 'source' => $fn,
357 'name' => $func,
358 'descr' => $descr,
359 'type' => $type,
360 'args' => $args,
361 'man' => $man,
362 'xref' => \%xref,
363 'errors' => \@errors,
364 'author' => $author,
365 'customrv' => $customrv,
366 'deprecated' => $deprecated,
367 'experimental' => $experimental,
368 };
369 if ($source =~ m/^ \* NODOC\s*$/m) {
370 $FUNCTIONS{$func}->{'nodoc'} = 1;
371 }
372 if ($source !~ m/^ \* XSSO \d/m) {
373 $FUNCTIONS{$func}->{'openpam'} = 1;
374 }
375 expand_errors($FUNCTIONS{$func});
376 return $FUNCTIONS{$func};
377 }
378
379 sub expand_errors($);
380 sub expand_errors($) {
381 my $func = shift; # Ref to function hash
382
383 my %errors;
384 my $ref;
385 my $fn;
386
387 if (defined($func->{'recursed'})) {
388 warn("$func->{'name'}(): loop in error spec\n");
389 return qw();
390 }
391 $func->{'recursed'} = 1;
392
393 foreach (@{$func->{'errors'}}) {
394 if (m/^(PAM_[A-Z_]+)$/) {
395 if (!defined($PAMERR{$1})) {
396 warn("$func->{'name'}(): unrecognized error: $1\n");
397 next;
398 }
399 $errors{$1} = 1;
400 } elsif (m/^!(PAM_[A-Z_]+)$/) {
401 # treat negations separately
402 } elsif (m/^=([a-z_]+)$/) {
403 $ref = $1;
404 if (!defined($FUNCTIONS{$ref})) {
405 $fn = $func->{'source'};
406 $fn =~ s/$func->{'name'}/$ref/;
407 parse_source($fn);
408 }
409 if (!defined($FUNCTIONS{$ref})) {
410 warn("$func->{'name'}(): reference to unknown $ref()\n");
411 next;
412 }
413 foreach (@{$FUNCTIONS{$ref}->{'errors'}}) {
414 $errors{$_} = 1;
415 }
416 } else {
417 warn("$func->{'name'}(): invalid error specification: $_\n");
418 }
419 }
420 foreach (@{$func->{'errors'}}) {
421 if (m/^!(PAM_[A-Z_]+)$/) {
422 delete($errors{$1});
423 }
424 }
425 delete($func->{'recursed'});
426 $func->{'errors'} = [ sort(keys(%errors)) ];
427 }
428
429 sub dictionary_order($$) {
430 my ($a, $b) = @_;
431
432 $a =~ s/[^[:alpha:]]//g;
433 $b =~ s/[^[:alpha:]]//g;
434 $a cmp $b;
435 }
436
437 sub genxref($) {
438 my $xref = shift; # References
439
440 my $mdoc = '';
441 my @refs = ();
442 foreach my $sect (sort(keys(%{$xref}))) {
443 foreach my $page (sort(dictionary_order keys(%{$xref->{$sect}}))) {
444 push(@refs, "$page $sect");
445 }
446 }
447 while ($_ = shift(@refs)) {
448 $mdoc .= ".Xr $_" .
449 (@refs ? " ,\n" : "\n");
450 }
451 return $mdoc;
452 }
453
454 sub gendoc($) {
455 my $func = shift; # Ref to function hash
456
457 local *FILE;
458 my $mdoc;
459 my $fn;
460
461 return if defined($func->{'nodoc'});
462
463 $mdoc = ".\\\"\t\$".
464 "NetBSD\$
465 .\\\"
466 $COPYRIGHT
467 .Dd $TODAY
468 .Dt " . uc($func->{'name'}) . " 3
469 .Os
470 .Sh NAME
471 .Nm $func->{'name'}
472 .Nd $func->{'descr'}
473 .Sh LIBRARY
474 .Lb libpam
475 .Sh SYNOPSIS
476 .In sys/types.h
477 ";
478 if ($func->{'args'} =~ m/\bFILE \*\b/) {
479 $mdoc .= ".In stdio.h\n";
480 }
481 $mdoc .= ".In security/pam_appl.h
482 ";
483 if ($func->{'name'} =~ m/_sm_/) {
484 $mdoc .= ".In security/pam_modules.h\n";
485 }
486 if ($func->{'name'} =~ m/openpam/) {
487 $mdoc .= ".In security/openpam.h\n";
488 }
489 $mdoc .= ".Ft \"$func->{'type'}\"
490 .Fn $func->{'name'} $func->{'args'}
491 .Sh DESCRIPTION
492 ";
493 if (defined($func->{'deprecated'})) {
494 $mdoc .= ".Bf Sy\n" .
495 "This function is deprecated and may be removed " .
496 "in a future release without further warning.\n";
497 if ($func->{'deprecated'}) {
498 $mdoc .= "The\n.Fn $func->{'deprecated'}\nfunction " .
499 "may be used to achieve similar results.\n";
500 }
501 $mdoc .= ".Ef\n.Pp\n";
502 }
503 if ($func->{'experimental'}) {
504 $mdoc .= ".Bf Sy\n" .
505 "This function is experimental and may be modified or removed " .
506 "in a future release without further warning.\n";
507 $mdoc .= ".Ef\n.Pp\n";
508 }
509 $mdoc .= "$func->{'man'}\n";
510 my @errors = @{$func->{'errors'}};
511 if ($func->{'customrv'}) {
512 # leave it
513 } elsif ($func->{'type'} eq "int" && @errors) {
514 $mdoc .= ".Sh RETURN VALUES
515 The
516 .Fn $func->{'name'}
517 function returns one of the following values:
518 .Bl -tag -width 18n
519 ";
520 foreach (@errors) {
521 $mdoc .= ".It Bq Er $_\n$PAMERR{$_}.\n";
522 }
523 $mdoc .= ".El\n";
524 } elsif ($func->{'type'} eq "int") {
525 $mdoc .= ".Sh RETURN VALUES
526 The
527 .Fn $func->{'name'}
528 function returns 0 on success and -1 on failure.
529 ";
530 } elsif ($func->{'type'} =~ m/\*$/) {
531 $mdoc .= ".Sh RETURN VALUES
532 The
533 .Fn $func->{'name'}
534 function returns
535 .Dv NULL
536 on failure.
537 ";
538 } elsif ($func->{'type'} ne "void") {
539 warn("$func->{'name'}(): no error specification\n");
540 }
541 $mdoc .= ".Sh SEE ALSO\n" . genxref($func->{'xref'});
542 $mdoc .= ".Sh STANDARDS\n";
543 if ($func->{'openpam'}) {
544 $mdoc .= "The
545 .Fn $func->{'name'}
546 function is an OpenPAM extension.
547 ";
548 } else {
549 $mdoc .= ".Rs
550 .%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
551 .%D \"June 1997\"
552 .Re
553 ";
554 }
555 $mdoc .= ".Sh AUTHORS
556 The
557 .Fn $func->{'name'}
558 function and this manual page were\n";
559 $mdoc .= $AUTHORS{$func->{'author'} // 'THINKSEC_DARPA'} . "\n";
560 $fn = "$func->{'name'}.3";
561 if (open(FILE, ">", $fn)) {
562 print(FILE $mdoc);
563 close(FILE);
564 } else {
565 warn("$fn: open(): $!\n");
566 }
567 }
568
569 sub readproto($) {
570 my $fn = shift; # File name
571
572 local *FILE;
573 my %func;
574
575 open(FILE, "<", "$fn")
576 or die("$fn: open(): $!\n");
577 while (<FILE>) {
578 if (m/^\.Nm ((?:open)?pam_.*?)\s*$/) {
579 $func{'Nm'} = $func{'Nm'} || $1;
580 } elsif (m/^\.Ft (\S.*?)\s*$/) {
581 $func{'Ft'} = $func{'Ft'} || $1;
582 } elsif (m/^\.Fn (\S.*?)\s*$/) {
583 $func{'Fn'} = $func{'Fn'} || $1;
584 }
585 }
586 close(FILE);
587 if ($func{'Nm'}) {
588 $FUNCTIONS{$func{'Nm'}} = \%func;
589 } else {
590 warn("No function found\n");
591 }
592 }
593
594 sub gensummary($) {
595 my $page = shift; # Which page to produce
596
597 local *FILE;
598 my $upage;
599 my $func;
600 my %xref;
601
602 open(FILE, ">", "$page.3")
603 or die("$page.3: $!\n");
604
605 $page =~ m/(\w+)$/;
606 $upage = uc($1);
607 print FILE "$COPYRIGHT
608 .Dd $TODAY
609 .Dt $upage 3
610 .Os
611 .Sh NAME
612 ";
613 my @funcs = sort(keys(%FUNCTIONS));
614 while ($func = shift(@funcs)) {
615 print FILE ".Nm $FUNCTIONS{$func}->{'Nm'}";
616 print FILE " ,"
617 if (@funcs);
618 print FILE "\n";
619 }
620 print FILE ".Nd Pluggable Authentication Modules Library
621 .Sh LIBRARY
622 .Lb libpam
623 .Sh SYNOPSIS\n";
624 if ($page eq 'pam') {
625 print FILE ".In security/pam_appl.h\n";
626 } else {
627 print FILE ".In security/openpam.h\n";
628 }
629 foreach $func (sort(keys(%FUNCTIONS))) {
630 print FILE ".Ft $FUNCTIONS{$func}->{'Ft'}\n";
631 print FILE ".Fn $FUNCTIONS{$func}->{'Fn'}\n";
632 }
633 while (<STDIN>) {
634 if (m/^\.Xr (\S+)\s*(\d)\s*$/) {
635 ++$xref{int($2)}->{$1};
636 }
637 print FILE $_;
638 }
639
640 if ($page eq 'pam') {
641 print FILE ".Sh RETURN VALUES
642 The following return codes are defined by
643 .In security/pam_constants.h :
644 .Bl -tag -width 18n
645 ";
646 foreach (sort(keys(%PAMERR))) {
647 print FILE ".It Bq Er $_\n$PAMERR{$_}.\n";
648 }
649 print FILE ".El\n";
650 }
651 print FILE ".Sh SEE ALSO
652 ";
653 if ($page eq 'pam') {
654 ++$xref{3}->{'openpam'};
655 }
656 foreach $func (keys(%FUNCTIONS)) {
657 ++$xref{3}->{$func};
658 }
659 print FILE genxref(\%xref);
660 print FILE ".Sh STANDARDS
661 .Rs
662 .%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
663 .%D \"June 1997\"
664 .Re
665 .Sh AUTHORS
666 The OpenPAM library and this manual page were developed for the
667 .Fx
668 Project by ThinkSec AS and Network Associates Laboratories, the
669 Security Research Division of Network Associates, Inc.\\& under
670 DARPA/SPAWAR contract N66001-01-C-8035
671 .Pq Dq CBOSS ,
672 as part of the DARPA CHATS research program.
673 .Pp
674 The OpenPAM library is maintained by
675 .An Dag-Erling Sm\\(/orgrav Aq des\@des.no .
676 ";
677 close(FILE);
678 }
679
680 sub usage() {
681
682 print(STDERR "usage: gendoc [-op] source [...]\n");
683 exit(1);
684 }
685
686 MAIN:{
687 my %opts;
688
689 usage()
690 unless (@ARGV && getopts("op", \%opts));
691 setlocale(LC_ALL, "en_US.UTF-8");
692 $TODAY = strftime("%B %e, %Y", localtime(time()));
693 $TODAY =~ s,\s+, ,g;
694 if ($opts{'o'} || $opts{'p'}) {
695 foreach my $fn (@ARGV) {
696 readproto($fn);
697 }
698 gensummary('openpam')
699 if ($opts{'o'});
700 gensummary('pam')
701 if ($opts{'p'});
702 } else {
703 foreach my $fn (@ARGV) {
704 my $func = parse_source($fn);
705 gendoc($func)
706 if (defined($func));
707 }
708 }
709 exit(0);
710 }
711