/* * straycats.c: find and process stray cat files * * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) * Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007, 2008, 2010, 2011 * Colin Watson. * * This file is part of man-db. * * man-db is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * man-db is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with man-db; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Tue May 3 21:24:51 BST 1994 Wilf. (G.Wilford@ee.surrey.ac.uk) */ #ifdef HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include #include #include "canonicalize.h" #include "dirname.h" #include "gettext.h" #define _(String) gettext (String) #include "manconfig.h" #include "error.h" #include "pipeline.h" #include "decompress.h" #include "encodings.h" #include "orderfiles.h" #include "security.h" #include "mydbm.h" #include "db_storage.h" #include "descriptions.h" #include "manp.h" #include "manconv_client.h" #include "ult_src.h" static char *catdir, *mandir; static int check_for_stray (MYDBM_FILE dbf) { DIR *cdir; struct dirent *catlist; char **names; size_t names_len, names_max, i; size_t lenman, lencat; int strays = 0; cdir = opendir (catdir); if (!cdir) { error (0, errno, _("can't search directory %s"), catdir); return 0; } names_len = 0; names_max = 1024; names = XNMALLOC (names_max, char *); while ((catlist = readdir (cdir)) != NULL) { if (*catlist->d_name == '.' && strlen (catlist->d_name) < (size_t) 3) continue; if (names_len >= names_max) { names_max *= 2; names = xnrealloc (names, names_max, sizeof (char *)); } names[names_len++] = xstrdup (catlist->d_name); } closedir (cdir); order_files (catdir, names, names_len); mandir = appendstr (mandir, "/", NULL); catdir = appendstr (catdir, "/", NULL); lenman = strlen (mandir); lencat = strlen (catdir); for (i = 0; i < names_len; ++i) { struct mandata info; char *ext, *section; short found; struct stat buf; #ifdef COMP_SRC struct compression *comp; #endif memset (&info, 0, sizeof (struct mandata)); *(mandir + lenman) = *(catdir + lencat) = '\0'; mandir = appendstr (mandir, names[i], NULL); catdir = appendstr (catdir, names[i], NULL); ext = strrchr (mandir, '.'); if (!ext) { if (quiet < 2) error (0, 0, _("warning: %s: " "ignoring bogus filename"), catdir); goto next_name; #if defined(COMP_SRC) || defined(COMP_CAT) # if defined(COMP_SRC) } else if (comp_info (ext, 0)) { # elif defined(COMP_CAT) } else if (strcmp (ext + 1, COMPRESS_EXT) == 0) { # endif /* COMP_* */ *ext = '\0'; info.comp = ext + 1; #endif /* COMP_SRC || COMP_CAT */ } else info.comp = NULL; ext = strrchr (mandir, '.'); *(mandir + lenman - 1) = '\0'; section = xstrdup (strrchr (mandir, '/') + 4); *(mandir + lenman - 1) = '/'; /* check for bogosity */ if (!ext || strncmp (ext + 1, section, strlen (section)) != 0) { if (quiet < 2) error (0, 0, _("warning: %s: " "ignoring bogus filename"), catdir); goto next_section; } /* * now that we've stripped off the cat compression * extension (if it has one), we can try some of ours. */ debug ("Testing for existence: %s\n", mandir); if (stat (mandir, &buf) == 0) found = 1; #ifdef COMP_SRC else if ((comp = comp_file (mandir))) { found = 1; free (comp->stem); } #endif else found = 0; if (!found) { pipeline *decomp; struct mandata *exists; lexgrog lg; char *lang, *page_encoding; char *mandir_base; pipecmd *col_cmd; char *col_locale; char *fullpath; /* we have a straycat. Need to filter it and get its whatis (if necessary) */ lg.whatis = 0; *(ext++) = '\0'; info.ext = ext; /* see if we already have it, before going any further */ mandir_base = base_name (mandir); exists = dblookup_exact (dbf, mandir_base, info.ext, 1); #ifndef FAVOUR_STRAYCATS if (exists && exists->id != WHATIS_CAT) #else /* FAVOUR_STRAYCATS */ if (exists && exists->id != WHATIS_CAT && exists->id != WHATIS_MAN) #endif /* !FAVOUR_STRAYCATS */ goto next_exists; debug ("%s(%s) is not in the db.\n", mandir_base, info.ext); /* fill in the missing parts of the structure */ info.name = NULL; info.sec = section; info.id = STRAY_CAT; info.pointer = NULL; info.filter = "-"; info.mtime.tv_sec = 0; info.mtime.tv_nsec = 0; drop_effective_privs (); decomp = decompress_open (catdir); regain_effective_privs (); if (!decomp) { error (0, errno, _("can't open %s"), catdir); goto next_exists; } lang = lang_dir (mandir); page_encoding = get_page_encoding (lang); if (page_encoding) add_manconv (decomp, page_encoding, "UTF-8"); free (page_encoding); free (lang); col_cmd = pipecmd_new_argstr (get_def_user ("col", COL)); pipecmd_arg (col_cmd, "-bx"); col_locale = find_charset_locale ("UTF-8"); if (col_locale) { pipecmd_setenv (col_cmd, "LC_CTYPE", col_locale); free (col_locale); } pipeline_command (decomp, col_cmd); fullpath = canonicalize_file_name (catdir); if (!fullpath) { if (quiet < 2) { if (errno == ENOENT) error (0, 0, _("warning: %s is a dangling symlink"), fullpath); else error (0, errno, _("can't resolve %s"), catdir); } } else { char *catdir_base; free (fullpath); drop_effective_privs (); pipeline_start (decomp); regain_effective_privs (); strays++; lg.type = CATPAGE; catdir_base = base_name (catdir); if (find_name_decompressed (decomp, catdir_base, &lg)) { struct page_description *descs; strays++; descs = parse_descriptions (mandir_base, lg.whatis); if (descs) { store_descriptions (dbf, descs, &info, NULL, mandir_base, NULL); free_descriptions (descs); } } else if (quiet < 2) error (0, 0, _("warning: %s: whatis parse for %s(%s) failed"), catdir, mandir_base, info.sec); free (catdir_base); } if (lg.whatis) free (lg.whatis); pipeline_free (decomp); next_exists: free_mandata_struct (exists); free (mandir_base); } next_section: free (section); next_name: free (names[i]); } free (names); return strays; } static int open_catdir (MYDBM_FILE dbf) { DIR *cdir; struct dirent *catlist; size_t catlen, manlen; int strays = 0; cdir = opendir (catdir); if (!cdir) { error (0, errno, _("can't search directory %s"), catdir); return 0; } if (!quiet) printf (_("Checking for stray cats under %s...\n"), catdir); catdir = appendstr (catdir, "/", NULL); mandir = appendstr (mandir, "/", NULL); catlen = strlen (catdir); manlen = strlen (mandir); /* should make this case insensitive */ while ((catlist = readdir (cdir))) { char *t1; if (strncmp (catlist->d_name, "cat", 3) != 0) continue; catdir = appendstr (catdir, catlist->d_name, NULL); mandir = appendstr (mandir, catlist->d_name, NULL); *(t1 = mandir + manlen) = 'm'; *(t1 + 2) = 'n'; strays += check_for_stray (dbf); *(catdir + catlen) = *(mandir + manlen) = '\0'; } closedir (cdir); return strays; } int straycats (const char *manpath) { MYDBM_FILE dbf; char *catpath; int strays; dbf = MYDBM_RWOPEN (database); if (dbf && dbver_rd (dbf)) { MYDBM_CLOSE (dbf); dbf = NULL; } if (!dbf) { error (0, errno, _("warning: can't update index cache %s"), database); return 0; } catpath = get_catpath (manpath, SYSTEM_CAT | USER_CAT); /* look in the usual catpath location */ mandir = xstrdup (manpath); catdir = xstrdup (manpath); strays = open_catdir (dbf); /* look in the alternate catpath location if we have one and it's different from the usual catpath */ if (catpath) debug ("catpath: %s, manpath: %s\n", catpath, manpath); if (catpath && strcmp (catpath, manpath) != 0) { *mandir = *catdir = '\0'; mandir = appendstr (mandir, manpath, NULL); catdir = appendstr (catdir, catpath, NULL); strays += open_catdir (dbf); } free (mandir); free (catdir); if (catpath) free (catpath); MYDBM_CLOSE (dbf); return strays; }