Sat Oct 12 17:26:26 2019 UTC ()
enlarge buffer sizes


(christos)
diff -r1.37 -r1.38 src/usr.sbin/catman/catman.c

cvs diff -r1.37 -r1.38 src/usr.sbin/catman/catman.c (switch to unified diff)

--- src/usr.sbin/catman/catman.c 2016/05/29 22:33:39 1.37
+++ src/usr.sbin/catman/catman.c 2019/10/12 17:26:26 1.38
@@ -1,640 +1,640 @@ @@ -1,640 +1,640 @@
1/* $NetBSD: catman.c,v 1.37 2016/05/29 22:33:39 dholland Exp $ */ 1/* $NetBSD: catman.c,v 1.38 2019/10/12 17:26:26 christos Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Author: Baldassare Dante Profeta <dante@mclink.it> 7 * Author: Baldassare Dante Profeta <dante@mclink.it>
8 * 8 *
9 * Redistribution and use in source and binary forms, with or without 9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions 10 * modification, are permitted provided that the following conditions
11 * are met: 11 * are met:
12 * 1. Redistributions of source code must retain the above copyright 12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer. 13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright 14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the 15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution. 16 * documentation and/or other materials provided with the distribution.
17 * 17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE. 28 * POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30 30
31#include <sys/cdefs.h> 31#include <sys/cdefs.h>
32#ifndef lint 32#ifndef lint
33__RCSID("$NetBSD: catman.c,v 1.37 2016/05/29 22:33:39 dholland Exp $"); 33__RCSID("$NetBSD: catman.c,v 1.38 2019/10/12 17:26:26 christos Exp $");
34#endif /* not lint */ 34#endif /* not lint */
35 35
36#include <sys/types.h> 36#include <sys/types.h>
37#include <sys/queue.h> 37#include <sys/queue.h>
38#include <sys/param.h> 38#include <sys/param.h>
39#include <sys/stat.h> 39#include <sys/stat.h>
40#include <sys/wait.h> 40#include <sys/wait.h>
41#include <sys/utsname.h> 41#include <sys/utsname.h>
42#include <ctype.h> 42#include <ctype.h>
43#include <dirent.h> 43#include <dirent.h>
44#include <err.h> 44#include <err.h>
45#include <errno.h> 45#include <errno.h>
46#include <fnmatch.h> 46#include <fnmatch.h>
47#include <limits.h> 47#include <limits.h>
48#include <libgen.h> 48#include <libgen.h>
49#include <stdio.h> 49#include <stdio.h>
50#include <stdlib.h> 50#include <stdlib.h>
51#include <string.h> 51#include <string.h>
52#include <unistd.h> 52#include <unistd.h>
53#include <glob.h> 53#include <glob.h>
54 54
55#include "manconf.h" 55#include "manconf.h"
56#include "pathnames.h" 56#include "pathnames.h"
57 57
58int f_nowhatis = 0; 58int f_nowhatis = 0;
59int f_noaction = 0; 59int f_noaction = 0;
60int f_noformat = 0; 60int f_noformat = 0;
61int f_ignerr = 0; 61int f_ignerr = 0;
62int f_noprint = 0; 62int f_noprint = 0;
63int dowhatis = 0; 63int dowhatis = 0;
64 64
65TAG *defp; /* pointer to _default list */ 65TAG *defp; /* pointer to _default list */
66 66
67static void setdefentries(char *, char *, const char *); 67static void setdefentries(char *, char *, const char *);
68static void uniquepath(void); 68static void uniquepath(void);
69static void catman(void); 69static void catman(void);
70static void scanmandir(const char *, const char *); 70static void scanmandir(const char *, const char *);
71static int splitentry(char *, char *, size_t, char *, size_t); 71static int splitentry(char *, char *, size_t, char *, size_t);
72static void setcatsuffix(char *, const char *, const char *); 72static void setcatsuffix(char *, const char *, const char *);
73static void makecat(const char *, const char *, const char *, const char *); 73static void makecat(const char *, const char *, const char *, const char *);
74static void makewhatis(void); 74static void makewhatis(void);
75static void dosystem(const char *); 75static void dosystem(const char *);
76__dead static void usage(void); 76__dead static void usage(void);
77 77
78 78
79int 79int
80main(int argc, char * const *argv) 80main(int argc, char * const *argv)
81{ 81{
82 char *m_path = NULL; 82 char *m_path = NULL;
83 char *m_add = NULL; 83 char *m_add = NULL;
84 int c; 84 int c;
85 85
86 while ((c = getopt(argc, argv, "km:M:npsw")) != -1) { 86 while ((c = getopt(argc, argv, "km:M:npsw")) != -1) {
87 switch (c) { 87 switch (c) {
88 case 'k': 88 case 'k':
89 f_ignerr = 1; 89 f_ignerr = 1;
90 break; 90 break;
91 case 'n': 91 case 'n':
92 f_nowhatis = 1; 92 f_nowhatis = 1;
93 break; 93 break;
94 case 'p': 94 case 'p':
95 f_noaction = 1; 95 f_noaction = 1;
96 break; 96 break;
97 case 's': 97 case 's':
98 f_noprint = 1; 98 f_noprint = 1;
99 break; 99 break;
100 case 'w': 100 case 'w':
101 f_noformat = 1; 101 f_noformat = 1;
102 break; 102 break;
103 case 'm': 103 case 'm':
104 m_add = optarg; 104 m_add = optarg;
105 break; 105 break;
106 case 'M': 106 case 'M':
107 m_path = optarg; 107 m_path = optarg;
108 break; 108 break;
109 default: 109 default:
110 usage(); 110 usage();
111 } 111 }
112 } 112 }
113 113
114 argc -= optind; 114 argc -= optind;
115 argv += optind; 115 argv += optind;
116 116
117 if (f_noprint && f_noaction) 117 if (f_noprint && f_noaction)
118 f_noprint = 0; 118 f_noprint = 0;
119 119
120 if (argc > 1) 120 if (argc > 1)
121 usage(); 121 usage();
122 122
123 config(_PATH_MANCONF); 123 config(_PATH_MANCONF);
124 setdefentries(m_path, m_add, (argc == 0) ? NULL : argv[argc-1]); 124 setdefentries(m_path, m_add, (argc == 0) ? NULL : argv[argc-1]);
125 uniquepath(); 125 uniquepath();
126 126
127 if (f_noformat == 0 || f_nowhatis == 0) 127 if (f_noformat == 0 || f_nowhatis == 0)
128 catman(); 128 catman();
129 if (f_nowhatis == 0 && dowhatis) 129 if (f_nowhatis == 0 && dowhatis)
130 makewhatis(); 130 makewhatis();
131 131
132 return(0); 132 return(0);
133} 133}
134 134
135static void 135static void
136setdefentries(char *m_path, char *m_add, const char *sections) 136setdefentries(char *m_path, char *m_add, const char *sections)
137{ 137{
138 TAG *defnewp, *sectnewp, *subp; 138 TAG *defnewp, *sectnewp, *subp;
139 ENTRY *e_defp, *e_subp; 139 ENTRY *e_defp, *e_subp;
140 const char *p, *slashp; 140 const char *p, *slashp;
141 char *machine; 141 char *machine;
142 char buf[MAXPATHLEN * 2]; 142 char buf[MAXPATHLEN * 2];
143 int i; 143 int i;
144 144
145 /* Get the machine type. */ 145 /* Get the machine type. */
146 if ((machine = getenv("MACHINE")) == NULL) { 146 if ((machine = getenv("MACHINE")) == NULL) {
147 struct utsname utsname; 147 struct utsname utsname;
148 148
149 if (uname(&utsname) == -1) { 149 if (uname(&utsname) == -1) {
150 perror("uname"); 150 perror("uname");
151 exit(1); 151 exit(1);
152 } 152 }
153 machine = utsname.machine; 153 machine = utsname.machine;
154 } 154 }
155 155
156 /* If there's no _default list, create an empty one. */ 156 /* If there's no _default list, create an empty one. */
157 defp = gettag("_default", 1); 157 defp = gettag("_default", 1);
158 subp = gettag("_subdir", 1); 158 subp = gettag("_subdir", 1);
159 if (defp == NULL || subp == NULL) 159 if (defp == NULL || subp == NULL)
160 err(1, "malloc"); 160 err(1, "malloc");
161 161
162 /* 162 /*
163 * 0: If one or more sections was specified, rewrite _subdir list. 163 * 0: If one or more sections was specified, rewrite _subdir list.
164 */ 164 */
165 if (sections != NULL) { 165 if (sections != NULL) {
166 if ((sectnewp = gettag("_section_new", 1)) == NULL) 166 if ((sectnewp = gettag("_section_new", 1)) == NULL)
167 err(1, "malloc"); 167 err(1, "malloc");
168 for (p = sections; *p;) { 168 for (p = sections; *p;) {
169 i = snprintf(buf, sizeof(buf), "man%c", *p++); 169 i = snprintf(buf, sizeof(buf), "man%c", *p++);
170 for (; *p && !isdigit((unsigned char)*p) && i < (int)sizeof(buf) - 1; i++) 170 for (; *p && !isdigit((unsigned char)*p) && i < (int)sizeof(buf) - 1; i++)
171 buf[i] = *p++; 171 buf[i] = *p++;
172 buf[i] = '\0'; 172 buf[i] = '\0';
173 if (addentry(sectnewp, buf, 0) < 0) 173 if (addentry(sectnewp, buf, 0) < 0)
174 err(1, "malloc"); 174 err(1, "malloc");
175 } 175 }
176 subp = sectnewp; 176 subp = sectnewp;
177 } 177 }
178 178
179 /* 179 /*
180 * 1: If the user specified a MANPATH variable, or set the -M 180 * 1: If the user specified a MANPATH variable, or set the -M
181 * option, we replace the _default list with the user's list, 181 * option, we replace the _default list with the user's list,
182 * appending the entries in the _subdir list and the machine. 182 * appending the entries in the _subdir list and the machine.
183 */ 183 */
184 if (m_path == NULL) 184 if (m_path == NULL)
185 m_path = getenv("MANPATH"); 185 m_path = getenv("MANPATH");
186 if (m_path != NULL) { 186 if (m_path != NULL) {
187 while ((e_defp = TAILQ_FIRST(&defp->entrylist)) != NULL) { 187 while ((e_defp = TAILQ_FIRST(&defp->entrylist)) != NULL) {
188 free(e_defp->s); 188 free(e_defp->s);
189 TAILQ_REMOVE(&defp->entrylist, e_defp, q); 189 TAILQ_REMOVE(&defp->entrylist, e_defp, q);
190 } 190 }
191 for (p = strtok(m_path, ":"); 191 for (p = strtok(m_path, ":");
192 p != NULL; p = strtok(NULL, ":")) { 192 p != NULL; p = strtok(NULL, ":")) {
193 slashp = p[strlen(p) - 1] == '/' ? "" : "/"; 193 slashp = p[strlen(p) - 1] == '/' ? "" : "/";
194 TAILQ_FOREACH(e_subp, &subp->entrylist, q) { 194 TAILQ_FOREACH(e_subp, &subp->entrylist, q) {
195 if (!strncmp(e_subp->s, "cat", 3)) 195 if (!strncmp(e_subp->s, "cat", 3))
196 continue; 196 continue;
197 (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}", 197 (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
198 p, slashp, e_subp->s, machine); 198 p, slashp, e_subp->s, machine);
199 if (addentry(defp, buf, 0) < 0) 199 if (addentry(defp, buf, 0) < 0)
200 err(1, "malloc"); 200 err(1, "malloc");
201 } 201 }
202 } 202 }
203 } 203 }
204 204
205 /* 205 /*
206 * 2: If the user did not specify MANPATH, -M or a section, rewrite 206 * 2: If the user did not specify MANPATH, -M or a section, rewrite
207 * the _default list to include the _subdir list and the machine. 207 * the _default list to include the _subdir list and the machine.
208 */ 208 */
209 if (m_path == NULL) { 209 if (m_path == NULL) {
210 defp = gettag("_default", 1); 210 defp = gettag("_default", 1);
211 defnewp = gettag("_default_new1", 1); 211 defnewp = gettag("_default_new1", 1);
212 if (defp == NULL || defnewp == NULL) 212 if (defp == NULL || defnewp == NULL)
213 err(1, "malloc"); 213 err(1, "malloc");
214 214
215 TAILQ_FOREACH(e_defp, &defp->entrylist, q) { 215 TAILQ_FOREACH(e_defp, &defp->entrylist, q) {
216 slashp = 216 slashp =
217 e_defp->s[strlen(e_defp->s) - 1] == '/' ? "" : "/"; 217 e_defp->s[strlen(e_defp->s) - 1] == '/' ? "" : "/";
218 TAILQ_FOREACH(e_subp, &subp->entrylist, q) { 218 TAILQ_FOREACH(e_subp, &subp->entrylist, q) {
219 if (!strncmp(e_subp->s, "cat", 3)) 219 if (!strncmp(e_subp->s, "cat", 3))
220 continue; 220 continue;
221 (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}", 221 (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
222 e_defp->s, slashp, e_subp->s, machine); 222 e_defp->s, slashp, e_subp->s, machine);
223 if (addentry(defnewp, buf, 0) < 0) 223 if (addentry(defnewp, buf, 0) < 0)
224 err(1, "malloc"); 224 err(1, "malloc");
225 } 225 }
226 } 226 }
227 defp = defnewp; 227 defp = defnewp;
228 } 228 }
229 229
230 /* 230 /*
231 * 3: If the user set the -m option, insert the user's list before 231 * 3: If the user set the -m option, insert the user's list before
232 * whatever list we have, again appending the _subdir list and 232 * whatever list we have, again appending the _subdir list and
233 * the machine. 233 * the machine.
234 */ 234 */
235 if (m_add != NULL) 235 if (m_add != NULL)
236 for (p = strtok(m_add, ":"); p != NULL; p = strtok(NULL, ":")) { 236 for (p = strtok(m_add, ":"); p != NULL; p = strtok(NULL, ":")) {
237 slashp = p[strlen(p) - 1] == '/' ? "" : "/"; 237 slashp = p[strlen(p) - 1] == '/' ? "" : "/";
238 TAILQ_FOREACH(e_subp, &subp->entrylist, q) { 238 TAILQ_FOREACH(e_subp, &subp->entrylist, q) {
239 if (!strncmp(e_subp->s, "cat", 3)) 239 if (!strncmp(e_subp->s, "cat", 3))
240 continue; 240 continue;
241 (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}", 241 (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
242 p, slashp, e_subp->s, machine); 242 p, slashp, e_subp->s, machine);
243 if (addentry(defp, buf, 1) < 0) 243 if (addentry(defp, buf, 1) < 0)
244 err(1, "malloc"); 244 err(1, "malloc");
245 } 245 }
246 } 246 }
247} 247}
248 248
249/* 249/*
250 * Remove entries (directory) which are symbolic links to other entries. 250 * Remove entries (directory) which are symbolic links to other entries.
251 * Some examples are showed below: 251 * Some examples are showed below:
252 * 1) if /usr/X11 -> /usr/X11R6 then remove all /usr/X11/man entries. 252 * 1) if /usr/X11 -> /usr/X11R6 then remove all /usr/X11/man entries.
253 * 2) if /usr/local/man -> /usr/share/man then remove all /usr/local/man 253 * 2) if /usr/local/man -> /usr/share/man then remove all /usr/local/man
254 * entries 254 * entries
255 */ 255 */
256static void 256static void
257uniquepath(void) 257uniquepath(void)
258{ 258{
259 TAG *defnewp; 259 TAG *defnewp;
260 ENTRY *e_defp; 260 ENTRY *e_defp;
261 glob_t manpaths; 261 glob_t manpaths;
262 struct stat st1; 262 struct stat st1;
263 struct stat st2; 263 struct stat st2;
264 struct stat st3; 264 struct stat st3;
265 int len, lnk, gflags; 265 int len, lnk, gflags;
266 size_t i, j; 266 size_t i, j;
267 char path[PATH_MAX], *p; 267 char path[PATH_MAX], *p;
268 268
269 gflags = 0; 269 gflags = 0;
270 TAILQ_FOREACH(e_defp, &defp->entrylist, q) { 270 TAILQ_FOREACH(e_defp, &defp->entrylist, q) {
271 glob(e_defp->s, GLOB_BRACE | GLOB_NOSORT | gflags, NULL, 271 glob(e_defp->s, GLOB_BRACE | GLOB_NOSORT | gflags, NULL,
272 &manpaths); 272 &manpaths);
273 gflags = GLOB_APPEND; 273 gflags = GLOB_APPEND;
274 } 274 }
275 275
276 if ((defnewp = gettag("_default_new2", 1)) == NULL) 276 if ((defnewp = gettag("_default_new2", 1)) == NULL)
277 err(1, "malloc"); 277 err(1, "malloc");
278 278
279 for (i = 0; i < manpaths.gl_pathc; i++) { 279 for (i = 0; i < manpaths.gl_pathc; i++) {
280 lnk = 0; 280 lnk = 0;
281 lstat(manpaths.gl_pathv[i], &st1); 281 lstat(manpaths.gl_pathv[i], &st1);
282 for (j = 0; j < manpaths.gl_pathc; j++) { 282 for (j = 0; j < manpaths.gl_pathc; j++) {
283 if (i != j) { 283 if (i != j) {
284 lstat(manpaths.gl_pathv[j], &st2); 284 lstat(manpaths.gl_pathv[j], &st2);
285 if (st1.st_ino == st2.st_ino) { 285 if (st1.st_ino == st2.st_ino) {
286 strlcpy(path, manpaths.gl_pathv[i], 286 strlcpy(path, manpaths.gl_pathv[i],
287 sizeof(path)); 287 sizeof(path));
288 for (p = path; *(p+1) != '\0';) { 288 for (p = path; *(p+1) != '\0';) {
289 p = dirname(p); 289 p = dirname(p);
290 lstat(p, &st3); 290 lstat(p, &st3);
291 if (S_ISLNK(st3.st_mode)) { 291 if (S_ISLNK(st3.st_mode)) {
292 lnk = 1; 292 lnk = 1;
293 break; 293 break;
294 } 294 }
295 } 295 }
296 } else { 296 } else {
297 len = readlink(manpaths.gl_pathv[i], 297 len = readlink(manpaths.gl_pathv[i],
298 path, sizeof(path) - 1); 298 path, sizeof(path) - 1);
299 if (len == -1) 299 if (len == -1)
300 continue; 300 continue;
301 path[len] = '\0'; 301 path[len] = '\0';
302 if (!strcmp(path, manpaths.gl_pathv[j])) 302 if (!strcmp(path, manpaths.gl_pathv[j]))
303 lnk = 1; 303 lnk = 1;
304 } 304 }
305 if (lnk) 305 if (lnk)
306 break; 306 break;
307 } 307 }
308 } 308 }
309 309
310 if (!lnk) { 310 if (!lnk) {
311 if (addentry(defnewp, manpaths.gl_pathv[i], 0) < 0) 311 if (addentry(defnewp, manpaths.gl_pathv[i], 0) < 0)
312 err(1, "malloc"); 312 err(1, "malloc");
313 } 313 }
314 } 314 }
315 315
316 globfree(&manpaths); 316 globfree(&manpaths);
317 317
318 defp = defnewp; 318 defp = defnewp;
319} 319}
320 320
321static void 321static void
322catman(void) 322catman(void)
323{ 323{
324 ENTRY *e_path; 324 ENTRY *e_path;
325 const char *mandir; 325 const char *mandir;
326 char catdir[PATH_MAX], *cp; 326 char catdir[PATH_MAX], *cp;
327 327
328 TAILQ_FOREACH(e_path, &defp->entrylist, q) { 328 TAILQ_FOREACH(e_path, &defp->entrylist, q) {
329 mandir = e_path->s; 329 mandir = e_path->s;
330 strlcpy(catdir, mandir, sizeof(catdir)); 330 strlcpy(catdir, mandir, sizeof(catdir));
331 if (!(cp = strstr(catdir, "man/man"))) 331 if (!(cp = strstr(catdir, "man/man")))
332 continue; 332 continue;
333 cp += 4; *cp++ = 'c'; *cp++ = 'a'; *cp = 't'; 333 cp += 4; *cp++ = 'c'; *cp++ = 'a'; *cp = 't';
334 scanmandir(catdir, mandir); 334 scanmandir(catdir, mandir);
335 } 335 }
336} 336}
337 337
338static void 338static void
339scanmandir(const char *catdir, const char *mandir) 339scanmandir(const char *catdir, const char *mandir)
340{ 340{
341 TAG *buildp, *crunchp; 341 TAG *buildp, *crunchp;
342 ENTRY *e_build, *e_crunch; 342 ENTRY *e_build, *e_crunch;
343 char manpage[PATH_MAX]; 343 char manpage[2 * PATH_MAX];
344 char catpage[PATH_MAX]; 344 char catpage[2 * PATH_MAX];
345 char linkname[PATH_MAX]; 345 char linkname[PATH_MAX];
346 char buffer[PATH_MAX], *bp; 346 char buffer[PATH_MAX], *bp;
347 char tmp[PATH_MAX]; 347 char tmp[2 * PATH_MAX];
348 char buildsuff[256], buildcmd[256]; 348 char buildsuff[256], buildcmd[256];
349 char crunchsuff[256], crunchcmd[256]; 349 char crunchsuff[256], crunchcmd[256];
350 char match[256]; 350 char match[2 * 256];
351 struct stat manstat; 351 struct stat manstat;
352 struct stat catstat; 352 struct stat catstat;
353 struct stat lnkstat; 353 struct stat lnkstat;
354 struct dirent *dp; 354 struct dirent *dp;
355 DIR *dirp; 355 DIR *dirp;
356 int len, error; 356 int len, error;
357 357
358 if ((dirp = opendir(mandir)) == 0) { 358 if ((dirp = opendir(mandir)) == 0) {
359 warn("can't open %s", mandir); 359 warn("can't open %s", mandir);
360 return; 360 return;
361 } 361 }
362 362
363 if (stat(catdir, &catstat) < 0) { 363 if (stat(catdir, &catstat) < 0) {
364 if (errno != ENOENT) { 364 if (errno != ENOENT) {
365 warn("can't stat %s", catdir); 365 warn("can't stat %s", catdir);
366 closedir(dirp); 366 closedir(dirp);
367 return; 367 return;
368 } 368 }
369 if (f_noprint == 0) 369 if (f_noprint == 0)
370 printf("mkdir %s\n", catdir); 370 printf("mkdir %s\n", catdir);
371 if (f_noaction == 0 && mkdir(catdir, 0755) < 0) { 371 if (f_noaction == 0 && mkdir(catdir, 0755) < 0) {
372 warn("can't create %s", catdir); 372 warn("can't create %s", catdir);
373 closedir(dirp); 373 closedir(dirp);
374 return; 374 return;
375 } 375 }
376 } 376 }
377 377
378 while ((dp = readdir(dirp)) != NULL) { 378 while ((dp = readdir(dirp)) != NULL) {
379 if (strcmp(dp->d_name, ".") == 0 || 379 if (strcmp(dp->d_name, ".") == 0 ||
380 strcmp(dp->d_name, "..") == 0) 380 strcmp(dp->d_name, "..") == 0)
381 continue; 381 continue;
382 382
383 snprintf(manpage, sizeof(manpage), "%s/%s", mandir, dp->d_name); 383 snprintf(manpage, sizeof(manpage), "%s/%s", mandir, dp->d_name);
384 snprintf(catpage, sizeof(catpage), "%s/%s", catdir, dp->d_name); 384 snprintf(catpage, sizeof(catpage), "%s/%s", catdir, dp->d_name);
385 385
386 e_build = NULL; 386 e_build = NULL;
387 if ((buildp = gettag("_build", 1)) == NULL) 387 if ((buildp = gettag("_build", 1)) == NULL)
388 err(1, "malloc"); 388 err(1, "malloc");
389 TAILQ_FOREACH(e_build, &buildp->entrylist, q) { 389 TAILQ_FOREACH(e_build, &buildp->entrylist, q) {
390 splitentry(e_build->s, buildsuff, sizeof(buildsuff), 390 splitentry(e_build->s, buildsuff, sizeof(buildsuff),
391 buildcmd, sizeof(buildcmd)); 391 buildcmd, sizeof(buildcmd));
392 snprintf(match, sizeof(match), "*%s", 392 snprintf(match, sizeof(match), "*%s",
393 buildsuff); 393 buildsuff);
394 if (!fnmatch(match, manpage, 0)) 394 if (!fnmatch(match, manpage, 0))
395 break; 395 break;
396 } 396 }
397 397
398 if (e_build == NULL) 398 if (e_build == NULL)
399 continue; 399 continue;
400 400
401 e_crunch = NULL; 401 e_crunch = NULL;
402 if ((crunchp = gettag("_crunch", 1)) == NULL) 402 if ((crunchp = gettag("_crunch", 1)) == NULL)
403 err(1, "malloc"); 403 err(1, "malloc");
404 TAILQ_FOREACH(e_crunch, &crunchp->entrylist, q) { 404 TAILQ_FOREACH(e_crunch, &crunchp->entrylist, q) {
405 splitentry(e_crunch->s, crunchsuff, sizeof(crunchsuff), 405 splitentry(e_crunch->s, crunchsuff, sizeof(crunchsuff),
406 crunchcmd, sizeof(crunchcmd)); 406 crunchcmd, sizeof(crunchcmd));
407 snprintf(match, sizeof(match), "*%s", crunchsuff); 407 snprintf(match, sizeof(match), "*%s", crunchsuff);
408 if (!fnmatch(match, manpage, 0)) 408 if (!fnmatch(match, manpage, 0))
409 break; 409 break;
410 } 410 }
411 411
412 if (lstat(manpage, &manstat) <0) { 412 if (lstat(manpage, &manstat) <0) {
413 warn("can't stat %s", manpage); 413 warn("can't stat %s", manpage);
414 continue; 414 continue;
415 } else { 415 } else {
416 if (S_ISLNK(manstat.st_mode)) { 416 if (S_ISLNK(manstat.st_mode)) {
417 strlcpy(buffer, catpage, sizeof(buffer)); 417 strlcpy(buffer, catpage, sizeof(buffer));
418 strlcpy(linkname, basename(buffer), 418 strlcpy(linkname, basename(buffer),
419 sizeof(linkname)); 419 sizeof(linkname));
420 len = readlink(manpage, buffer, 420 len = readlink(manpage, buffer,
421 sizeof(buffer) - 1); 421 sizeof(buffer) - 1);
422 if (len == -1) { 422 if (len == -1) {
423 warn("can't stat read symbolic link %s", 423 warn("can't stat read symbolic link %s",
424 manpage); 424 manpage);
425 continue; 425 continue;
426 } 426 }
427 buffer[len] = '\0'; 427 buffer[len] = '\0';
428 428
429 if (strcmp(buffer, basename(buffer)) == 0) { 429 if (strcmp(buffer, basename(buffer)) == 0) {
430 bp = basename(buffer); 430 bp = basename(buffer);
431 strlcpy(tmp, manpage, sizeof(tmp)); 431 strlcpy(tmp, manpage, sizeof(tmp));
432 snprintf(manpage, sizeof(manpage), 432 snprintf(manpage, sizeof(manpage),
433 "%s/%s", dirname(tmp), bp); 433 "%s/%s", dirname(tmp), bp);
434 strlcpy(tmp, catpage, sizeof(tmp)); 434 strlcpy(tmp, catpage, sizeof(tmp));
435 snprintf(catpage, sizeof(catpage), 435 snprintf(catpage, sizeof(catpage),
436 "%s/%s", dirname(tmp), buffer); 436 "%s/%s", dirname(tmp), buffer);
437 } else { 437 } else {
438 *linkname = '\0'; 438 *linkname = '\0';
439 } 439 }
440 440
441 } 441 }
442 else 442 else
443 *linkname = '\0'; 443 *linkname = '\0';
444 } 444 }
445 445
446 if (!e_crunch) { 446 if (!e_crunch) {
447 *crunchsuff = *crunchcmd = '\0'; 447 *crunchsuff = *crunchcmd = '\0';
448 } 448 }
449 setcatsuffix(catpage, buildsuff, crunchsuff); 449 setcatsuffix(catpage, buildsuff, crunchsuff);
450 if (*linkname != '\0') 450 if (*linkname != '\0')
451 setcatsuffix(linkname, buildsuff, crunchsuff); 451 setcatsuffix(linkname, buildsuff, crunchsuff);
452 452
453 if (stat(manpage, &manstat) < 0) { 453 if (stat(manpage, &manstat) < 0) {
454 warn("can't stat %s", manpage); 454 warn("can't stat %s", manpage);
455 continue; 455 continue;
456 } 456 }
457 457
458 if (!S_ISREG(manstat.st_mode)) { 458 if (!S_ISREG(manstat.st_mode)) {
459 warnx("not a regular file %s", manpage); 459 warnx("not a regular file %s", manpage);
460 continue; 460 continue;
461 } 461 }
462 462
463 if ((error = stat(catpage, &catstat)) && 463 if ((error = stat(catpage, &catstat)) &&
464 errno != ENOENT) { 464 errno != ENOENT) {
465 warn("can't stat %s", catpage); 465 warn("can't stat %s", catpage);
466 continue; 466 continue;
467 } 467 }
468 468
469 if ((error && errno == ENOENT) || 469 if ((error && errno == ENOENT) ||
470 manstat.st_mtime > catstat.st_mtime) { 470 manstat.st_mtime > catstat.st_mtime) {
471 if (f_noformat) { 471 if (f_noformat) {
472 dowhatis = 1; 472 dowhatis = 1;
473 } else { 473 } else {
474 /* 474 /*
475 * reformat out of date manpage 475 * reformat out of date manpage
476 */ 476 */
477 makecat(manpage, catpage, buildcmd, crunchcmd); 477 makecat(manpage, catpage, buildcmd, crunchcmd);
478 dowhatis = 1; 478 dowhatis = 1;
479 } 479 }
480 } 480 }
481 481
482 if (*linkname != '\0') { 482 if (*linkname != '\0') {
483 strlcpy(tmp, catpage, sizeof(tmp)); 483 strlcpy(tmp, catpage, sizeof(tmp));
484 snprintf(tmp, sizeof(tmp), "%s/%s", dirname(tmp), 484 snprintf(tmp, sizeof(tmp), "%s/%s", dirname(tmp),
485 linkname); 485 linkname);
486 if ((error = lstat(tmp, &lnkstat)) && 486 if ((error = lstat(tmp, &lnkstat)) &&
487 errno != ENOENT) { 487 errno != ENOENT) {
488 warn("can't stat %s", tmp); 488 warn("can't stat %s", tmp);
489 continue; 489 continue;
490 } 490 }
491 491
492 if (error && errno == ENOENT) { 492 if (error && errno == ENOENT) {
493 if (f_noformat) { 493 if (f_noformat) {
494 dowhatis = 1; 494 dowhatis = 1;
495 } else { 495 } else {
496 /* 496 /*
497 * create symbolic link 497 * create symbolic link
498 */ 498 */
499 if (f_noprint == 0) 499 if (f_noprint == 0)
500 printf("ln -s %s %s\n", catpage, 500 printf("ln -s %s %s\n", catpage,
501 linkname); 501 linkname);
502 if (f_noaction == 0) { 502 if (f_noaction == 0) {
503 strlcpy(tmp, catpage, 503 strlcpy(tmp, catpage,
504 sizeof(tmp)); 504 sizeof(tmp));
505 if (chdir(dirname(tmp)) == -1) { 505 if (chdir(dirname(tmp)) == -1) {
506 warn("can't chdir"); 506 warn("can't chdir");
507 continue; 507 continue;
508 } 508 }
509 509
510 if (symlink(catpage, linkname) 510 if (symlink(catpage, linkname)
511 == -1) { 511 == -1) {
512 warn("can't create" 512 warn("can't create"
513 " symbolic" 513 " symbolic"
514 " link %s", 514 " link %s",
515 linkname); 515 linkname);
516 continue; 516 continue;
517 } 517 }
518 } 518 }
519 dowhatis = 1; 519 dowhatis = 1;
520 } 520 }
521 } 521 }
522 } 522 }
523 } 523 }
524 closedir(dirp); 524 closedir(dirp);
525} 525}
526 526
527static int 527static int
528splitentry(char *s, char *first, size_t firstlen, char *second,  528splitentry(char *s, char *first, size_t firstlen, char *second,
529 size_t secondlen) 529 size_t secondlen)
530{ 530{
531 char *c; 531 char *c;
532 532
533 for (c = s; *c != '\0' && !isspace((unsigned char)*c); ++c) 533 for (c = s; *c != '\0' && !isspace((unsigned char)*c); ++c)
534 ; 534 ;
535 if (*c == '\0') 535 if (*c == '\0')
536 return(0); 536 return(0);
537 if ((size_t)(c - s + 1) > firstlen) 537 if ((size_t)(c - s + 1) > firstlen)
538 return(0); 538 return(0);
539 strncpy(first, s, c-s); 539 strncpy(first, s, c-s);
540 first[c-s] = '\0'; 540 first[c-s] = '\0';
541 for (; *c != '\0' && isspace((unsigned char)*c); ++c) 541 for (; *c != '\0' && isspace((unsigned char)*c); ++c)
542 ; 542 ;
543 if (strlcpy(second, c, secondlen) >= secondlen) 543 if (strlcpy(second, c, secondlen) >= secondlen)
544 return(0); 544 return(0);
545 return(1); 545 return(1);
546} 546}
547 547
548static void 548static void
549setcatsuffix(char *catpage, const char *suffix, const char *crunchsuff) 549setcatsuffix(char *catpage, const char *suffix, const char *crunchsuff)
550{ 550{
551 TAG *tp; 551 TAG *tp;
552 char *p; 552 char *p;
553 553
554 for (p = catpage + strlen(catpage); p != catpage; p--) 554 for (p = catpage + strlen(catpage); p != catpage; p--)
555 if (!fnmatch(suffix, p, 0)) { 555 if (!fnmatch(suffix, p, 0)) {
556 if ((tp = gettag("_suffix", 1)) == NULL) 556 if ((tp = gettag("_suffix", 1)) == NULL)
557 err(1, "malloc"); 557 err(1, "malloc");
558 if (! TAILQ_EMPTY(&tp->entrylist)) { 558 if (! TAILQ_EMPTY(&tp->entrylist)) {
559 sprintf(p, "%s%s", 559 sprintf(p, "%s%s",
560 TAILQ_FIRST(&tp->entrylist)->s, crunchsuff); 560 TAILQ_FIRST(&tp->entrylist)->s, crunchsuff);
561 } else { 561 } else {
562 sprintf(p, ".0%s", crunchsuff); 562 sprintf(p, ".0%s", crunchsuff);
563 } 563 }
564 break; 564 break;
565 } 565 }
566} 566}
567 567
568static void 568static void
569makecat(const char *manpage, const char *catpage, const char *buildcmd,  569makecat(const char *manpage, const char *catpage, const char *buildcmd,
570 const char *crunchcmd) 570 const char *crunchcmd)
571{ 571{
572 char crunchbuf[1024]; 572 char crunchbuf[1024];
573 char sysbuf[2048]; 573 char sysbuf[2048 + 128];
574 size_t len; 574 size_t len;
575 575
576 len = snprintf(sysbuf, sizeof(sysbuf), buildcmd, manpage); 576 len = snprintf(sysbuf, sizeof(sysbuf), buildcmd, manpage);
577 if (len > sizeof(sysbuf)) 577 if (len > sizeof(sysbuf))
578 errx(1, "snprintf"); 578 errx(1, "snprintf");
579 579
580 if (*crunchcmd != '\0') { 580 if (*crunchcmd != '\0') {
581 snprintf(crunchbuf, sizeof(crunchbuf), crunchcmd, catpage); 581 snprintf(crunchbuf, sizeof(crunchbuf), crunchcmd, catpage);
582 snprintf(sysbuf + len, sizeof(sysbuf) - len, " | %s",  582 snprintf(sysbuf + len, sizeof(sysbuf) - len, " | %s",
583 crunchbuf); 583 crunchbuf);
584 } else { 584 } else {
585 snprintf(sysbuf + len, sizeof(sysbuf) - len, " > %s", catpage); 585 snprintf(sysbuf + len, sizeof(sysbuf) - len, " > %s", catpage);
586 } 586 }
587 587
588 if (f_noprint == 0) 588 if (f_noprint == 0)
589 printf("%s\n", sysbuf); 589 printf("%s\n", sysbuf);
590 if (f_noaction == 0) 590 if (f_noaction == 0)
591 dosystem(sysbuf); 591 dosystem(sysbuf);
592} 592}
593 593
594static void 594static void
595makewhatis(void) 595makewhatis(void)
596{ 596{
597 TAG *whatdbp; 597 TAG *whatdbp;
598 ENTRY *e_whatdb; 598 ENTRY *e_whatdb;
599 char sysbuf[1024]; 599 char sysbuf[1024];
600 600
601 if ((whatdbp = gettag("_whatdb", 1)) == NULL) 601 if ((whatdbp = gettag("_whatdb", 1)) == NULL)
602 err(1, "malloc"); 602 err(1, "malloc");
603 TAILQ_FOREACH(e_whatdb, &whatdbp->entrylist, q) { 603 TAILQ_FOREACH(e_whatdb, &whatdbp->entrylist, q) {
604 snprintf(sysbuf, sizeof(sysbuf), "%s %s", 604 snprintf(sysbuf, sizeof(sysbuf), "%s %s",
605 _PATH_MAKEWHATIS, dirname(e_whatdb->s)); 605 _PATH_MAKEWHATIS, dirname(e_whatdb->s));
606 if (f_noprint == 0) 606 if (f_noprint == 0)
607 printf("%s\n", sysbuf); 607 printf("%s\n", sysbuf);
608 if (f_noaction == 0) 608 if (f_noaction == 0)
609 dosystem(sysbuf); 609 dosystem(sysbuf);
610 } 610 }
611} 611}
612 612
613static void 613static void
614dosystem(const char *cmd) 614dosystem(const char *cmd)
615{ 615{
616 int status; 616 int status;
617 617
618 if ((status = system(cmd)) == 0) 618 if ((status = system(cmd)) == 0)
619 return; 619 return;
620 620
621 if (status == -1) 621 if (status == -1)
622 err(1, "cannot execute action"); 622 err(1, "cannot execute action");
623 if (WIFSIGNALED(status)) 623 if (WIFSIGNALED(status))
624 errx(1, "child was signaled to quit. aborting"); 624 errx(1, "child was signaled to quit. aborting");
625 if (WIFSTOPPED(status)) 625 if (WIFSTOPPED(status))
626 errx(1, "child was stopped. aborting"); 626 errx(1, "child was stopped. aborting");
627 if (f_ignerr == 0) 627 if (f_ignerr == 0)
628 errx(1, "*** Exited %d", status); 628 errx(1, "*** Exited %d", status);
629 warnx("*** Exited %d (continuing)", status); 629 warnx("*** Exited %d (continuing)", status);
630} 630}
631 631
632static void 632static void
633usage(void) 633usage(void)
634{ 634{
635 (void)fprintf(stderr, 635 (void)fprintf(stderr,
636 "usage: catman [-knpsw] [-m manpath] [sections]\n"); 636 "usage: catman [-knpsw] [-m manpath] [sections]\n");
637 (void)fprintf(stderr, 637 (void)fprintf(stderr,
638 " catman [-knpsw] [-M manpath] [sections]\n"); 638 " catman [-knpsw] [-M manpath] [sections]\n");
639 exit(1); 639 exit(1);
640} 640}