]>
git.cameronkatri.com Git - mandoc.git/blob - cgi.c
1 /* $Id: cgi.c,v 1.84 2014/07/25 16:43:37 schwarze Exp $ */
3 * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2014 Ingo Schwarze <schwarze@usta.de>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32 #include "mandoc_aux.h"
35 #include "mansearch.h"
39 * A query as passed to the search function.
42 char *manpath
; /* desired manual directory */
43 char *arch
; /* architecture */
44 char *sec
; /* manual section */
45 char *expr
; /* unparsed expression string */
46 int equal
; /* match whole names, not substrings */
51 char **p
; /* array of available manpaths */
52 size_t psz
; /* number of available manpaths */
55 static void catman(const struct req
*, const char *);
56 static void format(const struct req
*, const char *);
57 static void html_print(const char *);
58 static void html_printquery(const struct req
*);
59 static void html_putchar(char);
60 static int http_decode(char *);
61 static void http_parse(struct req
*, const char *);
62 static void http_print(const char *);
63 static void http_putchar(char);
64 static void http_printquery(const struct req
*);
65 static void pathgen(struct req
*);
66 static void pg_error_badrequest(const char *);
67 static void pg_error_internal(void);
68 static void pg_index(const struct req
*);
69 static void pg_noresult(const struct req
*, const char *);
70 static void pg_search(const struct req
*);
71 static void pg_searchres(const struct req
*,
72 struct manpage
*, size_t);
73 static void pg_show(struct req
*, const char *);
74 static void resp_begin_html(int, const char *);
75 static void resp_begin_http(int, const char *);
76 static void resp_end_html(void);
77 static void resp_searchform(const struct req
*);
78 static void resp_show(const struct req
*, const char *);
80 static const char *scriptname
; /* CGI script name */
82 static const int sec_prios
[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
83 static const char *const sec_numbers
[] = {
84 "0", "1", "2", "3", "3p", "4", "5", "6", "7", "8", "9"
86 static const char *const sec_names
[] = {
88 "1 - General Commands",
91 "3p - Perl Subroutines",
95 "7 - Macros and Conventions",
96 "8 - Maintenance Commands",
97 "9 - Kernel Interface"
99 static const int sec_MAX
= sizeof(sec_names
) / sizeof(char *);
101 static const char *const arch_names
[] = {
102 "amd64", "alpha", "armish", "armv7",
103 "aviion", "hppa", "hppa64", "i386",
104 "ia64", "landisk", "loongson", "luna88k",
105 "macppc", "mips64", "octeon", "sgi",
106 "socppc", "solbourne", "sparc", "sparc64",
108 "amiga", "arc", "arm32", "atari",
109 "beagle", "cats", "hp300", "mac68k",
110 "mvme68k", "mvme88k", "mvmeppc", "palm",
111 "pc532", "pegasos", "pmax", "powerpc",
112 "sun3", "wgrisc", "x68k"
114 static const int arch_MAX
= sizeof(arch_names
) / sizeof(char *);
117 * Print a character, escaping HTML along the way.
118 * This will pass non-ASCII straight to output: be warned!
138 putchar((unsigned char)c
);
144 http_printquery(const struct req
*req
)
147 if (NULL
!= req
->q
.manpath
) {
149 http_print(req
->q
.manpath
);
151 if (NULL
!= req
->q
.sec
) {
153 http_print(req
->q
.sec
);
155 if (NULL
!= req
->q
.arch
) {
157 http_print(req
->q
.arch
);
159 if (NULL
!= req
->q
.expr
) {
161 http_print(req
->q
.expr
);
163 if (0 == req
->q
.equal
)
164 printf("&apropos=1");
168 html_printquery(const struct req
*req
)
171 if (NULL
!= req
->q
.manpath
) {
172 printf("&manpath=");
173 html_print(req
->q
.manpath
);
175 if (NULL
!= req
->q
.sec
) {
177 html_print(req
->q
.sec
);
179 if (NULL
!= req
->q
.arch
) {
180 printf("&arch=");
181 html_print(req
->q
.arch
);
183 if (NULL
!= req
->q
.expr
) {
184 printf("&query=");
185 html_print(req
->q
.expr
);
187 if (0 == req
->q
.equal
)
188 printf("&apropos=1");
192 http_print(const char *p
)
202 * Call through to html_putchar().
203 * Accepts NULL strings.
206 html_print(const char *p
)
216 * Transfer the responsibility for the allocated string *val
217 * to the query structure.
220 set_query_attr(char **attr
, char **val
)
233 * Parse the QUERY_STRING for key-value pairs
234 * and store the values into the query structure.
237 http_parse(struct req
*req
, const char *qs
)
242 req
->q
.manpath
= NULL
;
249 while (*qs
!= '\0') {
253 keysz
= strcspn(qs
, "=;&");
254 key
= mandoc_strndup(qs
, keysz
);
259 /* Parse one value. */
261 valsz
= strcspn(++qs
, ";&");
262 val
= mandoc_strndup(qs
, valsz
);
265 /* Decode and catch encoding errors. */
267 if ( ! (http_decode(key
) && http_decode(val
)))
270 /* Handle key-value pairs. */
272 if ( ! strcmp(key
, "query"))
273 set_query_attr(&req
->q
.expr
, &val
);
275 else if ( ! strcmp(key
, "apropos"))
276 req
->q
.equal
= !strcmp(val
, "0");
278 else if ( ! strcmp(key
, "manpath")) {
280 if ( ! strncmp(val
, "OpenBSD ", 8)) {
286 set_query_attr(&req
->q
.manpath
, &val
);
289 else if ( ! (strcmp(key
, "sec")
291 && strcmp(key
, "sektion")
294 if ( ! strcmp(val
, "0"))
296 set_query_attr(&req
->q
.sec
, &val
);
299 else if ( ! strcmp(key
, "arch")) {
300 if ( ! strcmp(val
, "default"))
302 set_query_attr(&req
->q
.arch
, &val
);
306 * The key must be freed in any case.
307 * The val may have been handed over to the query
308 * structure, in which case it is now NULL.
320 /* Fall back to the default manpath. */
322 if (req
->q
.manpath
== NULL
)
323 req
->q
.manpath
= mandoc_strdup(req
->p
[0]);
330 if (isalnum((unsigned char)c
)) {
331 putchar((unsigned char)c
);
333 } else if (' ' == c
) {
341 * HTTP-decode a string. The standard explanation is that this turns
342 * "%4e+foo" into "n foo" in the regular way. This is done in-place
343 * over the allocated string.
355 for ( ; '\0' != *p
; p
++, q
++) {
357 if ('\0' == (hex
[0] = *(p
+ 1)))
359 if ('\0' == (hex
[1] = *(p
+ 2)))
361 if (1 != sscanf(hex
, "%x", &c
))
369 *q
= '+' == *p
? ' ' : *p
;
377 resp_begin_http(int code
, const char *msg
)
381 printf("Status: %d %s\r\n", code
, msg
);
383 printf("Content-Type: text/html; charset=utf-8\r\n"
384 "Cache-Control: no-cache\r\n"
385 "Pragma: no-cache\r\n"
392 resp_begin_html(int code
, const char *msg
)
395 resp_begin_http(code
, msg
);
397 printf("<!DOCTYPE HTML PUBLIC "
398 " \"-//W3C//DTD HTML 4.01//EN\""
399 " \"http://www.w3.org/TR/html4/strict.dtd\">\n"
402 "<META HTTP-EQUIV=\"Content-Type\""
403 " CONTENT=\"text/html; charset=utf-8\">\n"
404 "<LINK REL=\"stylesheet\" HREF=\"%s/man-cgi.css\""
405 " TYPE=\"text/css\" media=\"all\">\n"
406 "<LINK REL=\"stylesheet\" HREF=\"%s/man.css\""
407 " TYPE=\"text/css\" media=\"all\">\n"
408 "<TITLE>%s</TITLE>\n"
411 "<!-- Begin page content. //-->\n",
412 CSS_DIR
, CSS_DIR
, CUSTOMIZE_TITLE
);
424 resp_searchform(const struct req
*req
)
428 puts(CUSTOMIZE_BEGIN
);
429 puts("<!-- Begin search form. //-->");
430 printf("<DIV ID=\"mancgi\">\n"
431 "<FORM ACTION=\"%s\" METHOD=\"get\">\n"
433 "<LEGEND>Manual Page Search Parameters</LEGEND>\n",
436 /* Write query input box. */
438 printf( "<TABLE><TR><TD>\n"
439 "<INPUT TYPE=\"text\" NAME=\"query\" VALUE=\"");
440 if (NULL
!= req
->q
.expr
)
441 html_print(req
->q
.expr
);
442 puts("\" SIZE=\"40\">");
444 /* Write submission and reset buttons. */
446 printf( "<INPUT TYPE=\"submit\" VALUE=\"Submit\">\n"
447 "<INPUT TYPE=\"reset\" VALUE=\"Reset\">\n");
449 /* Write show radio button */
451 printf( "</TD><TD>\n"
452 "<INPUT TYPE=\"radio\" ");
455 printf( "NAME=\"apropos\" ID=\"show\" VALUE=\"0\">\n"
456 "<LABEL FOR=\"show\">Show named manual page</LABEL>\n");
458 /* Write section selector. */
460 printf( "</TD></TR><TR><TD>\n"
461 "<SELECT NAME=\"sec\">");
462 for (i
= 0; i
< sec_MAX
; i
++) {
463 printf("<OPTION VALUE=\"%s\"", sec_numbers
[i
]);
464 if (NULL
!= req
->q
.sec
&&
465 0 == strcmp(sec_numbers
[i
], req
->q
.sec
))
467 printf(">%s</OPTION>\n", sec_names
[i
]);
471 /* Write architecture selector. */
473 printf( "<SELECT NAME=\"arch\">\n"
474 "<OPTION VALUE=\"default\"");
475 if (NULL
== req
->q
.arch
)
477 puts(">All Architectures</OPTION>");
478 for (i
= 0; i
< arch_MAX
; i
++) {
479 printf("<OPTION VALUE=\"%s\"", arch_names
[i
]);
480 if (NULL
!= req
->q
.arch
&&
481 0 == strcmp(arch_names
[i
], req
->q
.arch
))
483 printf(">%s</OPTION>\n", arch_names
[i
]);
487 /* Write manpath selector. */
490 puts("<SELECT NAME=\"manpath\">");
491 for (i
= 0; i
< (int)req
->psz
; i
++) {
493 if (NULL
== req
->q
.manpath
? 0 == i
:
494 0 == strcmp(req
->q
.manpath
, req
->p
[i
]))
497 html_print(req
->p
[i
]);
499 html_print(req
->p
[i
]);
505 /* Write search radio button */
507 printf( "</TD><TD>\n"
508 "<INPUT TYPE=\"radio\" ");
509 if (0 == req
->q
.equal
)
511 printf( "NAME=\"apropos\" ID=\"search\" VALUE=\"1\">\n"
512 "<LABEL FOR=\"search\">Search with apropos query</LABEL>\n");
514 puts("</TD></TR></TABLE>\n"
518 puts("<!-- End search form. //-->");
522 validate_urifrag(const char *frag
)
525 while ('\0' != *frag
) {
526 if ( ! (isalnum((unsigned char)*frag
) ||
527 '-' == *frag
|| '.' == *frag
||
528 '/' == *frag
|| '_' == *frag
))
536 validate_manpath(const struct req
*req
, const char* manpath
)
540 if ( ! strcmp(manpath
, "mandoc"))
543 for (i
= 0; i
< req
->psz
; i
++)
544 if ( ! strcmp(manpath
, req
->p
[i
]))
551 validate_filename(const char *file
)
554 if ('.' == file
[0] && '/' == file
[1])
557 return ( ! (strstr(file
, "../") || strstr(file
, "/..") ||
558 (strncmp(file
, "man", 3) && strncmp(file
, "cat", 3))));
562 pg_index(const struct req
*req
)
565 resp_begin_html(200, NULL
);
566 resp_searchform(req
);
568 "This web interface is documented in the "
569 "<A HREF=\"%s/mandoc/man8/man.cgi.8\">man.cgi</A> "
571 "<A HREF=\"%s/mandoc/man1/apropos.1\">apropos</A> "
572 "manual explains the query syntax.\n"
574 scriptname
, scriptname
);
579 pg_noresult(const struct req
*req
, const char *msg
)
581 resp_begin_html(200, NULL
);
582 resp_searchform(req
);
590 pg_error_badrequest(const char *msg
)
593 resp_begin_html(400, "Bad Request");
594 puts("<H1>Bad Request</H1>\n"
597 printf("Try again from the\n"
598 "<A HREF=\"%s\">main page</A>.\n"
604 pg_error_internal(void)
606 resp_begin_html(500, "Internal Server Error");
607 puts("<P>Internal Server Error</P>");
612 pg_searchres(const struct req
*req
, struct manpage
*r
, size_t sz
)
614 char *arch
, *archend
;
615 size_t i
, iuse
, isec
;
616 int archprio
, archpriouse
;
620 for (i
= 0; i
< sz
; i
++) {
621 if (validate_filename(r
[i
].file
))
623 fprintf(stderr
, "invalid filename %s in %s database\n",
624 r
[i
].file
, req
->q
.manpath
);
631 * If we have just one result, then jump there now
634 printf("Status: 303 See Other\r\n");
635 printf("Location: http://%s%s/%s/%s?",
636 HTTP_HOST
, scriptname
, req
->q
.manpath
, r
[0].file
);
637 http_printquery(req
);
639 "Content-Type: text/html; charset=utf-8\r\n"
644 resp_begin_html(200, NULL
);
645 resp_searchform(req
);
646 puts("<DIV CLASS=\"results\">");
649 for (i
= 0; i
< sz
; i
++) {
651 "<TD CLASS=\"title\">\n"
652 "<A HREF=\"%s/%s/%s?",
653 scriptname
, req
->q
.manpath
, r
[i
].file
);
654 html_printquery(req
);
656 html_print(r
[i
].names
);
659 "<TD CLASS=\"desc\">");
660 html_print(r
[i
].output
);
669 * In man(1) mode, show one of the pages
670 * even if more than one is found.
678 for (i
= 0; i
< sz
; i
++) {
679 isec
= strcspn(r
[i
].file
, "123456789");
680 sec
= r
[i
].file
[isec
];
683 prio
= sec_prios
[sec
- '1'];
684 if (NULL
== req
->q
.arch
) {
686 (NULL
== (arch
= strchr(
687 r
[i
].file
+ isec
, '/'))) ? 3 :
688 (NULL
== (archend
= strchr(
689 arch
+ 1, '/'))) ? 0 :
690 strncmp(arch
, "amd64/",
691 archend
- arch
) ? 2 : 1;
692 if (archprio
< archpriouse
) {
693 archpriouse
= archprio
;
698 if (archprio
> archpriouse
)
706 resp_show(req
, r
[iuse
].file
);
713 catman(const struct req
*req
, const char *file
)
721 if (NULL
== (f
= fopen(file
, "r"))) {
722 puts("<P>You specified an invalid manual file.</P>");
726 puts("<DIV CLASS=\"catman\">\n"
729 while (NULL
!= (p
= fgetln(f
, &len
))) {
731 for (i
= 0; i
< (int)len
- 1; i
++) {
733 * This means that the catpage is out of state.
734 * Ignore it and keep going (although the
738 if ('\b' == p
[i
] || '\n' == p
[i
])
742 * Print a regular character.
743 * Close out any bold/italic scopes.
744 * If we're in back-space mode, make sure we'll
745 * have something to enter when we backspace.
748 if ('\b' != p
[i
+ 1]) {
756 } else if (i
+ 2 >= (int)len
)
774 * Handle funny behaviour troff-isms.
775 * These grok'd from the original man2html.c.
778 if (('+' == p
[i
] && 'o' == p
[i
+ 2]) ||
779 ('o' == p
[i
] && '+' == p
[i
+ 2]) ||
780 ('|' == p
[i
] && '=' == p
[i
+ 2]) ||
781 ('=' == p
[i
] && '|' == p
[i
+ 2]) ||
782 ('*' == p
[i
] && '=' == p
[i
+ 2]) ||
783 ('=' == p
[i
] && '*' == p
[i
+ 2]) ||
784 ('*' == p
[i
] && '|' == p
[i
+ 2]) ||
785 ('|' == p
[i
] && '*' == p
[i
+ 2])) {
794 } else if (('|' == p
[i
] && '-' == p
[i
+ 2]) ||
795 ('-' == p
[i
] && '|' == p
[i
+ 1]) ||
796 ('+' == p
[i
] && '-' == p
[i
+ 1]) ||
797 ('-' == p
[i
] && '+' == p
[i
+ 1]) ||
798 ('+' == p
[i
] && '|' == p
[i
+ 1]) ||
799 ('|' == p
[i
] && '+' == p
[i
+ 1])) {
823 * Clean up the last character.
824 * We can get to a newline; don't print that.
832 if (i
== (int)len
- 1 && '\n' != p
[i
])
845 format(const struct req
*req
, const char *file
)
853 char opts
[PATH_MAX
+ 128];
855 if (-1 == (fd
= open(file
, O_RDONLY
, 0))) {
856 puts("<P>You specified an invalid manual file.</P>");
860 mp
= mparse_alloc(MPARSE_SO
, MANDOCLEVEL_FATAL
, NULL
,
862 rc
= mparse_readfd(mp
, fd
, file
);
865 if (rc
>= MANDOCLEVEL_FATAL
) {
866 fprintf(stderr
, "fatal mandoc error: %s/%s\n",
867 req
->q
.manpath
, file
);
872 snprintf(opts
, sizeof(opts
), "fragment,man=%s?"
873 "manpath=%s&query=%%N&sec=%%S&arch=%s",
874 scriptname
, req
->q
.manpath
,
875 req
->q
.arch
? req
->q
.arch
: "");
877 mparse_result(mp
, &mdoc
, &man
, NULL
);
878 if (NULL
== man
&& NULL
== mdoc
) {
879 fprintf(stderr
, "fatal mandoc error: %s/%s\n",
880 req
->q
.manpath
, file
);
886 vp
= html_alloc(opts
);
898 resp_show(const struct req
*req
, const char *file
)
901 if ('.' == file
[0] && '/' == file
[1])
911 pg_show(struct req
*req
, const char *fullpath
)
916 if ((file
= strchr(fullpath
, '/')) == NULL
) {
918 "You did not specify a page to show.");
921 manpath
= mandoc_strndup(fullpath
, file
- fullpath
);
924 if ( ! validate_manpath(req
, manpath
)) {
926 "You specified an invalid manpath.");
932 * Begin by chdir()ing into the manpath.
933 * This way we can pick up the database files, which are
934 * relative to the manpath root.
937 if (chdir(manpath
) == -1) {
938 fprintf(stderr
, "chdir %s: %s\n",
939 manpath
, strerror(errno
));
945 if (strcmp(manpath
, "mandoc")) {
946 free(req
->q
.manpath
);
947 req
->q
.manpath
= manpath
;
951 if ( ! validate_filename(file
)) {
953 "You specified an invalid manual file.");
957 resp_begin_html(200, NULL
);
958 resp_searchform(req
);
959 resp_show(req
, file
);
964 pg_search(const struct req
*req
)
966 struct mansearch search
;
967 struct manpaths paths
;
970 const char *ep
, *start
;
975 * Begin by chdir()ing into the root of the manpath.
976 * This way we can pick up the database files, which are
977 * relative to the manpath root.
980 if (-1 == (chdir(req
->q
.manpath
))) {
981 fprintf(stderr
, "chdir %s: %s\n",
982 req
->q
.manpath
, strerror(errno
));
987 search
.arch
= req
->q
.arch
;
988 search
.sec
= req
->q
.sec
;
989 search
.deftype
= req
->q
.equal
? TYPE_Nm
: (TYPE_Nm
| TYPE_Nd
);
990 search
.flags
= req
->q
.equal
? MANSEARCH_MAN
: 0;
993 paths
.paths
= mandoc_malloc(sizeof(char *));
994 paths
.paths
[0] = mandoc_strdup(".");
997 * Poor man's tokenisation: just break apart by spaces.
998 * Yes, this is half-ass. But it works for now.
1002 while (ep
&& isspace((unsigned char)*ep
))
1007 while (ep
&& '\0' != *ep
) {
1008 cp
= mandoc_reallocarray(cp
, sz
+ 1, sizeof(char *));
1010 while ('\0' != *ep
&& ! isspace((unsigned char)*ep
))
1012 cp
[sz
] = mandoc_malloc((ep
- start
) + 1);
1013 memcpy(cp
[sz
], start
, ep
- start
);
1014 cp
[sz
++][ep
- start
] = '\0';
1015 while (isspace((unsigned char)*ep
))
1019 if (0 == mansearch(&search
, &paths
, sz
, cp
, "Nd", &res
, &ressz
))
1020 pg_noresult(req
, "You entered an invalid query.");
1021 else if (0 == ressz
)
1022 pg_noresult(req
, "No results found.");
1024 pg_searchres(req
, res
, ressz
);
1026 for (i
= 0; i
< sz
; i
++)
1030 for (i
= 0; i
< (int)ressz
; i
++) {
1033 free(res
[i
].output
);
1037 free(paths
.paths
[0]);
1046 const char *querystring
;
1049 /* Scan our run-time environment. */
1051 if (NULL
== (scriptname
= getenv("SCRIPT_NAME")))
1054 if ( ! validate_urifrag(scriptname
)) {
1055 fprintf(stderr
, "unsafe SCRIPT_NAME \"%s\"\n",
1057 pg_error_internal();
1058 return(EXIT_FAILURE
);
1062 * First we change directory into the MAN_DIR so that
1063 * subsequent scanning for manpath directories is rooted
1064 * relative to the same position.
1067 if (-1 == chdir(MAN_DIR
)) {
1068 fprintf(stderr
, "MAN_DIR: %s: %s\n",
1069 MAN_DIR
, strerror(errno
));
1070 pg_error_internal();
1071 return(EXIT_FAILURE
);
1074 memset(&req
, 0, sizeof(struct req
));
1077 /* Next parse out the query string. */
1079 if (NULL
!= (querystring
= getenv("QUERY_STRING")))
1080 http_parse(&req
, querystring
);
1082 if ( ! validate_manpath(&req
, req
.q
.manpath
)) {
1083 pg_error_badrequest(
1084 "You specified an invalid manpath.");
1085 return(EXIT_FAILURE
);
1088 if ( ! (NULL
== req
.q
.arch
|| validate_urifrag(req
.q
.arch
))) {
1089 pg_error_badrequest(
1090 "You specified an invalid architecture.");
1091 return(EXIT_FAILURE
);
1094 /* Dispatch to the three different pages. */
1096 path
= getenv("PATH_INFO");
1099 else if ('/' == *path
)
1103 pg_show(&req
, path
);
1104 else if (NULL
!= req
.q
.expr
)
1109 free(req
.q
.manpath
);
1113 for (i
= 0; i
< (int)req
.psz
; i
++)
1116 return(EXIT_SUCCESS
);
1120 * Scan for indexable paths.
1123 pathgen(struct req
*req
)
1129 if (NULL
== (fp
= fopen("manpath.conf", "r"))) {
1130 fprintf(stderr
, "%s/manpath.conf: %s\n",
1131 MAN_DIR
, strerror(errno
));
1132 pg_error_internal();
1136 while (NULL
!= (dp
= fgetln(fp
, &dpsz
))) {
1137 if ('\n' == dp
[dpsz
- 1])
1139 req
->p
= mandoc_realloc(req
->p
,
1140 (req
->psz
+ 1) * sizeof(char *));
1141 dp
= mandoc_strndup(dp
, dpsz
);
1142 if ( ! validate_urifrag(dp
)) {
1143 fprintf(stderr
, "%s/manpath.conf contains "
1144 "unsafe path \"%s\"\n", MAN_DIR
, dp
);
1145 pg_error_internal();
1148 if (NULL
!= strchr(dp
, '/')) {
1149 fprintf(stderr
, "%s/manpath.conf contains "
1150 "path with slash \"%s\"\n", MAN_DIR
, dp
);
1151 pg_error_internal();
1154 req
->p
[req
->psz
++] = dp
;
1157 if ( req
->p
== NULL
) {
1158 fprintf(stderr
, "%s/manpath.conf is empty\n", MAN_DIR
);
1159 pg_error_internal();