Exemple #1
0
/* The do_we_replace logic. Decide, for some existing key, whether it should
 * be replaced with some new contents. Check that names and section
 * extensions match before calling this.
 */
static int replace_if_necessary (struct mandata *newdata,
				 struct mandata *olddata,
				 datum newkey, datum newcont)
{
	/* It's OK to replace ULT_MAN with SO_MAN if the mtime is newer. It
	 * isn't OK to replace a real page (either ULT_MAN or SO_MAN) with a
	 * whatis reference; if the real page really went away then
	 * purge_missing will catch that in time, but a real page that still
	 * exists should always take precedence.
	 */
	if (compare_ids (newdata->id, olddata->id, 1) <= 0 &&
	    newdata->_st_mtime > olddata->_st_mtime) {
		debug ("replace_if_necessary(): newer mtime; replacing\n");
		if (MYDBM_REPLACE (dbf, newkey, newcont))
			gripe_replace_key (MYDBM_DPTR (newkey));
		return 0;
	}

	if (compare_ids (newdata->id, olddata->id, 0) < 0) {
		if (MYDBM_REPLACE (dbf, newkey, newcont))
			gripe_replace_key (MYDBM_DPTR (newkey));
		return 0;
	}

	/* TODO: name fields should be collated with the requested name */

	if (newdata->id == olddata->id) {
		if (STREQ (dash_if_unset (newdata->comp), olddata->comp))
			return 0; /* same file */
		else {
			debug ("ignoring differing compression "
			       "extensions: %s\n", MYDBM_DPTR (newkey));
			return 1; /* differing exts */
		}
	}

	debug ("ignoring differing ids: %s\n", MYDBM_DPTR (newkey));
	return 0;
}
Exemple #2
0
/* scan for the page, print any matches */
static void do_apropos (MYDBM_FILE dbf,
			const char * const *pages, int num_pages, int *found)
{
	datum key, cont;
	char **lowpages;
	int *found_here;
	int (*combine) (int, int *);
	int i;
#ifndef BTREE
	datum nextkey;
#else /* BTREE */
	int end;
#endif /* !BTREE */

	lowpages = XNMALLOC (num_pages, char *);
	for (i = 0; i < num_pages; ++i) {
		lowpages[i] = lower (pages[i]);
		debug ("lower(%s) = \"%s\"\n", pages[i], lowpages[i]);
	}
	found_here = XNMALLOC (num_pages, int);
	combine = require_all ? all_set : any_set;

#ifndef BTREE
	key = MYDBM_FIRSTKEY (dbf);
	while (MYDBM_DPTR (key)) {
		cont = MYDBM_FETCH (dbf, key);
#else /* BTREE */
	end = btree_nextkeydata (dbf, &key, &cont);
	while (!end) {
#endif /* !BTREE */
		char *tab;
		struct mandata info;

		memset (&info, 0, sizeof (info));

		/* bug#4372, NULL pointer dereference in MYDBM_DPTR (cont),
		 * fix by [email protected] (J.H.M.Dassen), thanx Ray.
		 * cjwatson: In that case, complain and exit, otherwise we
		 * might loop (bug #95052).
		 */
		if (!MYDBM_DPTR (cont))
		{
			debug ("key was %s\n", MYDBM_DPTR (key));
			error (FATAL, 0,
			       _("Database %s corrupted; rebuild with "
				 "mandb --create"),
			       database);
		}

		if (*MYDBM_DPTR (key) == '$')
			goto nextpage;

		if (*MYDBM_DPTR (cont) == '\t')
			goto nextpage;

		/* a real page */

		split_content (MYDBM_DPTR (cont), &info);

		/* If there are sections given, does any of them match
		 * either the section or extension of this page?
		 */
		if (sections) {
			char * const *section;
			int matched = 0;

			for (section = sections; *section; ++section) {
				if (STREQ (*section, info.sec) ||
				    STREQ (*section, info.ext)) {
					matched = 1;
					break;
				}
			}

			if (!matched)
				goto nextpage;
		}

		tab = strrchr (MYDBM_DPTR (key), '\t');
		if (tab) 
			 *tab = '\0';

		memset (found_here, 0, num_pages * sizeof (*found_here));
		if (am_apropos) {
			char *whatis;

			parse_name ((const char **) lowpages, num_pages,
				    MYDBM_DPTR (key), found, found_here);
			whatis = info.whatis ? xstrdup (info.whatis) : NULL;
			if (!combine (num_pages, found_here) && whatis)
				parse_whatis (pages, lowpages, num_pages,
					      whatis, found, found_here);
			free (whatis);
		} else
			parse_name (pages, num_pages,
				    MYDBM_DPTR (key), found, found_here);
		if (combine (num_pages, found_here))
			display (dbf, &info, MYDBM_DPTR (key));

		if (tab)
			*tab = '\t';
nextpage:
#ifndef BTREE
		nextkey = MYDBM_NEXTKEY (dbf, key);
		MYDBM_FREE_DPTR (cont);
		MYDBM_FREE_DPTR (key);
		key = nextkey; 
#else /* BTREE */
		MYDBM_FREE_DPTR (cont);
		MYDBM_FREE_DPTR (key);
		end = btree_nextkeydata (dbf, &key, &cont);
#endif /* !BTREE */
		info.addr = NULL; /* == MYDBM_DPTR (cont), freed above */
		free_mandata_elements (&info);
	}

	for (i = 0; i < num_pages; ++i)
		free (lowpages[i]);
	free (lowpages);
}

/* loop through the man paths, searching for a match */
static int search (const char * const *pages, int num_pages)
{
	int *found = XCALLOC (num_pages, int);
	char *catpath, **mp;
	int any_found, i;

	for (mp = manpathlist; *mp; mp++) {
		MYDBM_FILE dbf;

		catpath = get_catpath (*mp, SYSTEM_CAT | USER_CAT);
		
		if (catpath) {
			database = mkdbname (catpath);
			free (catpath);
		} else
			database = mkdbname (*mp);

		debug ("path=%s\n", *mp);

		dbf = MYDBM_RDOPEN (database);
		if (dbf && dbver_rd (dbf)) {
			MYDBM_CLOSE (dbf);
			dbf = NULL;
		}
		if (!dbf) {
			use_grep (pages, num_pages, *mp, found);
			continue;
		}

		if (am_apropos)
			do_apropos (dbf, pages, num_pages, found);
		else {
			if (regex_opt || wildcard)
				do_apropos (dbf, pages, num_pages, found);
			else
				do_whatis (dbf, pages, num_pages, *mp, found);
		}
		free (database);
		database = NULL;
		MYDBM_CLOSE (dbf);
	}

	chkr_garbage_detector ();

	any_found = 0;
	for (i = 0; i < num_pages; ++i) {
		if (found[i])
			any_found = 1;
		else
			fprintf (stderr, _("%s: nothing appropriate.\n"),
				 pages[i]);
	}

	free (found);
	return any_found;
}
Exemple #3
0
int dbdelete (MYDBM_FILE dbf, const char *name, struct mandata *info)
{
	datum key, cont;

	memset (&key, 0, sizeof key);
	memset (&cont, 0, sizeof cont);

	/* get entry for info */

	debug ("Attempting delete of %s(%s) entry.\n", name, info->ext);

	MYDBM_SET (key, name_to_key (name));
	cont = MYDBM_FETCH (dbf, key);

	if (!MYDBM_DPTR (cont)) {			/* 0 entries */
		MYDBM_FREE_DPTR (key);
		return NO_ENTRY;
	} else if (*MYDBM_DPTR (cont) != '\t') {	/* 1 entry */
		MYDBM_DELETE (dbf, key);
		MYDBM_FREE_DPTR (cont);
	} else {					/* 2+ entries */
		char **names, **ext;
		char *multi_content = NULL;
		datum multi_key;
		int refs, i, j;

		/* Extract all of the extensions associated with
		   this key */

		refs = list_extensions (MYDBM_DPTR (cont) + 1, &names, &ext);

		for (i = 0; i < refs; ++i)
			if (STREQ (names[i], name) &&
			    STREQ (ext[i], info->ext))
				break;

		if (i >= refs) {
			free (names);
			free (ext);
			MYDBM_FREE_DPTR (cont);
			MYDBM_FREE_DPTR (key);
			return NO_ENTRY;
		}

		multi_key = make_multi_key (names[i], ext[i]);
		if (!MYDBM_EXISTS (dbf, multi_key)) {
			error (0, 0,
			       _( "multi key %s does not exist"),
			       MYDBM_DPTR (multi_key));
			gripe_corrupt_data ();
		}
		MYDBM_DELETE (dbf, multi_key);
		MYDBM_FREE_DPTR (multi_key);

		/* refs *may* be 1 if all manual pages with this name
		   have been deleted. In this case, we'll have to remove
		   the key too */

		if (refs == 1) {
			free (names);
			free (ext);
			MYDBM_FREE_DPTR (cont);
			MYDBM_DELETE (dbf, key);
			MYDBM_FREE_DPTR (key);
			return 0;
		}

		/* create our new multi content */
		for (j = 0; j < refs; ++j)
			if (i != j)
				multi_content = appendstr (multi_content,
							   "\t", names[j],
							   "\t", ext[j], NULL);

		MYDBM_FREE_DPTR (cont);

		/* if refs = 2 do something else. Doesn't really matter as
		   the gdbm db file does not shrink any after a deletion
		   anyway */

		MYDBM_SET (cont, multi_content);

		if (MYDBM_REPLACE (dbf, key, cont))
			gripe_replace_key (MYDBM_DPTR (key));

		free (names);
		free (ext);
	}

	MYDBM_FREE_DPTR (key);
	return 0;
}
Exemple #4
0
int dbstore (struct mandata *in, const char *base)
{
	datum oldkey, oldcont;

	memset (&oldkey, 0, sizeof oldkey);
	memset (&oldcont, 0, sizeof oldcont);

	/* create a simple key */
	MYDBM_SET (oldkey, name_to_key (base));
 	if (!*base) {
		dbprintf (in);
 		return 2;
 	}

	if (in->name) {
		error (0, 0, "in->name (%s) should not be set when calling "
			     "dbstore()!\n",
		       in->name);
		free (in->name);
		in->name = NULL;
	}

	/* get the content for the simple key */

	oldcont = MYDBM_FETCH (dbf, oldkey);

	if (MYDBM_DPTR (oldcont) == NULL) { 		/* situation (1) */
		if (!STREQ (base, MYDBM_DPTR (oldkey)))
			in->name = xstrdup (base);
		oldcont = make_content (in);
		if (MYDBM_REPLACE (dbf, oldkey, oldcont))
			gripe_replace_key (MYDBM_DPTR (oldkey));
		free (MYDBM_DPTR (oldcont));
		free (in->name);
		in->name = NULL;
	} else if (*MYDBM_DPTR (oldcont) == '\t') { 	/* situation (2) */
		datum newkey, newcont;

		memset (&newkey, 0, sizeof newkey);
		memset (&newcont, 0, sizeof newcont);

		newkey = make_multi_key (base, in->ext);
		newcont = make_content (in);

		/* Try to insert the new multi data */

		if (MYDBM_INSERT (dbf, newkey, newcont)) {
			datum cont;
			struct mandata info;
			int ret;

			MYDBM_FREE (MYDBM_DPTR (oldcont));
			cont = MYDBM_FETCH (dbf, newkey);
			split_content (MYDBM_DPTR (cont), &info);
			ret = replace_if_necessary (in, &info,
						    newkey, newcont);
			/* MYDBM_FREE (MYDBM_DPTR (cont)); */
			free_mandata_elements (&info);
			free (MYDBM_DPTR (newkey));
			free (MYDBM_DPTR (newcont));
			free (MYDBM_DPTR (oldkey));

			return ret;
		}

		/* Now lets add some info to the simple key's cont. */

		/* This next bit needs to be done first as we'll wipe out
		   MYDBM_DPTR (oldcont) otherwise (for NDBM only!) */

		free (MYDBM_DPTR (newkey));
		free (MYDBM_DPTR (newcont));

		MYDBM_SET (newcont, xasprintf (
			"%s\t%s\t%s", MYDBM_DPTR (oldcont), base, in->ext));
		MYDBM_FREE (MYDBM_DPTR (oldcont));

		/* Try to replace the old simple data with the new stuff */

		if (MYDBM_REPLACE (dbf, oldkey, newcont))
			gripe_replace_key (MYDBM_DPTR (oldkey));

		free (MYDBM_DPTR (newcont));
	} else { 				/* situation (3) */
		datum newkey, newcont, lastkey, lastcont;
		struct mandata old;
		char *old_name;

		memset (&newkey, 0, sizeof newkey);
		memset (&newcont, 0, sizeof newcont);
		memset (&lastkey, 0, sizeof lastkey);
		memset (&lastcont, 0, sizeof lastcont);

		/* Extract the old singular reference */

		split_content (MYDBM_DPTR (oldcont), &old);

		/* Create multi keys for both old
		   and new items, create new content */

		if (old.name)
			old_name = xstrdup (old.name);
		else
			old_name = xstrdup (MYDBM_DPTR (oldkey));

		lastkey = make_multi_key (old_name, old.ext);

		/* Check against identical multi keys before inserting
		   into db */

		if (STREQ (old_name, base) && STREQ (old.ext, in->ext)) {
			int ret;

			if (!STREQ (base, MYDBM_DPTR (oldkey)))
				in->name = xstrdup (base);
			newcont = make_content (in);
			ret = replace_if_necessary (in, &old, oldkey, newcont);
			/* MYDBM_FREE (MYDBM_DPTR (oldcont)); */
			free_mandata_elements (&old);
			free (MYDBM_DPTR (newcont));
			free (MYDBM_DPTR (lastkey));
			free (MYDBM_DPTR (oldkey));
			free (old_name);
			free (in->name);
			in->name = NULL;

			return ret;
		}

		/* Multi keys use the proper case, and so don't need a name
		 * field.
		 */
		if (old.name) {
			free (old.name);
			old.name = NULL;
		}

		lastcont = make_content (&old);

		/* We always replace here; if the multi key already exists
		 * in the database, then that indicates some kind of
		 * database corruption, but our new multi key is almost
		 * certainly better.
		 */
		if (MYDBM_REPLACE (dbf, lastkey, lastcont))
			gripe_replace_key (MYDBM_DPTR (lastkey));

		free (MYDBM_DPTR (lastkey));
		free (MYDBM_DPTR (lastcont));

		newkey = make_multi_key (base, in->ext);
		newcont = make_content (in);

		if (MYDBM_REPLACE (dbf, newkey, newcont))
			gripe_replace_key (MYDBM_DPTR (newkey));

		free (MYDBM_DPTR (newkey));
		free (MYDBM_DPTR (newcont));

		/* Now build a simple reference to the above two items */

		MYDBM_SET (newcont, xasprintf (
			"\t%s\t%s\t%s\t%s", old_name, old.ext, base, in->ext));

		if (MYDBM_REPLACE (dbf, oldkey, newcont))
			gripe_replace_key (MYDBM_DPTR (oldkey));

		/* MYDBM_FREE (MYDBM_DPTR (oldcont)); */
		free_mandata_elements (&old);
		free (MYDBM_DPTR (newcont));
		free (old_name);
	}

	free (MYDBM_DPTR (oldkey));
	return 0;
}