(root)/
man-db-2.12.0/
src/
straycats.c
       1  /*
       2   * straycats.c: find and process stray cat files
       3   *
       4   * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.)
       5   * Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007, 2008, 2010, 2011
       6   *               Colin Watson.
       7   *
       8   * This file is part of man-db.
       9   *
      10   * man-db is free software; you can redistribute it and/or modify it
      11   * under the terms of the GNU General Public License as published by
      12   * the Free Software Foundation; either version 2 of the License, or
      13   * (at your option) any later version.
      14   *
      15   * man-db is distributed in the hope that it will be useful, but
      16   * WITHOUT ANY WARRANTY; without even the implied warranty of
      17   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18   * GNU General Public License for more details.
      19   *
      20   * You should have received a copy of the GNU General Public License
      21   * along with man-db; if not, write to the Free Software Foundation,
      22   * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      23   *
      24   * Tue May  3 21:24:51 BST 1994 Wilf. (G.Wilford@ee.surrey.ac.uk)
      25   */
      26  
      27  #ifdef HAVE_CONFIG_H
      28  #  include "config.h"
      29  #endif /* HAVE_CONFIG_H */
      30  
      31  #include <assert.h>
      32  #include <stdbool.h>
      33  #include <string.h>
      34  #include <stdlib.h>
      35  #include <stdio.h>
      36  #include <signal.h>
      37  #include <errno.h>
      38  #include <sys/types.h>
      39  #include <sys/stat.h>
      40  #include <unistd.h>
      41  #include <dirent.h>
      42  
      43  #include "canonicalize.h"
      44  #include "dirname.h"
      45  #include "error.h"
      46  #include "gl_array_list.h"
      47  #include "gl_xlist.h"
      48  #include "xalloc.h"
      49  
      50  #include "gettext.h"
      51  #define _(String) gettext (String)
      52  
      53  #include "manconfig.h"
      54  
      55  #include "appendstr.h"
      56  #include "compression.h"
      57  #include "debug.h"
      58  #include "filenames.h"
      59  #include "glcontainers.h"
      60  #include "pipeline.h"
      61  #include "decompress.h"
      62  #include "encodings.h"
      63  #include "orderfiles.h"
      64  #include "sandbox.h"
      65  #include "security.h"
      66  #include "util.h"
      67  
      68  #include "mydbm.h"
      69  #include "db_storage.h"
      70  
      71  #include "descriptions.h"
      72  #include "lexgrog.h"
      73  #include "manp.h"
      74  #include "manconv_client.h"
      75  #include "straycats.h"
      76  #include "ult_src.h"
      77  
      78  extern man_sandbox *sandbox;
      79  
      80  static char *catdir, *mandir;
      81  
      82  static int check_for_stray (MYDBM_FILE dbf)
      83  {
      84  	DIR *cdir;
      85  	struct dirent *catlist;
      86  	gl_list_t names;
      87  	const char *name;
      88  	size_t lenman, lencat;
      89  	int strays = 0;
      90  
      91  	cdir = opendir (catdir);
      92  	if (!cdir) {
      93  		error (0, errno, _("can't search directory %s"), catdir);
      94  		return 0;
      95  	}
      96  
      97  	names = new_string_list (GL_ARRAY_LIST, false);
      98  
      99  	while ((catlist = readdir (cdir)) != NULL) {
     100  		if (*catlist->d_name == '.' &&
     101  		    strlen (catlist->d_name) < (size_t) 3)
     102  			continue;
     103  		gl_list_add_last (names, xstrdup (catlist->d_name));
     104  	}
     105  	closedir (cdir);
     106  
     107  	order_files (catdir, &names);
     108  
     109  	mandir = appendstr (mandir, "/", (void *) 0);
     110  	catdir = appendstr (catdir, "/", (void *) 0);
     111  	lenman = strlen (mandir);
     112  	lencat = strlen (catdir);
     113  
     114  	GL_LIST_FOREACH (names, name) {
     115  		struct mandata *info;
     116  		char *ext, *section = NULL;
     117  		short found;
     118  		struct stat buf;
     119  		struct compression *comp;
     120  
     121  		info = XZALLOC (struct mandata);
     122  
     123  		*(mandir + lenman) = *(catdir + lencat) = '\0';
     124  		mandir = appendstr (mandir, name, (void *) 0);
     125  		catdir = appendstr (catdir, name, (void *) 0);
     126  
     127  		ext = strrchr (mandir, '.');
     128  		if (!ext) {
     129  			if (quiet < 2)
     130  				error (0, 0,
     131  				       _("warning: %s: "
     132  					 "ignoring bogus filename"),
     133  				       catdir);
     134  			goto next;
     135  		} else if (comp_info (ext, false)) {
     136  			*ext = '\0';
     137  			info->comp = xstrdup (ext + 1);
     138  		}
     139  
     140  		ext = strrchr (mandir, '.');
     141  		*(mandir + lenman - 1) = '\0';
     142  		section = xstrdup (strrchr (mandir, '/') + 4);
     143  		*(mandir + lenman - 1) = '/';
     144  
     145  		/* check for bogosity */
     146  
     147  		if (!ext || strncmp (ext + 1, section, strlen (section)) != 0) {
     148  			if (quiet < 2)
     149  				error (0, 0,
     150  				       _("warning: %s: "
     151  					 "ignoring bogus filename"),
     152  				       catdir);
     153  			goto next;
     154  		}
     155  
     156  		/*
     157  		 * now that we've stripped off the cat compression
     158  		 * extension (if it has one), we can try some of ours.
     159  		 */
     160  
     161  		debug ("Testing for existence: %s\n", mandir);
     162  
     163  		if (stat (mandir, &buf) == 0)
     164  			found = 1;
     165  		else if ((comp = comp_file (mandir))) {
     166  			found = 1;
     167  			free (comp->stem);
     168  		} else
     169  			found = 0;
     170  
     171  		if (!found) {
     172  			decompress *decomp;
     173  			struct mandata *exists;
     174  			lexgrog lg;
     175  			char *lang, *page_encoding;
     176  			char *mandir_base;
     177  			pipecmd *col_cmd;
     178  			char *col_locale;
     179  			char *fullpath;
     180  
     181  			/* we have a straycat. Need to filter it and get
     182  			   its whatis (if necessary)  */
     183  
     184  			lg.whatis = 0;
     185  			*(ext++) = '\0';
     186  			info->ext = xstrdup (ext);
     187  
     188  			/* see if we already have it, before going any
     189  			   further */
     190  			mandir_base = base_name (mandir);
     191  			exists = dblookup_exact (dbf, mandir_base, info->ext,
     192  						 true);
     193  			if (exists &&
     194  			    compare_ids (STRAY_CAT, exists->id, false) >= 0)
     195  				goto next_exists;
     196  			debug ("%s(%s) is not in the db.\n",
     197  			       mandir_base, info->ext);
     198  
     199  			/* fill in the missing parts of the structure */
     200  			info->sec = xstrdup (section);
     201  			info->id = STRAY_CAT;
     202  			info->filter = xstrdup ("-");
     203  			info->mtime.tv_sec = 0;
     204  			info->mtime.tv_nsec = 0;
     205  
     206  			drop_effective_privs ();
     207  			decomp = decompress_open (catdir, 0);
     208  			regain_effective_privs ();
     209  			if (!decomp) {
     210  				error (0, errno, _("can't open %s"), catdir);
     211  				goto next_exists;
     212  			}
     213  
     214  			lang = lang_dir (mandir);
     215  			page_encoding = get_page_encoding (lang);
     216  			if (page_encoding)
     217  				add_manconv (decompress_get_pipeline (decomp),
     218  					     page_encoding, "UTF-8");
     219  			free (page_encoding);
     220  			free (lang);
     221  
     222  			col_cmd = pipecmd_new_argstr
     223  				(get_def_user ("col", PROG_COL));
     224  			pipecmd_arg (col_cmd, "-bx");
     225  			col_locale = find_charset_locale ("UTF-8");
     226  			if (col_locale) {
     227  				pipecmd_setenv (col_cmd, "LC_CTYPE",
     228  						col_locale);
     229  				free (col_locale);
     230  			}
     231  			pipecmd_pre_exec (col_cmd, sandbox_load, sandbox_free,
     232  					  sandbox);
     233  			pipeline_command (decompress_get_pipeline (decomp),
     234  					  col_cmd);
     235  
     236  			fullpath = canonicalize_file_name (catdir);
     237  			if (!fullpath)
     238  				gripe_canonicalize_failed (catdir);
     239  			else {
     240  				char *catdir_base;
     241  
     242  				free (fullpath);
     243  				drop_effective_privs ();
     244  				decompress_start (decomp);
     245  				regain_effective_privs ();
     246  
     247  				strays++;
     248  
     249  				lg.type = CATPAGE;
     250  				catdir_base = base_name (catdir);
     251  				if (find_name_decompressed (decomp,
     252  							    catdir_base,
     253  							    &lg)) {
     254  					gl_list_t descs, trace;
     255  					strays++;
     256  					descs = parse_descriptions
     257  						(mandir_base, lg.whatis);
     258  					trace = new_string_list (GL_ARRAY_LIST,
     259  								 true);
     260  					gl_list_add_last (trace,
     261  							  xstrdup (catdir));
     262  					store_descriptions (dbf, descs, info,
     263  							    NULL, mandir_base,
     264  							    trace);
     265  					gl_list_free (trace);
     266  					gl_list_free (descs);
     267  				} else if (quiet < 2)
     268  					error (0, 0, _("warning: %s: whatis parse for %s(%s) failed"),
     269  					       catdir, mandir_base, info->sec);
     270  				free (catdir_base);
     271  			}
     272  
     273  			free (lg.whatis);
     274  			decompress_free (decomp);
     275  next_exists:
     276  			free_mandata_struct (exists);
     277  			free (mandir_base);
     278  		}
     279  next:
     280  		free (section);
     281  		free_mandata_struct (info);
     282  	}
     283  	gl_list_free (names);
     284  	return strays;
     285  }
     286  
     287  static int open_catdir (MYDBM_FILE dbf)
     288  {
     289  	DIR *cdir;
     290  	struct dirent *catlist;
     291  	size_t catlen, manlen;
     292  	int strays = 0;
     293  
     294  	cdir = opendir (catdir);
     295  	if (!cdir) {
     296  		error (0, errno, _("can't search directory %s"), catdir);
     297  		return 0;
     298  	}
     299  
     300  	if (!quiet)
     301  		printf (_("Checking for stray cats under %s...\n"), catdir);
     302  
     303  	catdir = appendstr (catdir, "/", (void *) 0);
     304  	mandir = appendstr (mandir, "/", (void *) 0);
     305  	catlen = strlen (catdir);
     306  	manlen = strlen (mandir);
     307  
     308  	/* should make this case insensitive */
     309  	while ((catlist = readdir (cdir))) {
     310  		char *t1;
     311  
     312  		if (strncmp (catlist->d_name, "cat", 3) != 0)
     313  			continue;
     314  
     315  		catdir = appendstr (catdir, catlist->d_name, (void *) 0);
     316  		mandir = appendstr (mandir, catlist->d_name, (void *) 0);
     317  
     318  		*(t1 = mandir + manlen) = 'm';
     319  		*(t1 + 2) = 'n';
     320  
     321  		strays += check_for_stray (dbf);
     322  
     323  		*(catdir + catlen) = *(mandir + manlen) = '\0';
     324  	}
     325  	closedir (cdir);
     326  	return strays;
     327  }
     328  
     329  int straycats (MYDBM_FILE dbf, const char *manpath)
     330  {
     331  	char *catpath;
     332  	int strays;
     333  
     334  	assert (dbf->file);
     335  
     336  	catpath = get_catpath (manpath, SYSTEM_CAT | USER_CAT);
     337  
     338  	/* look in the usual catpath location */
     339  	mandir = xstrdup (manpath);
     340  	catdir = xstrdup (manpath);
     341  	strays = open_catdir (dbf);
     342  
     343  	/* look in the alternate catpath location if we have one
     344  	   and it's different from the usual catpath */
     345  
     346  	if (catpath)
     347  		debug ("catpath: %s, manpath: %s\n", catpath, manpath);
     348  
     349  	if (catpath && strcmp (catpath, manpath) != 0) {
     350  		*mandir = *catdir = '\0';
     351  		mandir = appendstr (mandir, manpath, (void *) 0);
     352  		catdir = appendstr (catdir, catpath, (void *) 0);
     353  		strays += open_catdir (dbf);
     354  	}
     355  
     356  	free (mandir);
     357  	free (catdir);
     358  
     359  	free (catpath);
     360  
     361  	return strays;
     362  }