d09fe2c467
- avoid double slashes when displaying man pages (got tired of '/usr/share/man//cat1/man.0'). - got rid of __P() while working on it. - incorporate some of my old notes explaining how manpath works into the comments of the code itself. - renamed some of the vars so that the code is consistent throughout (and hopefully clearer and easier to understand) - fixed relative man paths for multiple man pages (man did a chdir() on the first man page it had to format --- this broke any remaining relative path man pages left to process). save old directory and fchdir() back to it after formatting. - improved doc on "man -h" which does more than just whatis(1) [e.g. "man -h fopen" prints the required include files and the prototypes rather than just the one-liner you get with whatis(1)] - manconf.c now fills in the "len" length field in the TAG/ENTRY structures (man now uses len). revise man.conf file reading stuff to return error on failure in addentry/gettag (fka getlist) rather than just err()ing out. this allows man(1) to call cleanup and delete its tmp files rather than just leave them floating. revise other apps using this code (makewhatis, apropos, catman, whatis) to expect this. also remove __P on updated files.
635 lines
15 KiB
C
635 lines
15 KiB
C
/* $NetBSD: catman.c,v 1.26 2006/04/10 14:39:06 chuck Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Author: Baldassare Dante Profeta <dante@mclink.it>
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the NetBSD
|
|
* Foundation, Inc. and its contributors.
|
|
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/queue.h>
|
|
#include <sys/cdefs.h>
|
|
#include <sys/param.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/utsname.h>
|
|
#include <ctype.h>
|
|
#include <dirent.h>
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <fnmatch.h>
|
|
#include <limits.h>
|
|
#include <libgen.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <glob.h>
|
|
|
|
#include "manconf.h"
|
|
#include "pathnames.h"
|
|
|
|
int f_nowhatis = 0;
|
|
int f_noaction = 0;
|
|
int f_noformat = 0;
|
|
int f_ignerr = 0;
|
|
int f_noprint = 0;
|
|
int dowhatis = 0;
|
|
|
|
TAG *defp; /* pointer to _default list */
|
|
|
|
int main(int, char * const *);
|
|
static void setdefentries(char *, char *, const char *);
|
|
static void uniquepath(void);
|
|
static void catman(void);
|
|
static void scanmandir(const char *, const char *);
|
|
static int splitentry(char *, char *, size_t, char *, size_t);
|
|
static void setcatsuffix(char *, const char *, const char *);
|
|
static void makecat(const char *, const char *, const char *, const char *);
|
|
static void makewhatis(void);
|
|
static void dosystem(const char *);
|
|
static void usage(void);
|
|
|
|
|
|
int
|
|
main(int argc, char * const *argv)
|
|
{
|
|
char *m_path = NULL;
|
|
char *m_add = NULL;
|
|
int c;
|
|
|
|
while ((c = getopt(argc, argv, "km:M:npsw")) != -1) {
|
|
switch (c) {
|
|
case 'k':
|
|
f_ignerr = 1;
|
|
break;
|
|
case 'n':
|
|
f_nowhatis = 1;
|
|
break;
|
|
case 'p':
|
|
f_noaction = 1;
|
|
break;
|
|
case 's':
|
|
f_noprint = 1;
|
|
break;
|
|
case 'w':
|
|
f_noformat = 1;
|
|
break;
|
|
case 'm':
|
|
m_add = optarg;
|
|
break;
|
|
case 'M':
|
|
m_path = optarg;
|
|
break;
|
|
default:
|
|
usage();
|
|
}
|
|
}
|
|
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
if (f_noprint && f_noaction)
|
|
f_noprint = 0;
|
|
|
|
if (argc > 1)
|
|
usage();
|
|
|
|
config(_PATH_MANCONF);
|
|
setdefentries(m_path, m_add, (argc == 0) ? NULL : argv[argc-1]);
|
|
uniquepath();
|
|
|
|
if (f_noformat == 0 || f_nowhatis == 0)
|
|
catman();
|
|
if (f_nowhatis == 0 && dowhatis)
|
|
makewhatis();
|
|
|
|
return(0);
|
|
}
|
|
|
|
static void
|
|
setdefentries(char *m_path, char *m_add, const char *sections)
|
|
{
|
|
TAG *defnewp, *sectnewp, *subp;
|
|
ENTRY *e_defp, *e_subp;
|
|
const char *p;
|
|
char *slashp, *machine;
|
|
char buf[MAXPATHLEN * 2];
|
|
int i;
|
|
|
|
/* Get the machine type. */
|
|
if ((machine = getenv("MACHINE")) == NULL) {
|
|
struct utsname utsname;
|
|
|
|
if (uname(&utsname) == -1) {
|
|
perror("uname");
|
|
exit(1);
|
|
}
|
|
machine = utsname.machine;
|
|
}
|
|
|
|
/* If there's no _default list, create an empty one. */
|
|
defp = gettag("_default", 1);
|
|
subp = gettag("_subdir", 1);
|
|
if (defp == NULL || subp == NULL)
|
|
err(1, "malloc");
|
|
|
|
/*
|
|
* 0: If one or more sections was specified, rewrite _subdir list.
|
|
*/
|
|
if (sections != NULL) {
|
|
if ((sectnewp = gettag("_section_new", 1)) == NULL)
|
|
err(1, "malloc");
|
|
for (p = sections; *p;) {
|
|
i = snprintf(buf, sizeof(buf), "man%c", *p++);
|
|
for (; *p && !isdigit((unsigned char)*p) && i < sizeof(buf) - 1; i++)
|
|
buf[i] = *p++;
|
|
buf[i] = '\0';
|
|
if (addentry(sectnewp, buf, 0) < 0)
|
|
err(1, "malloc");
|
|
}
|
|
subp = sectnewp;
|
|
}
|
|
|
|
/*
|
|
* 1: If the user specified a MANPATH variable, or set the -M
|
|
* option, we replace the _default list with the user's list,
|
|
* appending the entries in the _subdir list and the machine.
|
|
*/
|
|
if (m_path == NULL)
|
|
m_path = getenv("MANPATH");
|
|
if (m_path != NULL) {
|
|
while ((e_defp = TAILQ_FIRST(&defp->entrylist)) != NULL) {
|
|
free(e_defp->s);
|
|
TAILQ_REMOVE(&defp->entrylist, e_defp, q);
|
|
}
|
|
for (p = strtok(m_path, ":");
|
|
p != NULL; p = strtok(NULL, ":")) {
|
|
slashp = p[strlen(p) - 1] == '/' ? "" : "/";
|
|
TAILQ_FOREACH(e_subp, &subp->entrylist, q) {
|
|
if (!strncmp(e_subp->s, "cat", 3))
|
|
continue;
|
|
(void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
|
|
p, slashp, e_subp->s, machine);
|
|
if (addentry(defp, buf, 0) < 0)
|
|
err(1, "malloc");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 2: If the user did not specify MANPATH, -M or a section, rewrite
|
|
* the _default list to include the _subdir list and the machine.
|
|
*/
|
|
if (m_path == NULL) {
|
|
defp = gettag("_default", 1);
|
|
defnewp = gettag("_default_new1", 1);
|
|
if (defp == NULL || defnewp == NULL)
|
|
err(1, "malloc");
|
|
|
|
TAILQ_FOREACH(e_defp, &defp->entrylist, q) {
|
|
slashp =
|
|
e_defp->s[strlen(e_defp->s) - 1] == '/' ? "" : "/";
|
|
TAILQ_FOREACH(e_subp, &subp->entrylist, q) {
|
|
if (!strncmp(e_subp->s, "cat", 3))
|
|
continue;
|
|
(void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
|
|
e_defp->s, slashp, e_subp->s, machine);
|
|
if (addentry(defnewp, buf, 0) < 0)
|
|
err(1, "malloc");
|
|
}
|
|
}
|
|
defp = defnewp;
|
|
}
|
|
|
|
/*
|
|
* 3: If the user set the -m option, insert the user's list before
|
|
* whatever list we have, again appending the _subdir list and
|
|
* the machine.
|
|
*/
|
|
if (m_add != NULL)
|
|
for (p = strtok(m_add, ":"); p != NULL; p = strtok(NULL, ":")) {
|
|
slashp = p[strlen(p) - 1] == '/' ? "" : "/";
|
|
TAILQ_FOREACH(e_subp, &subp->entrylist, q) {
|
|
if (!strncmp(e_subp->s, "cat", 3))
|
|
continue;
|
|
(void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
|
|
p, slashp, e_subp->s, machine);
|
|
if (addentry(defp, buf, 1) < 0)
|
|
err(1, "malloc");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Remove entries (directory) which are symbolic links to other entries.
|
|
* Some examples are showed below:
|
|
* 1) if /usr/X11 -> /usr/X11R6 then remove all /usr/X11/man entries.
|
|
* 2) if /usr/local/man -> /usr/share/man then remove all /usr/local/man
|
|
* entries
|
|
*/
|
|
static void
|
|
uniquepath(void)
|
|
{
|
|
TAG *defnewp;
|
|
ENTRY *e_defp;
|
|
glob_t manpaths;
|
|
struct stat st1;
|
|
struct stat st2;
|
|
struct stat st3;
|
|
int len, lnk, gflags;
|
|
size_t i, j;
|
|
char path[PATH_MAX], *p;
|
|
|
|
gflags = 0;
|
|
TAILQ_FOREACH(e_defp, &defp->entrylist, q) {
|
|
glob(e_defp->s, GLOB_BRACE | GLOB_NOSORT | gflags, NULL,
|
|
&manpaths);
|
|
gflags = GLOB_APPEND;
|
|
}
|
|
|
|
if ((defnewp = gettag("_default_new2", 1)) == NULL)
|
|
err(1, "malloc");
|
|
|
|
for (i = 0; i < manpaths.gl_pathc; i++) {
|
|
lnk = 0;
|
|
lstat(manpaths.gl_pathv[i], &st1);
|
|
for (j = 0; j < manpaths.gl_pathc; j++) {
|
|
if (i != j) {
|
|
lstat(manpaths.gl_pathv[j], &st2);
|
|
if (st1.st_ino == st2.st_ino) {
|
|
strlcpy(path, manpaths.gl_pathv[i],
|
|
sizeof(path));
|
|
for (p = path; *(p+1) != '\0';) {
|
|
p = dirname(p);
|
|
lstat(p, &st3);
|
|
if (S_ISLNK(st3.st_mode)) {
|
|
lnk = 1;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
len = readlink(manpaths.gl_pathv[i],
|
|
path, sizeof(path) - 1);
|
|
if (len == -1)
|
|
continue;
|
|
path[len] = '\0';
|
|
if (!strcmp(path, manpaths.gl_pathv[j]))
|
|
lnk = 1;
|
|
}
|
|
if (lnk)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!lnk) {
|
|
if (addentry(defnewp, manpaths.gl_pathv[i], 0) < 0)
|
|
err(1, "malloc");
|
|
}
|
|
}
|
|
|
|
globfree(&manpaths);
|
|
|
|
defp = defnewp;
|
|
}
|
|
|
|
static void
|
|
catman(void)
|
|
{
|
|
ENTRY *e_path;
|
|
const char *mandir;
|
|
char catdir[PATH_MAX], *cp;
|
|
|
|
TAILQ_FOREACH(e_path, &defp->entrylist, q) {
|
|
mandir = e_path->s;
|
|
strlcpy(catdir, mandir, sizeof(catdir));
|
|
if (!(cp = strstr(catdir, "man/man")))
|
|
continue;
|
|
cp += 4; *cp++ = 'c'; *cp++ = 'a'; *cp = 't';
|
|
scanmandir(catdir, mandir);
|
|
}
|
|
}
|
|
|
|
static void
|
|
scanmandir(const char *catdir, const char *mandir)
|
|
{
|
|
TAG *buildp, *crunchp;
|
|
ENTRY *e_build, *e_crunch;
|
|
char manpage[PATH_MAX];
|
|
char catpage[PATH_MAX];
|
|
char linkname[PATH_MAX];
|
|
char buffer[PATH_MAX], *bp;
|
|
char tmp[PATH_MAX];
|
|
char buildsuff[256], buildcmd[256];
|
|
char crunchsuff[256], crunchcmd[256];
|
|
char match[256];
|
|
struct stat manstat;
|
|
struct stat catstat;
|
|
struct stat lnkstat;
|
|
struct dirent *dp;
|
|
DIR *dirp;
|
|
int len, error;
|
|
|
|
if ((dirp = opendir(mandir)) == 0) {
|
|
warn("can't open %s", mandir);
|
|
return;
|
|
}
|
|
|
|
if (stat(catdir, &catstat) < 0) {
|
|
if (errno != ENOENT) {
|
|
warn("can't stat %s", catdir);
|
|
closedir(dirp);
|
|
return;
|
|
}
|
|
if (f_noprint == 0)
|
|
printf("mkdir %s\n", catdir);
|
|
if (f_noaction == 0 && mkdir(catdir, 0755) < 0) {
|
|
warn("can't create %s", catdir);
|
|
closedir(dirp);
|
|
return;
|
|
}
|
|
}
|
|
|
|
while ((dp = readdir(dirp)) != NULL) {
|
|
if (strcmp(dp->d_name, ".") == 0 ||
|
|
strcmp(dp->d_name, "..") == 0)
|
|
continue;
|
|
|
|
snprintf(manpage, sizeof(manpage), "%s/%s", mandir, dp->d_name);
|
|
snprintf(catpage, sizeof(catpage), "%s/%s", catdir, dp->d_name);
|
|
|
|
e_build = NULL;
|
|
if ((buildp = gettag("_build", 1)) == NULL)
|
|
err(1, "malloc");
|
|
TAILQ_FOREACH(e_build, &buildp->entrylist, q) {
|
|
splitentry(e_build->s, buildsuff, sizeof(buildsuff),
|
|
buildcmd, sizeof(buildcmd));
|
|
snprintf(match, sizeof(match), "*%s",
|
|
buildsuff);
|
|
if (!fnmatch(match, manpage, 0))
|
|
break;
|
|
}
|
|
|
|
if (e_build == NULL)
|
|
continue;
|
|
|
|
e_crunch = NULL;
|
|
if ((crunchp = gettag("_crunch", 1)) == NULL)
|
|
err(1, "malloc");
|
|
TAILQ_FOREACH(e_crunch, &crunchp->entrylist, q) {
|
|
splitentry(e_crunch->s, crunchsuff, sizeof(crunchsuff),
|
|
crunchcmd, sizeof(crunchcmd));
|
|
snprintf(match, sizeof(match), "*%s", crunchsuff);
|
|
if (!fnmatch(match, manpage, 0))
|
|
break;
|
|
}
|
|
|
|
if (lstat(manpage, &manstat) <0) {
|
|
warn("can't stat %s", manpage);
|
|
continue;
|
|
} else {
|
|
if (S_ISLNK(manstat.st_mode)) {
|
|
strlcpy(buffer, catpage, sizeof(buffer));
|
|
strlcpy(linkname, basename(buffer),
|
|
sizeof(linkname));
|
|
len = readlink(manpage, buffer,
|
|
sizeof(buffer) - 1);
|
|
if (len == -1) {
|
|
warn("can't stat read symbolic link %s",
|
|
manpage);
|
|
continue;
|
|
}
|
|
buffer[len] = '\0';
|
|
bp = basename(buffer);
|
|
strlcpy(tmp, manpage, sizeof(tmp));
|
|
snprintf(manpage, sizeof(manpage), "%s/%s",
|
|
dirname(tmp), bp);
|
|
strlcpy(tmp, catpage, sizeof(tmp));
|
|
snprintf(catpage, sizeof(catpage), "%s/%s",
|
|
dirname(tmp), buffer);
|
|
}
|
|
else
|
|
*linkname = '\0';
|
|
}
|
|
|
|
if (!e_crunch) {
|
|
*crunchsuff = *crunchcmd = '\0';
|
|
}
|
|
setcatsuffix(catpage, buildsuff, crunchsuff);
|
|
if (*linkname != '\0')
|
|
setcatsuffix(linkname, buildsuff, crunchsuff);
|
|
|
|
if (stat(manpage, &manstat) < 0) {
|
|
warn("can't stat %s", manpage);
|
|
continue;
|
|
}
|
|
|
|
if (!S_ISREG(manstat.st_mode)) {
|
|
warnx("not a regular file %s", manpage);
|
|
continue;
|
|
}
|
|
|
|
if ((error = stat(catpage, &catstat)) &&
|
|
errno != ENOENT) {
|
|
warn("can't stat %s", catpage);
|
|
continue;
|
|
}
|
|
|
|
if ((error && errno == ENOENT) ||
|
|
manstat.st_mtime > catstat.st_mtime) {
|
|
if (f_noformat) {
|
|
dowhatis = 1;
|
|
} else {
|
|
/*
|
|
* reformat out of date manpage
|
|
*/
|
|
makecat(manpage, catpage, buildcmd, crunchcmd);
|
|
dowhatis = 1;
|
|
}
|
|
}
|
|
|
|
if (*linkname != '\0') {
|
|
strlcpy(tmp, catpage, sizeof(tmp));
|
|
snprintf(tmp, sizeof(tmp), "%s/%s", dirname(tmp),
|
|
linkname);
|
|
if ((error = lstat(tmp, &lnkstat)) &&
|
|
errno != ENOENT) {
|
|
warn("can't stat %s", tmp);
|
|
continue;
|
|
}
|
|
|
|
if (error && errno == ENOENT) {
|
|
if (f_noformat) {
|
|
dowhatis = 1;
|
|
} else {
|
|
/*
|
|
* create symbolic link
|
|
*/
|
|
if (f_noprint == 0)
|
|
printf("ln -s %s %s\n", catpage,
|
|
linkname);
|
|
if (f_noaction == 0) {
|
|
strlcpy(tmp, catpage,
|
|
sizeof(tmp));
|
|
if (chdir(dirname(tmp)) == -1) {
|
|
warn("can't chdir");
|
|
continue;
|
|
}
|
|
|
|
if (symlink(catpage, linkname)
|
|
== -1) {
|
|
warn("can't create"
|
|
" symbolic"
|
|
" link %s",
|
|
linkname);
|
|
continue;
|
|
}
|
|
}
|
|
dowhatis = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
closedir(dirp);
|
|
}
|
|
|
|
static int
|
|
splitentry(char *s, char *first, size_t firstlen, char *second,
|
|
size_t secondlen)
|
|
{
|
|
char *c;
|
|
|
|
for (c = s; *c != '\0' && !isspace((unsigned char)*c); ++c)
|
|
;
|
|
if (*c == '\0')
|
|
return(0);
|
|
if (c - s + 1 > firstlen)
|
|
return(0);
|
|
strncpy(first, s, c-s);
|
|
first[c-s] = '\0';
|
|
for (; *c != '\0' && isspace((unsigned char)*c); ++c)
|
|
;
|
|
if (strlcpy(second, c, secondlen) >= secondlen)
|
|
return(0);
|
|
return(1);
|
|
}
|
|
|
|
static void
|
|
setcatsuffix(char *catpage, const char *suffix, const char *crunchsuff)
|
|
{
|
|
TAG *tp;
|
|
char *p;
|
|
|
|
for (p = catpage + strlen(catpage); p != catpage; p--)
|
|
if (!fnmatch(suffix, p, 0)) {
|
|
if ((tp = gettag("_suffix", 1)) == NULL)
|
|
err(1, "malloc");
|
|
if (! TAILQ_EMPTY(&tp->entrylist)) {
|
|
sprintf(p, "%s%s",
|
|
TAILQ_FIRST(&tp->entrylist)->s, crunchsuff);
|
|
} else {
|
|
sprintf(p, ".0%s", crunchsuff);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
makecat(const char *manpage, const char *catpage, const char *buildcmd,
|
|
const char *crunchcmd)
|
|
{
|
|
char crunchbuf[1024];
|
|
char sysbuf[2048];
|
|
|
|
snprintf(sysbuf, sizeof(sysbuf), buildcmd, manpage);
|
|
|
|
if (*crunchcmd != '\0') {
|
|
snprintf(crunchbuf, sizeof(crunchbuf), crunchcmd, catpage);
|
|
snprintf(sysbuf, sizeof(sysbuf), "%s | %s", sysbuf, crunchbuf);
|
|
} else {
|
|
snprintf(sysbuf, sizeof(sysbuf), "%s > %s", sysbuf, catpage);
|
|
}
|
|
|
|
if (f_noprint == 0)
|
|
printf("%s\n", sysbuf);
|
|
if (f_noaction == 0)
|
|
dosystem(sysbuf);
|
|
}
|
|
|
|
static void
|
|
makewhatis(void)
|
|
{
|
|
TAG *whatdbp;
|
|
ENTRY *e_whatdb;
|
|
char sysbuf[1024];
|
|
|
|
if ((whatdbp = gettag("_whatdb", 1)) == NULL)
|
|
err(1, "malloc");
|
|
TAILQ_FOREACH(e_whatdb, &whatdbp->entrylist, q) {
|
|
snprintf(sysbuf, sizeof(sysbuf), "%s %s",
|
|
_PATH_WHATIS, dirname(e_whatdb->s));
|
|
if (f_noprint == 0)
|
|
printf("%s\n", sysbuf);
|
|
if (f_noaction == 0)
|
|
dosystem(sysbuf);
|
|
}
|
|
}
|
|
|
|
static void
|
|
dosystem(const char *cmd)
|
|
{
|
|
int status;
|
|
|
|
if ((status = system(cmd)) == 0)
|
|
return;
|
|
|
|
if (status == -1)
|
|
err(1, "cannot execute action");
|
|
if (WIFSIGNALED(status))
|
|
errx(1, "child was signaled to quit. aborting");
|
|
if (WIFSTOPPED(status))
|
|
errx(1, "child was stopped. aborting");
|
|
if (f_ignerr == 0)
|
|
errx(1, "*** Exited %d", status);
|
|
warnx("*** Exited %d (continuing)", status);
|
|
}
|
|
|
|
static void
|
|
usage(void)
|
|
{
|
|
(void)fprintf(stderr,
|
|
"usage: catman [-knpsw] [-m manpath] [sections]\n");
|
|
(void)fprintf(stderr,
|
|
" catman [-knpsw] [-M manpath] [sections]\n");
|
|
exit(1);
|
|
}
|