Print this page
9718 update mandoc to 1.14.4
   1 /*      $Id: main.c,v 1.301 2017/07/26 10:21:55 schwarze Exp $ */
   2 /*
   3  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
   4  * Copyright (c) 2010-2012, 2014-2017 Ingo Schwarze <schwarze@openbsd.org>
   5  * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
   6  *
   7  * Permission to use, copy, modify, and distribute this software for any
   8  * purpose with or without fee is hereby granted, provided that the above
   9  * copyright notice and this permission notice appear in all copies.
  10  *
  11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
  12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
  14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  18  */
  19 #include "config.h"
  20 
  21 #include <sys/types.h>

  22 #include <sys/param.h>    /* MACHINE */

  23 #include <sys/wait.h>
  24 
  25 #include <assert.h>
  26 #include <ctype.h>
  27 #if HAVE_ERR
  28 #include <err.h>
  29 #endif
  30 #include <errno.h>
  31 #include <fcntl.h>
  32 #include <glob.h>
  33 #if HAVE_SANDBOX_INIT
  34 #include <sandbox.h>
  35 #endif
  36 #include <signal.h>
  37 #include <stdio.h>
  38 #include <stdint.h>
  39 #include <stdlib.h>
  40 #include <string.h>
  41 #include <time.h>
  42 #include <unistd.h>


 103 static  void              parse(struct curparse *, int, const char *);
 104 static  void              passthrough(const char *, int, int);
 105 static  pid_t             spawn_pager(struct tag_files *);
 106 static  int               toptions(struct curparse *, char *);
 107 static  void              usage(enum argmode) __attribute__((__noreturn__));
 108 static  int               woptions(struct curparse *, char *);
 109 
 110 static  const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
 111 static  char              help_arg[] = "help";
 112 static  char             *help_argv[] = {help_arg, NULL};
 113 static  enum mandoclevel  rc;
 114 static  FILE             *mmsg_stream;
 115 
 116 
 117 int
 118 main(int argc, char *argv[])
 119 {
 120         struct manconf   conf;
 121         struct mansearch search;
 122         struct curparse  curp;

 123         struct tag_files *tag_files;
 124         struct manpage  *res, *resp;
 125         const char      *progname, *sec, *thisarg;
 126         char            *conf_file, *defpaths, *auxpaths;
 127         char            *oarg;
 128         unsigned char   *uc;
 129         size_t           i, sz;
 130         int              prio, best_prio;
 131         enum outmode     outmode;
 132         int              fd;
 133         int              show_usage;
 134         int              options;
 135         int              use_pager;
 136         int              status, signum;
 137         int              c;
 138         pid_t            pager_pid, tc_pgid, man_pgid, pid;
 139 
 140 #if HAVE_PROGNAME
 141         progname = getprogname();
 142 #else
 143         if (argc < 1)
 144                 progname = mandoc_strdup("mandoc");
 145         else if ((progname = strrchr(argv[0], '/')) == NULL)
 146                 progname = argv[0];
 147         else
 148                 ++progname;
 149         setprogname(progname);
 150 #endif
 151 
 152         if (strncmp(progname, "mandocdb", 8) == 0 ||


 299         if (oarg != NULL) {
 300                 if (outmode == OUTMODE_LST)
 301                         search.outkey = oarg;
 302                 else {
 303                         while (oarg != NULL) {
 304                                 thisarg = oarg;
 305                                 if (manconf_output(&conf.output,
 306                                     strsep(&oarg, ","), 0) == 0)
 307                                         continue;
 308                                 warnx("-O %s: Bad argument", thisarg);
 309                                 return (int)MANDOCLEVEL_BADARG;
 310                         }
 311                 }
 312         }
 313 
 314         if (outmode == OUTMODE_FLN ||
 315             outmode == OUTMODE_LST ||
 316             !isatty(STDOUT_FILENO))
 317                 use_pager = 0;
 318 










 319 #if HAVE_PLEDGE
 320         if (!use_pager)
 321                 if (pledge("stdio rpath", NULL) == -1)
 322                         err((int)MANDOCLEVEL_SYSERR, "pledge");
 323 #endif
 324 
 325         /* Parse arguments. */
 326 
 327         if (argc > 0) {
 328                 argc -= optind;
 329                 argv += optind;
 330         }
 331         resp = NULL;
 332 
 333         /*
 334          * Quirks for help(1)
 335          * and for a man(1) section argument without -s.
 336          */
 337 
 338         if (search.argmode == ARG_NAME) {


 357                         search.arch = MACHINE;
 358 #endif
 359         }
 360 
 361         rc = MANDOCLEVEL_OK;
 362 
 363         /* man(1), whatis(1), apropos(1) */
 364 
 365         if (search.argmode != ARG_FILE) {
 366                 if (search.argmode == ARG_NAME &&
 367                     outmode == OUTMODE_ONE)
 368                         search.firstmatch = 1;
 369 
 370                 /* Access the mandoc database. */
 371 
 372                 manconf_parse(&conf, conf_file, defpaths, auxpaths);
 373                 if ( ! mansearch(&search, &conf.manpath,
 374                     argc, argv, &res, &sz))
 375                         usage(search.argmode);
 376 
 377                 if (sz == 0) {
 378                         if (search.argmode == ARG_NAME)
 379                                 fs_search(&search, &conf.manpath,
 380                                     argc, argv, &res, &sz);
 381                         else
 382                                 warnx("nothing appropriate");






 383                 }












 384 
 385                 if (sz == 0) {


 386                         rc = MANDOCLEVEL_BADARG;
 387                         goto out;
 388                 }
 389 
 390                 /*
 391                  * For standard man(1) and -a output mode,
 392                  * prepare for copying filename pointers
 393                  * into the program parameter array.
 394                  */
 395 
 396                 if (outmode == OUTMODE_ONE) {
 397                         argc = 1;
 398                         best_prio = 20;
 399                 } else if (outmode == OUTMODE_ALL)
 400                         argc = (int)sz;
 401 
 402                 /* Iterate all matching manuals. */
 403 
 404                 resp = res;
 405                 for (i = 0; i < sz; i++) {


 449 
 450         if (search.argmode == ARG_FILE)
 451                 moptions(&options, auxpaths);
 452 
 453         mchars_alloc();
 454         curp.mp = mparse_alloc(options, curp.mmin, mmsg,
 455             curp.os_e, curp.os_s);
 456 
 457         /*
 458          * Conditionally start up the lookaside buffer before parsing.
 459          */
 460         if (OUTT_MAN == curp.outtype)
 461                 mparse_keep(curp.mp);
 462 
 463         if (argc < 1) {
 464                 if (use_pager)
 465                         tag_files = tag_init();
 466                 parse(&curp, STDIN_FILENO, "<stdin>");
 467         }
 468 









 469         while (argc > 0) {













 470                 fd = mparse_open(curp.mp, resp != NULL ? resp->file : *argv);
 471                 if (fd != -1) {
 472                         if (use_pager) {
 473                                 tag_files = tag_init();
 474                                 use_pager = 0;
 475                         }
 476 
 477                         if (resp == NULL)
 478                                 parse(&curp, fd, *argv);
 479                         else if (resp->form == FORM_SRC) {
 480                                 /* For .so only; ignore failure. */
 481                                 (void)chdir(conf.manpath.paths[resp->ipath]);
 482                                 parse(&curp, fd, resp->file);
 483                         } else
 484                                 passthrough(resp->file, fd,
 485                                     conf.output.synopsisonly);
 486 











 487                         if (argc > 1 && curp.outtype <= OUTT_UTF8) {
 488                                 if (curp.outdata == NULL)
 489                                         outdata_alloc(&curp);
 490                                 terminal_sepline(curp.outdata);
 491                         }
 492                 } else if (rc < MANDOCLEVEL_ERROR)
 493                         rc = MANDOCLEVEL_ERROR;
 494 
 495                 if (MANDOCLEVEL_OK != rc && curp.wstop)
 496                         break;
 497 
 498                 if (resp != NULL)
 499                         resp++;
 500                 else
 501                         argv++;
 502                 if (--argc)
 503                         mparse_reset(curp.mp);
 504         }




 505 
 506         if (curp.outdata != NULL) {
 507                 switch (curp.outtype) {
 508                 case OUTT_HTML:
 509                         html_free(curp.outdata);
 510                         break;
 511                 case OUTT_UTF8:
 512                 case OUTT_LOCALE:
 513                 case OUTT_ASCII:
 514                         ascii_free(curp.outdata);
 515                         break;
 516                 case OUTT_PDF:
 517                 case OUTT_PS:
 518                         pspdf_free(curp.outdata);
 519                         break;
 520                 default:
 521                         break;
 522                 }
 523         }
 524         mandoc_xr_free();


 705         size_t           ipath, isec, lastsz;
 706 
 707         assert(cfg->argmode == ARG_NAME);
 708 
 709         if (res != NULL)
 710                 *res = NULL;
 711         *ressz = lastsz = 0;
 712         while (argc) {
 713                 for (ipath = 0; ipath < paths->sz; ipath++) {
 714                         if (cfg->sec != NULL) {
 715                                 if (fs_lookup(paths, ipath, cfg->sec,
 716                                     cfg->arch, *argv, res, ressz) &&
 717                                     cfg->firstmatch)
 718                                         return 1;
 719                         } else for (isec = 0; isec < nsec; isec++)
 720                                 if (fs_lookup(paths, ipath, sections[isec],
 721                                     cfg->arch, *argv, res, ressz) &&
 722                                     cfg->firstmatch)
 723                                         return 1;
 724                 }
 725                 if (res != NULL && *ressz == lastsz)

 726                         warnx("No entry for %s in the manual.", *argv);
 727                 lastsz = *ressz;
 728                 argv++;
 729                 argc--;
 730         }
 731         return 0;
 732 }
 733 
 734 static void
 735 parse(struct curparse *curp, int fd, const char *file)
 736 {
 737         enum mandoclevel  rctmp;
 738         struct roff_man  *man;
 739 
 740         /* Begin by parsing the file itself. */
 741 
 742         assert(file);
 743         assert(fd >= 0);
 744 
 745         rctmp = mparse_readfd(curp->mp, fd, file);


1156         case -1:
1157                 err((int)MANDOCLEVEL_SYSERR, "fork");
1158         case 0:
1159                 break;
1160         default:
1161                 (void)setpgid(pager_pid, 0);
1162                 (void)tcsetpgrp(tag_files->ofd, pager_pid);
1163 #if HAVE_PLEDGE
1164                 if (pledge("stdio rpath tmppath tty proc", NULL) == -1)
1165                         err((int)MANDOCLEVEL_SYSERR, "pledge");
1166 #endif
1167                 tag_files->pager_pid = pager_pid;
1168                 return pager_pid;
1169         }
1170 
1171         /* The child process becomes the pager. */
1172 
1173         if (dup2(tag_files->ofd, STDOUT_FILENO) == -1)
1174                 err((int)MANDOCLEVEL_SYSERR, "pager stdout");
1175         close(tag_files->ofd);
1176         close(tag_files->tfd);
1177 
1178         /* Do not start the pager before controlling the terminal. */
1179 
1180         while (tcgetpgrp(STDOUT_FILENO) != getpid())
1181                 nanosleep(&timeout, NULL);
1182 
1183         execvp(argv[0], argv);
1184         err((int)MANDOCLEVEL_SYSERR, "exec %s", argv[0]);
1185 }
   1 /*      $Id: main.c,v 1.306 2018/05/14 14:10:23 schwarze Exp $ */
   2 /*
   3  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
   4  * Copyright (c) 2010-2012, 2014-2018 Ingo Schwarze <schwarze@openbsd.org>
   5  * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
   6  *
   7  * Permission to use, copy, modify, and distribute this software for any
   8  * purpose with or without fee is hereby granted, provided that the above
   9  * copyright notice and this permission notice appear in all copies.
  10  *
  11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
  12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
  14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  18  */
  19 #include "config.h"
  20 
  21 #include <sys/types.h>
  22 #include <sys/ioctl.h>
  23 #include <sys/param.h>    /* MACHINE */
  24 #include <sys/termios.h>
  25 #include <sys/wait.h>
  26 
  27 #include <assert.h>
  28 #include <ctype.h>
  29 #if HAVE_ERR
  30 #include <err.h>
  31 #endif
  32 #include <errno.h>
  33 #include <fcntl.h>
  34 #include <glob.h>
  35 #if HAVE_SANDBOX_INIT
  36 #include <sandbox.h>
  37 #endif
  38 #include <signal.h>
  39 #include <stdio.h>
  40 #include <stdint.h>
  41 #include <stdlib.h>
  42 #include <string.h>
  43 #include <time.h>
  44 #include <unistd.h>


 105 static  void              parse(struct curparse *, int, const char *);
 106 static  void              passthrough(const char *, int, int);
 107 static  pid_t             spawn_pager(struct tag_files *);
 108 static  int               toptions(struct curparse *, char *);
 109 static  void              usage(enum argmode) __attribute__((__noreturn__));
 110 static  int               woptions(struct curparse *, char *);
 111 
 112 static  const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
 113 static  char              help_arg[] = "help";
 114 static  char             *help_argv[] = {help_arg, NULL};
 115 static  enum mandoclevel  rc;
 116 static  FILE             *mmsg_stream;
 117 
 118 
 119 int
 120 main(int argc, char *argv[])
 121 {
 122         struct manconf   conf;
 123         struct mansearch search;
 124         struct curparse  curp;
 125         struct winsize   ws;
 126         struct tag_files *tag_files;
 127         struct manpage  *res, *resp;
 128         const char      *progname, *sec, *thisarg;
 129         char            *conf_file, *defpaths, *auxpaths;
 130         char            *oarg;
 131         unsigned char   *uc;
 132         size_t           i, sz;
 133         int              prio, best_prio;
 134         enum outmode     outmode;
 135         int              fd, startdir;
 136         int              show_usage;
 137         int              options;
 138         int              use_pager;
 139         int              status, signum;
 140         int              c;
 141         pid_t            pager_pid, tc_pgid, man_pgid, pid;
 142 
 143 #if HAVE_PROGNAME
 144         progname = getprogname();
 145 #else
 146         if (argc < 1)
 147                 progname = mandoc_strdup("mandoc");
 148         else if ((progname = strrchr(argv[0], '/')) == NULL)
 149                 progname = argv[0];
 150         else
 151                 ++progname;
 152         setprogname(progname);
 153 #endif
 154 
 155         if (strncmp(progname, "mandocdb", 8) == 0 ||


 302         if (oarg != NULL) {
 303                 if (outmode == OUTMODE_LST)
 304                         search.outkey = oarg;
 305                 else {
 306                         while (oarg != NULL) {
 307                                 thisarg = oarg;
 308                                 if (manconf_output(&conf.output,
 309                                     strsep(&oarg, ","), 0) == 0)
 310                                         continue;
 311                                 warnx("-O %s: Bad argument", thisarg);
 312                                 return (int)MANDOCLEVEL_BADARG;
 313                         }
 314                 }
 315         }
 316 
 317         if (outmode == OUTMODE_FLN ||
 318             outmode == OUTMODE_LST ||
 319             !isatty(STDOUT_FILENO))
 320                 use_pager = 0;
 321 
 322         if (use_pager &&
 323             (conf.output.width == 0 || conf.output.indent == 0) &&
 324             ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 &&
 325             ws.ws_col > 1) {
 326                 if (conf.output.width == 0 && ws.ws_col < 79)
 327                         conf.output.width = ws.ws_col - 1;
 328                 if (conf.output.indent == 0 && ws.ws_col < 66)
 329                         conf.output.indent = 3;
 330         }
 331 
 332 #if HAVE_PLEDGE
 333         if (!use_pager)
 334                 if (pledge("stdio rpath", NULL) == -1)
 335                         err((int)MANDOCLEVEL_SYSERR, "pledge");
 336 #endif
 337 
 338         /* Parse arguments. */
 339 
 340         if (argc > 0) {
 341                 argc -= optind;
 342                 argv += optind;
 343         }
 344         resp = NULL;
 345 
 346         /*
 347          * Quirks for help(1)
 348          * and for a man(1) section argument without -s.
 349          */
 350 
 351         if (search.argmode == ARG_NAME) {


 370                         search.arch = MACHINE;
 371 #endif
 372         }
 373 
 374         rc = MANDOCLEVEL_OK;
 375 
 376         /* man(1), whatis(1), apropos(1) */
 377 
 378         if (search.argmode != ARG_FILE) {
 379                 if (search.argmode == ARG_NAME &&
 380                     outmode == OUTMODE_ONE)
 381                         search.firstmatch = 1;
 382 
 383                 /* Access the mandoc database. */
 384 
 385                 manconf_parse(&conf, conf_file, defpaths, auxpaths);
 386                 if ( ! mansearch(&search, &conf.manpath,
 387                     argc, argv, &res, &sz))
 388                         usage(search.argmode);
 389 
 390                 if (sz == 0 && search.argmode == ARG_NAME)

 391                         fs_search(&search, &conf.manpath,
 392                             argc, argv, &res, &sz);
 393 
 394                 if (search.argmode == ARG_NAME) {
 395                         for (c = 0; c < argc; c++) {
 396                                 if (strchr(argv[c], '/') == NULL)
 397                                         continue;
 398                                 if (access(argv[c], R_OK) == -1) {
 399                                         warn("%s", argv[c]);
 400                                         continue;
 401                                 }
 402                                 res = mandoc_reallocarray(res,
 403                                     sz + 1, sizeof(*res));
 404                                 res[sz].file = mandoc_strdup(argv[c]);
 405                                 res[sz].names = NULL;
 406                                 res[sz].output = NULL;
 407                                 res[sz].ipath = SIZE_MAX;
 408                                 res[sz].bits = 0;
 409                                 res[sz].sec = 10;
 410                                 res[sz].form = FORM_SRC;
 411                                 sz++;
 412                         }
 413                 }
 414 
 415                 if (sz == 0) {
 416                         if (search.argmode != ARG_NAME)
 417                                 warnx("nothing appropriate");
 418                         rc = MANDOCLEVEL_BADARG;
 419                         goto out;
 420                 }
 421 
 422                 /*
 423                  * For standard man(1) and -a output mode,
 424                  * prepare for copying filename pointers
 425                  * into the program parameter array.
 426                  */
 427 
 428                 if (outmode == OUTMODE_ONE) {
 429                         argc = 1;
 430                         best_prio = 20;
 431                 } else if (outmode == OUTMODE_ALL)
 432                         argc = (int)sz;
 433 
 434                 /* Iterate all matching manuals. */
 435 
 436                 resp = res;
 437                 for (i = 0; i < sz; i++) {


 481 
 482         if (search.argmode == ARG_FILE)
 483                 moptions(&options, auxpaths);
 484 
 485         mchars_alloc();
 486         curp.mp = mparse_alloc(options, curp.mmin, mmsg,
 487             curp.os_e, curp.os_s);
 488 
 489         /*
 490          * Conditionally start up the lookaside buffer before parsing.
 491          */
 492         if (OUTT_MAN == curp.outtype)
 493                 mparse_keep(curp.mp);
 494 
 495         if (argc < 1) {
 496                 if (use_pager)
 497                         tag_files = tag_init();
 498                 parse(&curp, STDIN_FILENO, "<stdin>");
 499         }
 500 
 501         /*
 502          * Remember the original working directory, if possible.
 503          * This will be needed if some names on the command line
 504          * are page names and some are relative file names.
 505          * Do not error out if the current directory is not
 506          * readable: Maybe it won't be needed after all.
 507          */
 508         startdir = open(".", O_RDONLY | O_DIRECTORY);
 509 
 510         while (argc > 0) {
 511 
 512                 /*
 513                  * Changing directories is not needed in ARG_FILE mode.
 514                  * Do it on a best-effort basis.  Even in case of
 515                  * failure, some functionality may still work.
 516                  */
 517                 if (resp != NULL) {
 518                         if (resp->ipath != SIZE_MAX)
 519                                 (void)chdir(conf.manpath.paths[resp->ipath]);
 520                         else if (startdir != -1)
 521                                 (void)fchdir(startdir);
 522                 }
 523 
 524                 fd = mparse_open(curp.mp, resp != NULL ? resp->file : *argv);
 525                 if (fd != -1) {
 526                         if (use_pager) {
 527                                 tag_files = tag_init();
 528                                 use_pager = 0;
 529                         }
 530 
 531                         if (resp == NULL)
 532                                 parse(&curp, fd, *argv);
 533                         else if (resp->form == FORM_SRC)


 534                                 parse(&curp, fd, resp->file);
 535                         else
 536                                 passthrough(resp->file, fd,
 537                                     conf.output.synopsisonly);
 538 
 539                         if (ferror(stdout)) {
 540                                 if (tag_files != NULL) {
 541                                         warn("%s", tag_files->ofn);
 542                                         tag_unlink();
 543                                         tag_files = NULL;
 544                                 } else
 545                                         warn("stdout");
 546                                 rc = MANDOCLEVEL_SYSERR;
 547                                 break;
 548                         }
 549 
 550                         if (argc > 1 && curp.outtype <= OUTT_UTF8) {
 551                                 if (curp.outdata == NULL)
 552                                         outdata_alloc(&curp);
 553                                 terminal_sepline(curp.outdata);
 554                         }
 555                 } else if (rc < MANDOCLEVEL_ERROR)
 556                         rc = MANDOCLEVEL_ERROR;
 557 
 558                 if (MANDOCLEVEL_OK != rc && curp.wstop)
 559                         break;
 560 
 561                 if (resp != NULL)
 562                         resp++;
 563                 else
 564                         argv++;
 565                 if (--argc)
 566                         mparse_reset(curp.mp);
 567         }
 568         if (startdir != -1) {
 569                 (void)fchdir(startdir);
 570                 close(startdir);
 571         }
 572 
 573         if (curp.outdata != NULL) {
 574                 switch (curp.outtype) {
 575                 case OUTT_HTML:
 576                         html_free(curp.outdata);
 577                         break;
 578                 case OUTT_UTF8:
 579                 case OUTT_LOCALE:
 580                 case OUTT_ASCII:
 581                         ascii_free(curp.outdata);
 582                         break;
 583                 case OUTT_PDF:
 584                 case OUTT_PS:
 585                         pspdf_free(curp.outdata);
 586                         break;
 587                 default:
 588                         break;
 589                 }
 590         }
 591         mandoc_xr_free();


 772         size_t           ipath, isec, lastsz;
 773 
 774         assert(cfg->argmode == ARG_NAME);
 775 
 776         if (res != NULL)
 777                 *res = NULL;
 778         *ressz = lastsz = 0;
 779         while (argc) {
 780                 for (ipath = 0; ipath < paths->sz; ipath++) {
 781                         if (cfg->sec != NULL) {
 782                                 if (fs_lookup(paths, ipath, cfg->sec,
 783                                     cfg->arch, *argv, res, ressz) &&
 784                                     cfg->firstmatch)
 785                                         return 1;
 786                         } else for (isec = 0; isec < nsec; isec++)
 787                                 if (fs_lookup(paths, ipath, sections[isec],
 788                                     cfg->arch, *argv, res, ressz) &&
 789                                     cfg->firstmatch)
 790                                         return 1;
 791                 }
 792                 if (res != NULL && *ressz == lastsz &&
 793                     strchr(*argv, '/') == NULL)
 794                         warnx("No entry for %s in the manual.", *argv);
 795                 lastsz = *ressz;
 796                 argv++;
 797                 argc--;
 798         }
 799         return 0;
 800 }
 801 
 802 static void
 803 parse(struct curparse *curp, int fd, const char *file)
 804 {
 805         enum mandoclevel  rctmp;
 806         struct roff_man  *man;
 807 
 808         /* Begin by parsing the file itself. */
 809 
 810         assert(file);
 811         assert(fd >= 0);
 812 
 813         rctmp = mparse_readfd(curp->mp, fd, file);


1224         case -1:
1225                 err((int)MANDOCLEVEL_SYSERR, "fork");
1226         case 0:
1227                 break;
1228         default:
1229                 (void)setpgid(pager_pid, 0);
1230                 (void)tcsetpgrp(tag_files->ofd, pager_pid);
1231 #if HAVE_PLEDGE
1232                 if (pledge("stdio rpath tmppath tty proc", NULL) == -1)
1233                         err((int)MANDOCLEVEL_SYSERR, "pledge");
1234 #endif
1235                 tag_files->pager_pid = pager_pid;
1236                 return pager_pid;
1237         }
1238 
1239         /* The child process becomes the pager. */
1240 
1241         if (dup2(tag_files->ofd, STDOUT_FILENO) == -1)
1242                 err((int)MANDOCLEVEL_SYSERR, "pager stdout");
1243         close(tag_files->ofd);
1244         assert(tag_files->tfd == -1);
1245 
1246         /* Do not start the pager before controlling the terminal. */
1247 
1248         while (tcgetpgrp(STDOUT_FILENO) != getpid())
1249                 nanosleep(&timeout, NULL);
1250 
1251         execvp(argv[0], argv);
1252         err((int)MANDOCLEVEL_SYSERR, "exec %s", argv[0]);
1253 }