(root)/
man-db-2.12.0/
libdb/
db_gdbm.c
       1  /*
       2   * db_gdbm.c: low level gdbm interface routines for man.
       3   *
       4   * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.)
       5   *
       6   * This library is free software; you can redistribute it and/or
       7   * modify it under the terms of the GNU Library General Public
       8   * License as published by the Free Software Foundation; either
       9   * version 2 of the License, or (at your option) any later version.
      10   *
      11   * This library is distributed in the hope that it will be useful,
      12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14   * Library General Public License for more details.
      15   *
      16   * You should have received a copy of the GNU Library General Public
      17   * License along with this library; if not, write to the Free Software
      18   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      19   *
      20   * Mon Aug  8 20:35:30 BST 1994  Wilf. (G.Wilford@ee.surrey.ac.uk)
      21   */
      22  
      23  #ifdef HAVE_CONFIG_H
      24  #  include "config.h"
      25  #endif /* HAVE_CONFIG_H */
      26  
      27  #ifdef GDBM
      28  
      29  #include <stdbool.h>
      30  #include <string.h>
      31  #include <stdlib.h>
      32  #include <stdio.h>
      33  #include <setjmp.h>
      34  #include <sys/types.h>
      35  #include <sys/stat.h>
      36  #include <unistd.h>
      37  
      38  #include "stat-time.h"
      39  #include "timespec.h"
      40  #include "xalloc.h"
      41  
      42  #include "manconfig.h"
      43  
      44  #include "cleanup.h"
      45  #include "debug.h"
      46  
      47  #include "db_xdbm.h"
      48  #include "mydbm.h"
      49  
      50  /* setjmp/longjmp handling to defend against _gdbm_fatal exiting under our
      51   * feet.  Not thread-safe, but there is no plan for man-db to ever use
      52   * threads.
      53   */
      54  static jmp_buf open_env;
      55  static bool opening;
      56  
      57  /* Mimic _gdbm_fatal's error output, but handle errors during open more
      58   * gracefully than exiting.
      59   */
      60  static void trap_error (const char *val)
      61  {
      62  	if (opening) {
      63  		debug ("gdbm error: %s\n", val);
      64  		longjmp (open_env, 1);
      65  	} else
      66  		fprintf (stderr, "gdbm fatal: %s\n", val);
      67  }
      68  
      69  man_gdbm_wrapper man_gdbm_new (const char *name)
      70  {
      71  	man_gdbm_wrapper wrap;
      72  
      73  	wrap = xmalloc (sizeof *wrap);
      74  	wrap->name = xstrdup (name);
      75  	wrap->file = NULL;
      76  	wrap->mtime = NULL;
      77  
      78  	return wrap;
      79  }
      80  
      81  bool man_gdbm_open_wrapper (man_gdbm_wrapper wrap, int flags)
      82  {
      83  	datum key, content;
      84  
      85  	opening = true;
      86  	if (setjmp (open_env))
      87  		return false;
      88  	wrap->file = gdbm_open (wrap->name, BLK_SIZE, flags, DBMODE,
      89  				trap_error);
      90  	if (!wrap->file)
      91  		return false;
      92  
      93  	if ((flags & ~GDBM_FAST) != GDBM_NEWDB) {
      94  		/* While the setjmp/longjmp guard is in effect, make sure we
      95  		 * can read from the database at all.
      96  		 */
      97  		memset (&key, 0, sizeof key);
      98  		MYDBM_SET (key, xstrdup (VER_KEY));
      99  		content = MYDBM_FETCH (wrap, key);
     100  		MYDBM_FREE_DPTR (key);
     101  		MYDBM_FREE_DPTR (content);
     102  	}
     103  
     104  	opening = false;
     105  
     106  	return true;
     107  }
     108  
     109  static datum unsorted_firstkey (man_gdbm_wrapper wrap)
     110  {
     111  	return gdbm_firstkey (wrap->file);
     112  }
     113  
     114  static datum unsorted_nextkey (man_gdbm_wrapper wrap, datum key)
     115  {
     116  	return gdbm_nextkey (wrap->file, key);
     117  }
     118  
     119  datum man_gdbm_firstkey (man_gdbm_wrapper wrap)
     120  {
     121  	return man_xdbm_firstkey (wrap, unsorted_firstkey, unsorted_nextkey);
     122  }
     123  
     124  datum man_gdbm_nextkey (man_gdbm_wrapper wrap, datum key)
     125  {
     126  	return man_xdbm_nextkey (wrap, key);
     127  }
     128  
     129  struct timespec man_gdbm_get_time (man_gdbm_wrapper wrap)
     130  {
     131  	struct stat st;
     132  
     133  	if (!wrap->mtime) {
     134  		wrap->mtime = XMALLOC (struct timespec);
     135  		if (fstat (gdbm_fdesc (wrap->file), &st) < 0) {
     136  			wrap->mtime->tv_sec = -1;
     137  			wrap->mtime->tv_nsec = -1;
     138  		} else
     139  			*wrap->mtime = get_stat_mtime (&st);
     140  	}
     141  
     142  	return *wrap->mtime;
     143  }
     144  
     145  static void raw_close (man_gdbm_wrapper wrap)
     146  {
     147  	if (wrap->file)
     148  		gdbm_close (wrap->file);
     149  }
     150  
     151  void man_gdbm_free (man_gdbm_wrapper wrap)
     152  {
     153  	man_xdbm_free (wrap, raw_close);
     154  }
     155  
     156  #ifndef HAVE_GDBM_EXISTS
     157  
     158  int gdbm_exists (GDBM_FILE file, datum key)
     159  {
     160  	char *memory;
     161  
     162  	memory = MYDBM_DPTR (gdbm_fetch (file, key));
     163  	if (memory) {
     164  		free (memory);
     165  		return 1;
     166  	}
     167  
     168  	return 0;
     169  }
     170  
     171  #endif /* !HAVE_GDBM_EXISTS */
     172  
     173  #endif /* GDBM */