(root)/
man-db-2.12.0/
lib/
util.c
       1  /*
       2   * util.c
       3   *
       4   * Copyright (C) 1990, 1991 John W. Eaton.
       5   * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.)
       6   * Copyright (C) 2001, 2002, 2004, 2007, 2008, 2010 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   * John W. Eaton
      25   * jwe@che.utexas.edu
      26   * Department of Chemical Engineering
      27   * The University of Texas at Austin
      28   * Austin, Texas  78712
      29   *
      30   * Wed May  4 15:44:47 BST 1994 Wilf. (G.Wilford@ee.surrey.ac.uk): slight
      31   * changes to all routines, mainly cosmetic.
      32   */
      33  
      34  #ifdef HAVE_CONFIG_H
      35  #  include "config.h"
      36  #endif /* HAVE_CONFIG_H */
      37  
      38  #include <assert.h>
      39  #include <stdbool.h>
      40  #include <string.h>
      41  #include <stdlib.h>
      42  #include <stdio.h>
      43  #include <sys/types.h>
      44  #include <sys/stat.h>
      45  #include <dirent.h>
      46  #include <unistd.h>
      47  #include <locale.h>
      48  
      49  #include "attribute.h"
      50  #include "stat-time.h"
      51  #include "timespec.h"
      52  #include "xalloc.h"
      53  #include "xstrndup.h"
      54  #include "xvasprintf.h"
      55  
      56  #include "gettext.h"
      57  
      58  #include "manconfig.h"
      59  
      60  #include "debug.h"
      61  #include "error.h"
      62  #include "util.h"
      63  
      64  /*
      65   * Does file a have a different timestamp to file b?
      66   *
      67   * case:
      68   *
      69   *   a is man_page, b is cat_page
      70   *
      71   *   a and b have different times  returns  1/3  (ret & 1) == 1
      72   *   a and b have same times       returns  0/2  (!(ret & 1)) == 1
      73   *   a is zero in length           returns  + 2 (for Wilf. and his stray cats)
      74   *   b is zero in length           returns  + 4
      75   *   stat on a fails               returns   -1
      76   *   stat on b fails               returns   -2
      77   *   stat on a and b fails         returns   -3
      78   */
      79  int is_changed (const char *fa, const char *fb)
      80  {
      81  	struct stat fa_sb;
      82  	struct stat fb_sb;
      83  	int fa_stat;
      84  	int fb_stat;
      85  	int status = 0;
      86  
      87  	debug ("is_changed: a=%s, b=%s", fa, fb);
      88  
      89  	fa_stat = stat (fa, &fa_sb);
      90  	if (fa_stat != 0)
      91  		status = 1;
      92  
      93  	fb_stat = stat (fb, &fb_sb);
      94  	if (fb_stat != 0)
      95  		status |= 2;
      96  
      97  	if (status != 0) {
      98  		debug (" (%d)\n", -status);
      99  		return -status;
     100  	}
     101  
     102  	if (fa_sb.st_size == 0)
     103  		status |= 2;
     104  
     105  	if (fb_sb.st_size == 0)
     106  		status |= 4;
     107  
     108  	status |= (timespec_cmp (get_stat_mtime (&fa_sb),
     109  				 get_stat_mtime (&fb_sb)) != 0);
     110  
     111  	debug (" (%d)\n", status);
     112  	return status;
     113  }
     114  
     115  /*
     116   * Is path a directory?
     117   */
     118  int is_directory (const char *path)
     119  {
     120  	struct stat sb;
     121  	int status;
     122  
     123  	status = stat (path, &sb);
     124  
     125  	if (status != 0)
     126  		return status;
     127  
     128  	return ((sb.st_mode & S_IFDIR) != 0);
     129  }
     130  
     131  /* Escape dangerous metacharacters before dumping into a shell command. */
     132  char *escape_shell (const char *unesc)
     133  {
     134  	char *esc, *escp;
     135  	const char *unescp;
     136  
     137  	if (!unesc)
     138  		return NULL;
     139  
     140  	escp = esc = xmalloc (strlen (unesc) * 2 + 1);
     141  	for (unescp = unesc; *unescp; unescp++)
     142  		if ((*unescp >= '0' && *unescp <= '9') ||
     143  		    (*unescp >= 'A' && *unescp <= 'Z') ||
     144  		    (*unescp >= 'a' && *unescp <= 'z') ||
     145  		    strchr (",-./:@_", *unescp))
     146  			*escp++ = *unescp;
     147  		else {
     148  			*escp++ = '\\';
     149  			*escp++ = *unescp;
     150  		}
     151  	*escp = 0;
     152  	return esc;
     153  }
     154  
     155  /* Remove a directory and all files in it.  Only recurse beyond that if
     156   * RECURSE is set.
     157   */
     158  int remove_directory (const char *directory, bool recurse)
     159  {
     160  	DIR *handle = opendir (directory);
     161  	struct dirent *entry;
     162  
     163  	if (!handle)
     164  		return -1;
     165  	while ((entry = readdir (handle)) != NULL) {
     166  		struct stat st;
     167  		char *path;
     168  
     169  		if (STREQ (entry->d_name, ".") || STREQ (entry->d_name, ".."))
     170  			continue;
     171  		path = xasprintf ("%s/%s", directory, entry->d_name);
     172  		assert (path);
     173  		if (stat (path, &st) == -1) {
     174  			free (path);
     175  			closedir (handle);
     176  			return -1;
     177  		}
     178  		if (recurse && S_ISDIR (st.st_mode)) {
     179  			if (remove_directory (path, recurse) == -1) {
     180  				free (path);
     181  				closedir (handle);
     182  				return -1;
     183  			}
     184  		} else if (S_ISREG (st.st_mode)) {
     185  			if (unlink (path) == -1) {
     186  				free (path);
     187  				closedir (handle);
     188  				return -1;
     189  			}
     190  		}
     191  		free (path);
     192  	}
     193  	closedir (handle);
     194  
     195  	if (rmdir (directory) == -1)
     196  		return -1;
     197  	return 0;
     198  }
     199  
     200  /* Returns an allocated copy of s, with leading and trailing spaces
     201   * removed.
     202   */
     203  char * ATTRIBUTE_MALLOC trim_spaces (const char *s)
     204  {
     205  	int length;
     206  	while (*s == ' ')
     207  		++s;
     208  	length = strlen (s);
     209  	while (length && s[length - 1] == ' ')
     210  		--length;
     211  	return xstrndup (s, length);
     212  }
     213  
     214  char *lang_dir (const char *filename)
     215  {
     216  	char *ld;	/* the lang dir: point to static data */
     217  	const char *fm;	/* the first "/man/" dir */
     218  	const char *sm;	/* the second "/man?/" dir */
     219  
     220  	ld = xstrdup ("");
     221  	if (!filename)
     222  		return ld;
     223  
     224  	/* Check whether filename is in a man page hierarchy. */
     225  	if (STRNEQ (filename, "man/", 4))
     226  		fm = filename;
     227  	else {
     228  		fm = strstr (filename, "/man/");
     229  		if (fm)
     230  			++fm;
     231  	}
     232  	if (!fm)
     233  		return ld;
     234  	sm = strstr (fm + 2, "/man");
     235  	if (!sm)
     236  		return ld;
     237  	if (sm[5] != '/')
     238  		return ld;
     239  	if (!strchr ("123456789lno", sm[4]))
     240  		return ld;
     241  
     242  	/* If there's no lang dir element, it's an English man page. */
     243  	if (sm == fm + 3) {
     244  		free (ld);
     245  		return xstrdup ("C");
     246  	}
     247  
     248  	/* found a lang dir */
     249  	fm += 4;
     250  	sm = strchr (fm, '/');
     251  	if (!sm)
     252  		return ld;
     253  	free (ld);
     254  	ld = xstrndup (fm, sm - fm);
     255  	debug ("found lang dir element %s\n", ld);
     256  	return ld;
     257  }
     258  
     259  void init_locale (void)
     260  {
     261  	const char *locale = setlocale (LC_ALL, "");
     262  	if (!locale &&
     263  	    !getenv ("MAN_NO_LOCALE_WARNING") &&
     264  	    !getenv ("DPKG_RUNNING_VERSION"))
     265  		/* Obviously can't translate this. */
     266  		error (0, 0, "can't set the locale; make sure $LC_* and $LANG "
     267  			     "are correct");
     268  	setenv ("MAN_NO_LOCALE_WARNING", "1", 1);
     269  #ifdef ENABLE_NLS
     270  	bindtextdomain (PACKAGE, LOCALEDIR);
     271  	bindtextdomain (PACKAGE "-gnulib", LOCALEDIR);
     272  	textdomain (PACKAGE);
     273  #endif /* ENABLE_NLS */
     274  }