]>
git.cameronkatri.com Git - mandoc.git/blob - cgi.c
1 /* $Id: cgi.c,v 1.91 2014/07/25 21:05:41 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 *query
; /* unparsed query expression */
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_putchar(char);
59 static int http_decode(char *);
60 static void http_parse(struct req
*, const char *);
61 static void http_print(const char *);
62 static void http_putchar(char);
63 static void http_printquery(const struct req
*, const char *);
64 static void pathgen(struct req
*);
65 static void pg_error_badrequest(const char *);
66 static void pg_error_internal(void);
67 static void pg_index(const struct req
*);
68 static void pg_noresult(const struct req
*, const char *);
69 static void pg_search(const struct req
*);
70 static void pg_searchres(const struct req
*,
71 struct manpage
*, size_t);
72 static void pg_show(struct req
*, const char *);
73 static void resp_begin_html(int, const char *);
74 static void resp_begin_http(int, const char *);
75 static void resp_end_html(void);
76 static void resp_searchform(const struct req
*);
77 static void resp_show(const struct req
*, const char *);
78 static void set_query_attr(char **, char **);
79 static int validate_filename(const char *);
80 static int validate_manpath(const struct req
*, const char *);
81 static int validate_urifrag(const char *);
83 static const char *scriptname
; /* CGI script name */
85 static const int sec_prios
[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
86 static const char *const sec_numbers
[] = {
87 "0", "1", "2", "3", "3p", "4", "5", "6", "7", "8", "9"
89 static const char *const sec_names
[] = {
91 "1 - General Commands",
94 "3p - Perl Subroutines",
98 "7 - Macros and Conventions",
99 "8 - Maintenance Commands",
100 "9 - Kernel Interface"
102 static const int sec_MAX
= sizeof(sec_names
) / sizeof(char *);
104 static const char *const arch_names
[] = {
105 "amd64", "alpha", "armish", "armv7",
106 "aviion", "hppa", "hppa64", "i386",
107 "ia64", "landisk", "loongson", "luna88k",
108 "macppc", "mips64", "octeon", "sgi",
109 "socppc", "solbourne", "sparc", "sparc64",
111 "amiga", "arc", "arm32", "atari",
112 "beagle", "cats", "hp300", "mac68k",
113 "mvme68k", "mvme88k", "mvmeppc", "palm",
114 "pc532", "pegasos", "pmax", "powerpc",
115 "sun3", "wgrisc", "x68k"
117 static const int arch_MAX
= sizeof(arch_names
) / sizeof(char *);
120 * Print a character, escaping HTML along the way.
121 * This will pass non-ASCII straight to output: be warned!
141 putchar((unsigned char)c
);
147 http_printquery(const struct req
*req
, const char *sep
)
150 if (NULL
!= req
->q
.query
) {
152 http_print(req
->q
.query
);
154 if (0 == req
->q
.equal
)
155 printf("%sapropos=1", sep
);
156 if (NULL
!= req
->q
.sec
) {
157 printf("%ssec=", sep
);
158 http_print(req
->q
.sec
);
160 if (NULL
!= req
->q
.arch
) {
161 printf("%sarch=", sep
);
162 http_print(req
->q
.arch
);
164 if (NULL
!= req
->q
.manpath
&&
165 strcmp(req
->q
.manpath
, req
->p
[0])) {
166 printf("%smanpath=", sep
);
167 http_print(req
->q
.manpath
);
172 http_print(const char *p
)
182 * Call through to html_putchar().
183 * Accepts NULL strings.
186 html_print(const char *p
)
196 * Transfer the responsibility for the allocated string *val
197 * to the query structure.
200 set_query_attr(char **attr
, char **val
)
213 * Parse the QUERY_STRING for key-value pairs
214 * and store the values into the query structure.
217 http_parse(struct req
*req
, const char *qs
)
222 req
->q
.manpath
= NULL
;
229 while (*qs
!= '\0') {
233 keysz
= strcspn(qs
, "=;&");
234 key
= mandoc_strndup(qs
, keysz
);
239 /* Parse one value. */
241 valsz
= strcspn(++qs
, ";&");
242 val
= mandoc_strndup(qs
, valsz
);
245 /* Decode and catch encoding errors. */
247 if ( ! (http_decode(key
) && http_decode(val
)))
250 /* Handle key-value pairs. */
252 if ( ! strcmp(key
, "query"))
253 set_query_attr(&req
->q
.query
, &val
);
255 else if ( ! strcmp(key
, "apropos"))
256 req
->q
.equal
= !strcmp(val
, "0");
258 else if ( ! strcmp(key
, "manpath")) {
260 if ( ! strncmp(val
, "OpenBSD ", 8)) {
266 set_query_attr(&req
->q
.manpath
, &val
);
269 else if ( ! (strcmp(key
, "sec")
271 && strcmp(key
, "sektion")
274 if ( ! strcmp(val
, "0"))
276 set_query_attr(&req
->q
.sec
, &val
);
279 else if ( ! strcmp(key
, "arch")) {
280 if ( ! strcmp(val
, "default"))
282 set_query_attr(&req
->q
.arch
, &val
);
286 * The key must be freed in any case.
287 * The val may have been handed over to the query
288 * structure, in which case it is now NULL.
300 /* Fall back to the default manpath. */
302 if (req
->q
.manpath
== NULL
)
303 req
->q
.manpath
= mandoc_strdup(req
->p
[0]);
310 if (isalnum((unsigned char)c
)) {
311 putchar((unsigned char)c
);
313 } else if (' ' == c
) {
321 * HTTP-decode a string. The standard explanation is that this turns
322 * "%4e+foo" into "n foo" in the regular way. This is done in-place
323 * over the allocated string.
335 for ( ; '\0' != *p
; p
++, q
++) {
337 if ('\0' == (hex
[0] = *(p
+ 1)))
339 if ('\0' == (hex
[1] = *(p
+ 2)))
341 if (1 != sscanf(hex
, "%x", &c
))
349 *q
= '+' == *p
? ' ' : *p
;
357 resp_begin_http(int code
, const char *msg
)
361 printf("Status: %d %s\r\n", code
, msg
);
363 printf("Content-Type: text/html; charset=utf-8\r\n"
364 "Cache-Control: no-cache\r\n"
365 "Pragma: no-cache\r\n"
372 resp_begin_html(int code
, const char *msg
)
375 resp_begin_http(code
, msg
);
377 printf("<!DOCTYPE HTML PUBLIC "
378 " \"-//W3C//DTD HTML 4.01//EN\""
379 " \"http://www.w3.org/TR/html4/strict.dtd\">\n"
382 "<META HTTP-EQUIV=\"Content-Type\""
383 " CONTENT=\"text/html; charset=utf-8\">\n"
384 "<LINK REL=\"stylesheet\" HREF=\"%s/man-cgi.css\""
385 " TYPE=\"text/css\" media=\"all\">\n"
386 "<LINK REL=\"stylesheet\" HREF=\"%s/man.css\""
387 " TYPE=\"text/css\" media=\"all\">\n"
388 "<TITLE>%s</TITLE>\n"
391 "<!-- Begin page content. //-->\n",
392 CSS_DIR
, CSS_DIR
, CUSTOMIZE_TITLE
);
404 resp_searchform(const struct req
*req
)
408 puts(CUSTOMIZE_BEGIN
);
409 puts("<!-- Begin search form. //-->");
410 printf("<DIV ID=\"mancgi\">\n"
411 "<FORM ACTION=\"%s\" METHOD=\"get\">\n"
413 "<LEGEND>Manual Page Search Parameters</LEGEND>\n",
416 /* Write query input box. */
418 printf( "<TABLE><TR><TD>\n"
419 "<INPUT TYPE=\"text\" NAME=\"query\" VALUE=\"");
420 if (NULL
!= req
->q
.query
)
421 html_print(req
->q
.query
);
422 puts("\" SIZE=\"40\">");
424 /* Write submission and reset buttons. */
426 printf( "<INPUT TYPE=\"submit\" VALUE=\"Submit\">\n"
427 "<INPUT TYPE=\"reset\" VALUE=\"Reset\">\n");
429 /* Write show radio button */
431 printf( "</TD><TD>\n"
432 "<INPUT TYPE=\"radio\" ");
434 printf("CHECKED=\"checked\" ");
435 printf( "NAME=\"apropos\" ID=\"show\" VALUE=\"0\">\n"
436 "<LABEL FOR=\"show\">Show named manual page</LABEL>\n");
438 /* Write section selector. */
440 puts( "</TD></TR><TR><TD>\n"
441 "<SELECT NAME=\"sec\">");
442 for (i
= 0; i
< sec_MAX
; i
++) {
443 printf("<OPTION VALUE=\"%s\"", sec_numbers
[i
]);
444 if (NULL
!= req
->q
.sec
&&
445 0 == strcmp(sec_numbers
[i
], req
->q
.sec
))
446 printf(" SELECTED=\"selected\"");
447 printf(">%s</OPTION>\n", sec_names
[i
]);
451 /* Write architecture selector. */
453 printf( "<SELECT NAME=\"arch\">\n"
454 "<OPTION VALUE=\"default\"");
455 if (NULL
== req
->q
.arch
)
456 printf(" SELECTED=\"selected\"");
457 puts(">All Architectures</OPTION>");
458 for (i
= 0; i
< arch_MAX
; i
++) {
459 printf("<OPTION VALUE=\"%s\"", arch_names
[i
]);
460 if (NULL
!= req
->q
.arch
&&
461 0 == strcmp(arch_names
[i
], req
->q
.arch
))
462 printf(" SELECTED=\"selected\"");
463 printf(">%s</OPTION>\n", arch_names
[i
]);
467 /* Write manpath selector. */
470 puts("<SELECT NAME=\"manpath\">");
471 for (i
= 0; i
< (int)req
->psz
; i
++) {
473 if (NULL
== req
->q
.manpath
? 0 == i
:
474 0 == strcmp(req
->q
.manpath
, req
->p
[i
]))
475 printf("SELECTED=\"selected\" ");
477 html_print(req
->p
[i
]);
479 html_print(req
->p
[i
]);
485 /* Write search radio button */
487 printf( "</TD><TD>\n"
488 "<INPUT TYPE=\"radio\" ");
489 if (0 == req
->q
.equal
)
490 printf("CHECKED=\"checked\" ");
491 printf( "NAME=\"apropos\" ID=\"search\" VALUE=\"1\">\n"
492 "<LABEL FOR=\"search\">Search with apropos query</LABEL>\n");
494 puts("</TD></TR></TABLE>\n"
498 puts("<!-- End search form. //-->");
502 validate_urifrag(const char *frag
)
505 while ('\0' != *frag
) {
506 if ( ! (isalnum((unsigned char)*frag
) ||
507 '-' == *frag
|| '.' == *frag
||
508 '/' == *frag
|| '_' == *frag
))
516 validate_manpath(const struct req
*req
, const char* manpath
)
520 if ( ! strcmp(manpath
, "mandoc"))
523 for (i
= 0; i
< req
->psz
; i
++)
524 if ( ! strcmp(manpath
, req
->p
[i
]))
531 validate_filename(const char *file
)
534 if ('.' == file
[0] && '/' == file
[1])
537 return ( ! (strstr(file
, "../") || strstr(file
, "/..") ||
538 (strncmp(file
, "man", 3) && strncmp(file
, "cat", 3))));
542 pg_index(const struct req
*req
)
545 resp_begin_html(200, NULL
);
546 resp_searchform(req
);
548 "This web interface is documented in the\n"
549 "<A HREF=\"%s/mandoc/man8/man.cgi.8\">man.cgi</A>\n"
551 "<A HREF=\"%s/mandoc/man1/apropos.1\">apropos</A>\n"
552 "manual explains the query syntax.\n"
554 scriptname
, scriptname
);
559 pg_noresult(const struct req
*req
, const char *msg
)
561 resp_begin_html(200, NULL
);
562 resp_searchform(req
);
570 pg_error_badrequest(const char *msg
)
573 resp_begin_html(400, "Bad Request");
574 puts("<H1>Bad Request</H1>\n"
577 printf("Try again from the\n"
578 "<A HREF=\"%s\">main page</A>.\n"
584 pg_error_internal(void)
586 resp_begin_html(500, "Internal Server Error");
587 puts("<P>Internal Server Error</P>");
592 pg_searchres(const struct req
*req
, struct manpage
*r
, size_t sz
)
594 char *arch
, *archend
;
595 size_t i
, iuse
, isec
;
596 int archprio
, archpriouse
;
600 for (i
= 0; i
< sz
; i
++) {
601 if (validate_filename(r
[i
].file
))
603 fprintf(stderr
, "invalid filename %s in %s database\n",
604 r
[i
].file
, req
->q
.manpath
);
611 * If we have just one result, then jump there now
614 printf("Status: 303 See Other\r\n");
615 printf("Location: http://%s%s/%s/%s?",
616 HTTP_HOST
, scriptname
, req
->q
.manpath
, r
[0].file
);
617 http_printquery(req
, "&");
619 "Content-Type: text/html; charset=utf-8\r\n"
624 resp_begin_html(200, NULL
);
625 resp_searchform(req
);
626 puts("<DIV CLASS=\"results\">");
629 for (i
= 0; i
< sz
; i
++) {
631 "<TD CLASS=\"title\">\n"
632 "<A HREF=\"%s/%s/%s?",
633 scriptname
, req
->q
.manpath
, r
[i
].file
);
634 http_printquery(req
, "&");
636 html_print(r
[i
].names
);
639 "<TD CLASS=\"desc\">");
640 html_print(r
[i
].output
);
649 * In man(1) mode, show one of the pages
650 * even if more than one is found.
658 for (i
= 0; i
< sz
; i
++) {
659 isec
= strcspn(r
[i
].file
, "123456789");
660 sec
= r
[i
].file
[isec
];
663 prio
= sec_prios
[sec
- '1'];
664 if (NULL
== req
->q
.arch
) {
666 (NULL
== (arch
= strchr(
667 r
[i
].file
+ isec
, '/'))) ? 3 :
668 (NULL
== (archend
= strchr(
669 arch
+ 1, '/'))) ? 0 :
670 strncmp(arch
, "amd64/",
671 archend
- arch
) ? 2 : 1;
672 if (archprio
< archpriouse
) {
673 archpriouse
= archprio
;
678 if (archprio
> archpriouse
)
686 resp_show(req
, r
[iuse
].file
);
693 catman(const struct req
*req
, const char *file
)
701 if (NULL
== (f
= fopen(file
, "r"))) {
702 puts("<P>You specified an invalid manual file.</P>");
706 puts("<DIV CLASS=\"catman\">\n"
709 while (NULL
!= (p
= fgetln(f
, &len
))) {
711 for (i
= 0; i
< (int)len
- 1; i
++) {
713 * This means that the catpage is out of state.
714 * Ignore it and keep going (although the
718 if ('\b' == p
[i
] || '\n' == p
[i
])
722 * Print a regular character.
723 * Close out any bold/italic scopes.
724 * If we're in back-space mode, make sure we'll
725 * have something to enter when we backspace.
728 if ('\b' != p
[i
+ 1]) {
736 } else if (i
+ 2 >= (int)len
)
754 * Handle funny behaviour troff-isms.
755 * These grok'd from the original man2html.c.
758 if (('+' == p
[i
] && 'o' == p
[i
+ 2]) ||
759 ('o' == p
[i
] && '+' == p
[i
+ 2]) ||
760 ('|' == p
[i
] && '=' == p
[i
+ 2]) ||
761 ('=' == p
[i
] && '|' == p
[i
+ 2]) ||
762 ('*' == p
[i
] && '=' == p
[i
+ 2]) ||
763 ('=' == p
[i
] && '*' == p
[i
+ 2]) ||
764 ('*' == p
[i
] && '|' == p
[i
+ 2]) ||
765 ('|' == p
[i
] && '*' == p
[i
+ 2])) {
774 } else if (('|' == p
[i
] && '-' == p
[i
+ 2]) ||
775 ('-' == p
[i
] && '|' == p
[i
+ 1]) ||
776 ('+' == p
[i
] && '-' == p
[i
+ 1]) ||
777 ('-' == p
[i
] && '+' == p
[i
+ 1]) ||
778 ('+' == p
[i
] && '|' == p
[i
+ 1]) ||
779 ('|' == p
[i
] && '+' == p
[i
+ 1])) {
803 * Clean up the last character.
804 * We can get to a newline; don't print that.
812 if (i
== (int)len
- 1 && '\n' != p
[i
])
825 format(const struct req
*req
, const char *file
)
836 if (-1 == (fd
= open(file
, O_RDONLY
, 0))) {
837 puts("<P>You specified an invalid manual file.</P>");
841 mp
= mparse_alloc(MPARSE_SO
, MANDOCLEVEL_FATAL
, NULL
,
843 rc
= mparse_readfd(mp
, fd
, file
);
846 if (rc
>= MANDOCLEVEL_FATAL
) {
847 fprintf(stderr
, "fatal mandoc error: %s/%s\n",
848 req
->q
.manpath
, file
);
853 usepath
= strcmp(req
->q
.manpath
, req
->p
[0]);
854 mandoc_asprintf(&opts
,
855 "fragment,man=%s?query=%%N&sec=%%S%s%s%s%s",
857 req
->q
.arch
? "&arch=" : "",
858 req
->q
.arch
? req
->q
.arch
: "",
859 usepath
? "&manpath=" : "",
860 usepath
? req
->q
.manpath
: "");
862 mparse_result(mp
, &mdoc
, &man
, NULL
);
863 if (NULL
== man
&& NULL
== mdoc
) {
864 fprintf(stderr
, "fatal mandoc error: %s/%s\n",
865 req
->q
.manpath
, file
);
871 vp
= html_alloc(opts
);
884 resp_show(const struct req
*req
, const char *file
)
887 if ('.' == file
[0] && '/' == file
[1])
897 pg_show(struct req
*req
, const char *fullpath
)
902 if ((file
= strchr(fullpath
, '/')) == NULL
) {
904 "You did not specify a page to show.");
907 manpath
= mandoc_strndup(fullpath
, file
- fullpath
);
910 if ( ! validate_manpath(req
, manpath
)) {
912 "You specified an invalid manpath.");
918 * Begin by chdir()ing into the manpath.
919 * This way we can pick up the database files, which are
920 * relative to the manpath root.
923 if (chdir(manpath
) == -1) {
924 fprintf(stderr
, "chdir %s: %s\n",
925 manpath
, strerror(errno
));
931 if (strcmp(manpath
, "mandoc")) {
932 free(req
->q
.manpath
);
933 req
->q
.manpath
= manpath
;
937 if ( ! validate_filename(file
)) {
939 "You specified an invalid manual file.");
943 resp_begin_html(200, NULL
);
944 resp_searchform(req
);
945 resp_show(req
, file
);
950 pg_search(const struct req
*req
)
952 struct mansearch search
;
953 struct manpaths paths
;
956 const char *ep
, *start
;
961 * Begin by chdir()ing into the root of the manpath.
962 * This way we can pick up the database files, which are
963 * relative to the manpath root.
966 if (-1 == (chdir(req
->q
.manpath
))) {
967 fprintf(stderr
, "chdir %s: %s\n",
968 req
->q
.manpath
, strerror(errno
));
973 search
.arch
= req
->q
.arch
;
974 search
.sec
= req
->q
.sec
;
975 search
.deftype
= req
->q
.equal
? TYPE_Nm
: (TYPE_Nm
| TYPE_Nd
);
976 search
.flags
= req
->q
.equal
? MANSEARCH_MAN
: 0;
979 paths
.paths
= mandoc_malloc(sizeof(char *));
980 paths
.paths
[0] = mandoc_strdup(".");
983 * Poor man's tokenisation: just break apart by spaces.
984 * Yes, this is half-ass. But it works for now.
988 while (ep
&& isspace((unsigned char)*ep
))
993 while (ep
&& '\0' != *ep
) {
994 cp
= mandoc_reallocarray(cp
, sz
+ 1, sizeof(char *));
996 while ('\0' != *ep
&& ! isspace((unsigned char)*ep
))
998 cp
[sz
] = mandoc_malloc((ep
- start
) + 1);
999 memcpy(cp
[sz
], start
, ep
- start
);
1000 cp
[sz
++][ep
- start
] = '\0';
1001 while (isspace((unsigned char)*ep
))
1005 if (0 == mansearch(&search
, &paths
, sz
, cp
, "Nd", &res
, &ressz
))
1006 pg_noresult(req
, "You entered an invalid query.");
1007 else if (0 == ressz
)
1008 pg_noresult(req
, "No results found.");
1010 pg_searchres(req
, res
, ressz
);
1012 for (i
= 0; i
< sz
; i
++)
1016 for (i
= 0; i
< (int)ressz
; i
++) {
1019 free(res
[i
].output
);
1023 free(paths
.paths
[0]);
1032 const char *querystring
;
1035 /* Scan our run-time environment. */
1037 if (NULL
== (scriptname
= getenv("SCRIPT_NAME")))
1040 if ( ! validate_urifrag(scriptname
)) {
1041 fprintf(stderr
, "unsafe SCRIPT_NAME \"%s\"\n",
1043 pg_error_internal();
1044 return(EXIT_FAILURE
);
1048 * First we change directory into the MAN_DIR so that
1049 * subsequent scanning for manpath directories is rooted
1050 * relative to the same position.
1053 if (-1 == chdir(MAN_DIR
)) {
1054 fprintf(stderr
, "MAN_DIR: %s: %s\n",
1055 MAN_DIR
, strerror(errno
));
1056 pg_error_internal();
1057 return(EXIT_FAILURE
);
1060 memset(&req
, 0, sizeof(struct req
));
1063 /* Next parse out the query string. */
1065 if (NULL
!= (querystring
= getenv("QUERY_STRING")))
1066 http_parse(&req
, querystring
);
1068 if ( ! (NULL
== req
.q
.manpath
||
1069 validate_manpath(&req
, req
.q
.manpath
))) {
1070 pg_error_badrequest(
1071 "You specified an invalid manpath.");
1072 return(EXIT_FAILURE
);
1075 if ( ! (NULL
== req
.q
.arch
|| validate_urifrag(req
.q
.arch
))) {
1076 pg_error_badrequest(
1077 "You specified an invalid architecture.");
1078 return(EXIT_FAILURE
);
1081 /* Dispatch to the three different pages. */
1083 path
= getenv("PATH_INFO");
1086 else if ('/' == *path
)
1090 pg_show(&req
, path
);
1091 else if (NULL
!= req
.q
.query
)
1096 free(req
.q
.manpath
);
1100 for (i
= 0; i
< (int)req
.psz
; i
++)
1103 return(EXIT_SUCCESS
);
1107 * Scan for indexable paths.
1110 pathgen(struct req
*req
)
1116 if (NULL
== (fp
= fopen("manpath.conf", "r"))) {
1117 fprintf(stderr
, "%s/manpath.conf: %s\n",
1118 MAN_DIR
, strerror(errno
));
1119 pg_error_internal();
1123 while (NULL
!= (dp
= fgetln(fp
, &dpsz
))) {
1124 if ('\n' == dp
[dpsz
- 1])
1126 req
->p
= mandoc_realloc(req
->p
,
1127 (req
->psz
+ 1) * sizeof(char *));
1128 dp
= mandoc_strndup(dp
, dpsz
);
1129 if ( ! validate_urifrag(dp
)) {
1130 fprintf(stderr
, "%s/manpath.conf contains "
1131 "unsafe path \"%s\"\n", MAN_DIR
, dp
);
1132 pg_error_internal();
1135 if (NULL
!= strchr(dp
, '/')) {
1136 fprintf(stderr
, "%s/manpath.conf contains "
1137 "path with slash \"%s\"\n", MAN_DIR
, dp
);
1138 pg_error_internal();
1141 req
->p
[req
->psz
++] = dp
;
1144 if ( req
->p
== NULL
) {
1145 fprintf(stderr
, "%s/manpath.conf is empty\n", MAN_DIR
);
1146 pg_error_internal();