1 /* $Id: catman.c,v 1.11.2.2 2013/10/11 00:06:48 schwarze Exp $ */
3 * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #include <sys/param.h>
34 #if defined(__linux__) || defined(__sun)
43 #define xstrlcpy(_dst, _src, _sz) \
44 do if (strlcpy((_dst), (_src), (_sz)) >= (_sz)) { \
45 fprintf(stderr, "%s: Path too long", (_dst)); \
47 } while (/* CONSTCOND */0)
49 #define xstrlcat(_dst, _src, _sz) \
50 do if (strlcat((_dst), (_src), (_sz)) >= (_sz)) { \
51 fprintf(stderr, "%s: Path too long", (_dst)); \
53 } while (/* CONSTCOND */0)
55 static int indexhtml(char *, size_t, char *, size_t);
56 static int manup(const struct manpaths
*, char *);
57 static int mkpath(char *, mode_t
, mode_t
);
58 static int treecpy(char *, char *);
59 static int update(char *, char *);
60 static void usage(void);
62 static const char *progname
;
67 main(int argc
, char *argv
[])
70 char *aux
, *base
, *conf_file
;
76 progname
= strrchr(argv
[0], '/');
82 aux
= base
= conf_file
= NULL
;
83 xstrlcpy(buf
, "/var/www/cache/man.cgi", MAXPATHLEN
);
85 while (-1 != (ch
= getopt(argc
, argv
, "C:fm:M:o:v")))
100 xstrlcpy(buf
, optarg
, MAXPATHLEN
);
107 return(EXIT_FAILURE
);
115 return(EXIT_FAILURE
);
118 memset(&dirs
, 0, sizeof(struct manpaths
));
119 manpath_parse(&dirs
, conf_file
, base
, aux
);
120 ch
= manup(&dirs
, buf
);
122 return(ch
? EXIT_SUCCESS
: EXIT_FAILURE
);
129 fprintf(stderr
, "usage: %s "
139 * If "src" file doesn't exist (errors out), return -1. Otherwise,
140 * return 1 if "src" is newer (which also happens "dst" doesn't exist)
144 isnewer(const char *dst
, const char *src
)
148 if (-1 == stat(src
, &s1
))
153 return(-1 == stat(dst
, &s2
) ? 1 : s1
.st_mtime
> s2
.st_mtime
);
157 * Copy the contents of one file into another.
158 * Returns 0 on failure, 1 on success.
161 filecpy(const char *dst
, const char *src
)
170 if (-1 == (dfd
= open(dst
, O_CREAT
|O_TRUNC
|O_WRONLY
, 0644))) {
173 } else if (-1 == (sfd
= open(src
, O_RDONLY
, 0))) {
178 while ((rsz
= read(sfd
, buf
, BUFSIZ
)) > 0)
179 if (-1 == (wsz
= write(dfd
, buf
, (size_t)rsz
))) {
182 } else if (wsz
< rsz
) {
183 fprintf(stderr
, "%s: Short write\n", dst
);
201 * Pass over the recno database and re-create HTML pages if they're
202 * found to be out of date.
203 * Returns -1 on fatal error, 1 on success.
206 indexhtml(char *src
, size_t ssz
, char *dst
, size_t dsz
)
214 char fname
[MAXPATHLEN
];
216 xstrlcpy(fname
, dst
, MAXPATHLEN
);
217 xstrlcat(fname
, "/", MAXPATHLEN
);
218 xstrlcat(fname
, MANDOC_IDX
, MAXPATHLEN
);
220 idx
= dbopen(fname
, O_RDONLY
, 0, DB_RECNO
, NULL
);
227 while (0 == (c
= (*idx
->seq
)(idx
, &key
, &val
, fl
))) {
230 * If the record is zero-length, then it's unassigned.
236 f
= (const char *)val
.data
+ 1;
237 if (NULL
== memchr(f
, '\0', val
.size
- 1))
240 src
[(int)ssz
] = dst
[(int)dsz
] = '\0';
242 xstrlcat(dst
, "/", MAXPATHLEN
);
243 xstrlcat(dst
, f
, MAXPATHLEN
);
245 xstrlcat(src
, "/", MAXPATHLEN
);
246 xstrlcat(src
, f
, MAXPATHLEN
);
248 if (-1 == (rc
= isnewer(dst
, src
))) {
249 fprintf(stderr
, "%s: File missing\n", f
);
254 d
= strrchr(dst
, '/');
258 if (-1 == mkpath(dst
, 0755, 0755)) {
265 if ( ! filecpy(dst
, src
))
276 fprintf(stderr
, "%s: Corrupt index\n", fname
);
278 return(1 == c
? 1 : -1);
282 * Copy both recno and btree databases into the destination.
283 * Call in to begin recreating HTML files.
284 * Return -1 on fatal error and 1 if the update went well.
287 update(char *dst
, char *src
)
294 xstrlcat(src
, "/", MAXPATHLEN
);
295 xstrlcat(dst
, "/", MAXPATHLEN
);
297 xstrlcat(src
, MANDOC_DB
, MAXPATHLEN
);
298 xstrlcat(dst
, MANDOC_DB
, MAXPATHLEN
);
300 if ( ! filecpy(dst
, src
))
305 dst
[(int)dsz
] = src
[(int)ssz
] = '\0';
307 xstrlcat(src
, "/", MAXPATHLEN
);
308 xstrlcat(dst
, "/", MAXPATHLEN
);
310 xstrlcat(src
, MANDOC_IDX
, MAXPATHLEN
);
311 xstrlcat(dst
, MANDOC_IDX
, MAXPATHLEN
);
313 if ( ! filecpy(dst
, src
))
318 dst
[(int)dsz
] = src
[(int)ssz
] = '\0';
320 return(indexhtml(src
, ssz
, dst
, dsz
));
324 * See if btree or recno databases in the destination are out of date
325 * with respect to a single manpath component.
326 * Return -1 on fatal error, 0 if the source is no longer valid (and
327 * shouldn't be listed), and 1 if the update went well.
330 treecpy(char *dst
, char *src
)
338 xstrlcat(src
, "/", MAXPATHLEN
);
339 xstrlcat(dst
, "/", MAXPATHLEN
);
341 xstrlcat(src
, MANDOC_IDX
, MAXPATHLEN
);
342 xstrlcat(dst
, MANDOC_IDX
, MAXPATHLEN
);
344 if (-1 == (rc
= isnewer(dst
, src
)))
347 dst
[(int)dsz
] = src
[(int)ssz
] = '\0';
350 return(update(dst
, src
));
352 xstrlcat(src
, "/", MAXPATHLEN
);
353 xstrlcat(dst
, "/", MAXPATHLEN
);
355 xstrlcat(src
, MANDOC_DB
, MAXPATHLEN
);
356 xstrlcat(dst
, MANDOC_DB
, MAXPATHLEN
);
358 if (-1 == (rc
= isnewer(dst
, src
)))
363 dst
[(int)dsz
] = src
[(int)ssz
] = '\0';
365 return(update(dst
, src
));
369 * Update the destination's file-tree with respect to changes in the
370 * source manpath components.
371 * "Change" is defined by an updated index or btree database.
372 * Returns 1 on success, 0 on failure.
375 manup(const struct manpaths
*dirs
, char *base
)
377 char dst
[MAXPATHLEN
],
385 /* Create the path and file for the catman.conf file. */
388 xstrlcpy(dst
, base
, MAXPATHLEN
);
389 xstrlcat(dst
, "/etc", MAXPATHLEN
);
390 if (-1 == mkpath(dst
, 0755, 0755)) {
395 xstrlcat(dst
, "/catman.conf", MAXPATHLEN
);
396 if (NULL
== (f
= fopen(dst
, "w"))) {
402 for (i
= 0; i
< dirs
->sz
; i
++) {
403 path
= dirs
->paths
[i
];
405 xstrlcat(dst
, path
, MAXPATHLEN
);
406 if (-1 == mkpath(dst
, 0755, 0755)) {
411 xstrlcpy(src
, path
, MAXPATHLEN
);
412 if (-1 == (c
= treecpy(dst
, src
)))
418 * We want to use a relative path here because manpath.h
419 * will realpath() when invoked with man.cgi, and we'll
420 * make sure to chdir() into the cache directory before.
422 * This allows the cache directory to be in an arbitrary
423 * place, working in both chroot() and non-chroot()
426 assert('/' == path
[0]);
427 fprintf(f
, "_whatdb %s/whatis.db\n", path
+ 1);
431 return(i
== dirs
->sz
);
435 * Copyright (c) 1983, 1992, 1993
436 * The Regents of the University of California. All rights reserved.
438 * Redistribution and use in source and binary forms, with or without
439 * modification, are permitted provided that the following conditions
441 * 1. Redistributions of source code must retain the above copyright
442 * notice, this list of conditions and the following disclaimer.
443 * 2. Redistributions in binary form must reproduce the above copyright
444 * notice, this list of conditions and the following disclaimer in the
445 * documentation and/or other materials provided with the distribution.
446 * 3. Neither the name of the University nor the names of its contributors
447 * may be used to endorse or promote products derived from this software
448 * without specific prior written permission.
450 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
451 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
452 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
453 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
454 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
455 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
456 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
457 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
458 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
459 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
463 mkpath(char *path
, mode_t mode
, mode_t dir_mode
)
473 slash
+= strspn(slash
, "/");
475 slash
+= strcspn(slash
, "/");
477 done
= (*slash
== '\0');
480 /* skip existing path components */
481 exists
= !stat(path
, &sb
);
482 if (!done
&& exists
&& S_ISDIR(sb
.st_mode
)) {
487 if (mkdir(path
, done
? mode
: dir_mode
) == 0) {
488 if (mode
> 0777 && chmod(path
, mode
) < 0)
495 if (!S_ISDIR(sb
.st_mode
)) {
496 /* Is there, but isn't a directory */