xref: /titanic_51/usr/src/cmd/rcm_daemon/common/filesys_rcm.c (revision 648495d6a097a39eaebc7e56d25f2463ff3bba65)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
525e8c5aaSvikram  * Common Development and Distribution License (the "License").
625e8c5aaSvikram  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*648495d6Svikram  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * This module adds support to the RCM framework for mounted filesystems.
307c478bd9Sstevel@tonic-gate  *
317c478bd9Sstevel@tonic-gate  * The module provides this functionality:
327c478bd9Sstevel@tonic-gate  * 	1) reports device usage for mounted filesystems
337c478bd9Sstevel@tonic-gate  *	2) prevents offline operations for mounted resources
347c478bd9Sstevel@tonic-gate  *	3) prevents suspend operations (unless forced) of those filesystems
357c478bd9Sstevel@tonic-gate  *	   deemed critical for the continued operation of the OS
367c478bd9Sstevel@tonic-gate  *	4) propagates RCM operations from mounted resources to the consumers
377c478bd9Sstevel@tonic-gate  *	   of files within the mounted filesystems
387c478bd9Sstevel@tonic-gate  */
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #include <stdio.h>
417c478bd9Sstevel@tonic-gate #include <assert.h>
427c478bd9Sstevel@tonic-gate #include <string.h>
437c478bd9Sstevel@tonic-gate #include <synch.h>
447c478bd9Sstevel@tonic-gate #include <libintl.h>
457c478bd9Sstevel@tonic-gate #include <errno.h>
467c478bd9Sstevel@tonic-gate #include <sys/mnttab.h>
477c478bd9Sstevel@tonic-gate #include <sys/param.h>
487c478bd9Sstevel@tonic-gate #include <sys/stat.h>
497c478bd9Sstevel@tonic-gate #include <sys/utssys.h>
5025e8c5aaSvikram #include <unistd.h>
5125e8c5aaSvikram #include <limits.h>
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #include "rcm_module.h"
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate /* Definitions */
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate #define	HASH_DEFAULT		4
587c478bd9Sstevel@tonic-gate #define	HASH_THRESHOLD		256
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate #define	OPT_IGNORE		"ignore"
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate #define	MSG_HDR_STD		gettext("mounted filesystem")
637c478bd9Sstevel@tonic-gate #define	MSG_HDR_STD_MULTI	gettext("mounted filesystems")
647c478bd9Sstevel@tonic-gate #define	MSG_HDR_CRIT		gettext("cannot suspend filesystem")
657c478bd9Sstevel@tonic-gate #define	MSG_HDR_CRIT_MULTI	gettext("cannot suspend filesystems")
667c478bd9Sstevel@tonic-gate #define	MSG_SEPARATOR		gettext(", ")
677c478bd9Sstevel@tonic-gate #define	MSG_FAIL_USAGE		gettext("failed to construct usage string.")
687c478bd9Sstevel@tonic-gate #define	MSG_FAIL_DEPENDENTS	gettext("failed while calling dependents.")
697c478bd9Sstevel@tonic-gate #define	MSG_FAIL_REMOVE		gettext("filesystems cannot be removed.")
707c478bd9Sstevel@tonic-gate #define	MSG_FAIL_INTERNAL	gettext("internal processing failure.")
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate typedef struct hashentry {
737c478bd9Sstevel@tonic-gate 	int n_mounts;
747c478bd9Sstevel@tonic-gate 	char *special;
7525e8c5aaSvikram 	char *fstype;
767c478bd9Sstevel@tonic-gate 	char **mountps;
777c478bd9Sstevel@tonic-gate 	struct hashentry *next;
787c478bd9Sstevel@tonic-gate } hashentry_t;
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate typedef struct {
817c478bd9Sstevel@tonic-gate 	time_t timestamp;
827c478bd9Sstevel@tonic-gate 	uint32_t hash_size;
837c478bd9Sstevel@tonic-gate 	hashentry_t **mounts;
847c478bd9Sstevel@tonic-gate } cache_t;
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate /* Forward Declarations */
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate /* module interface routines */
897c478bd9Sstevel@tonic-gate static int mnt_register(rcm_handle_t *);
907c478bd9Sstevel@tonic-gate static int mnt_unregister(rcm_handle_t *);
917c478bd9Sstevel@tonic-gate static int mnt_getinfo(rcm_handle_t *, char *, id_t, uint_t, char **, char **,
927c478bd9Sstevel@tonic-gate     nvlist_t *, rcm_info_t **);
937c478bd9Sstevel@tonic-gate static int mnt_suspend(rcm_handle_t *, char *, id_t, timespec_t *,
947c478bd9Sstevel@tonic-gate     uint_t, char **, rcm_info_t **);
957c478bd9Sstevel@tonic-gate static int mnt_resume(rcm_handle_t *, char *, id_t, uint_t, char **,
967c478bd9Sstevel@tonic-gate     rcm_info_t **);
977c478bd9Sstevel@tonic-gate static int mnt_offline(rcm_handle_t *, char *, id_t, uint_t, char **,
987c478bd9Sstevel@tonic-gate     rcm_info_t **);
997c478bd9Sstevel@tonic-gate static int mnt_online(rcm_handle_t *, char *, id_t, uint_t, char **,
1007c478bd9Sstevel@tonic-gate     rcm_info_t **);
1017c478bd9Sstevel@tonic-gate static int mnt_remove(rcm_handle_t *, char *, id_t, uint_t, char **,
1027c478bd9Sstevel@tonic-gate     rcm_info_t **);
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /* cache functions */
1057c478bd9Sstevel@tonic-gate static cache_t *cache_create();
1067c478bd9Sstevel@tonic-gate static int cache_insert(cache_t *, struct mnttab *);
1077c478bd9Sstevel@tonic-gate static int cache_sync(rcm_handle_t *, cache_t **);
1087c478bd9Sstevel@tonic-gate static hashentry_t *cache_lookup(cache_t *, char *);
1097c478bd9Sstevel@tonic-gate static void free_cache(cache_t **);
1107c478bd9Sstevel@tonic-gate static void free_entry(hashentry_t **);
1117c478bd9Sstevel@tonic-gate static void free_list(char **);
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate /* miscellaneous functions */
1147c478bd9Sstevel@tonic-gate static uint32_t hash(uint32_t, char *);
1157c478bd9Sstevel@tonic-gate static void register_rsrc(rcm_handle_t *, char *);
1167c478bd9Sstevel@tonic-gate static void unregister_rsrc(rcm_handle_t *, char *);
1177c478bd9Sstevel@tonic-gate static char *create_message(char *, char *, char **);
1187c478bd9Sstevel@tonic-gate static int detect_critical_failure(char **, uint_t, char **);
1197c478bd9Sstevel@tonic-gate static int is_critical(char *);
1207c478bd9Sstevel@tonic-gate static int use_cache(char *, char **, char ***);
1217c478bd9Sstevel@tonic-gate static void prune_dependents(char **, char *);
1227c478bd9Sstevel@tonic-gate static char **create_dependents(hashentry_t *);
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate /* Module-Private data */
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate static struct rcm_mod_ops mnt_ops =
1277c478bd9Sstevel@tonic-gate {
1287c478bd9Sstevel@tonic-gate 	RCM_MOD_OPS_VERSION,
1297c478bd9Sstevel@tonic-gate 	mnt_register,
1307c478bd9Sstevel@tonic-gate 	mnt_unregister,
1317c478bd9Sstevel@tonic-gate 	mnt_getinfo,
1327c478bd9Sstevel@tonic-gate 	mnt_suspend,
1337c478bd9Sstevel@tonic-gate 	mnt_resume,
1347c478bd9Sstevel@tonic-gate 	mnt_offline,
1357c478bd9Sstevel@tonic-gate 	mnt_online,
1367c478bd9Sstevel@tonic-gate 	mnt_remove
1377c478bd9Sstevel@tonic-gate };
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate static cache_t *mnt_cache;
1407c478bd9Sstevel@tonic-gate static mutex_t cache_lock;
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate /* Module Interface Routines */
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate /*
1457c478bd9Sstevel@tonic-gate  * rcm_mod_init()
1467c478bd9Sstevel@tonic-gate  *
1477c478bd9Sstevel@tonic-gate  *	Called when module is loaded.  Returns the ops vector.
1487c478bd9Sstevel@tonic-gate  */
1497c478bd9Sstevel@tonic-gate struct rcm_mod_ops *
1507c478bd9Sstevel@tonic-gate rcm_mod_init()
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate 	return (&mnt_ops);
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate /*
1567c478bd9Sstevel@tonic-gate  * rcm_mod_info()
1577c478bd9Sstevel@tonic-gate  *
1587c478bd9Sstevel@tonic-gate  *	Returns a string identifying this module.
1597c478bd9Sstevel@tonic-gate  */
1607c478bd9Sstevel@tonic-gate const char *
1617c478bd9Sstevel@tonic-gate rcm_mod_info()
1627c478bd9Sstevel@tonic-gate {
163*648495d6Svikram 	return ("File system module 1.9");
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate /*
1677c478bd9Sstevel@tonic-gate  * rcm_mod_fini()
1687c478bd9Sstevel@tonic-gate  *
1697c478bd9Sstevel@tonic-gate  *	Called when module is unloaded.  Frees up all used memory.
1707c478bd9Sstevel@tonic-gate  *
1717c478bd9Sstevel@tonic-gate  *	Locking: the cache is locked for the duration of this function.
1727c478bd9Sstevel@tonic-gate  */
1737c478bd9Sstevel@tonic-gate int
1747c478bd9Sstevel@tonic-gate rcm_mod_fini()
1757c478bd9Sstevel@tonic-gate {
1767c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
1777c478bd9Sstevel@tonic-gate 	free_cache(&mnt_cache);
1787c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate /*
1847c478bd9Sstevel@tonic-gate  * mnt_register()
1857c478bd9Sstevel@tonic-gate  *
1867c478bd9Sstevel@tonic-gate  *	Called to synchronize the module's registrations.  Results in the
1877c478bd9Sstevel@tonic-gate  *	construction of a new cache, destruction of any old cache data,
1887c478bd9Sstevel@tonic-gate  *	and a full synchronization of the module's registrations.
1897c478bd9Sstevel@tonic-gate  *
1907c478bd9Sstevel@tonic-gate  *	Locking: the cache is locked for the duration of this function.
1917c478bd9Sstevel@tonic-gate  */
1927c478bd9Sstevel@tonic-gate int
1937c478bd9Sstevel@tonic-gate mnt_register(rcm_handle_t *hd)
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "FILESYS: register()\n");
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	/* cache_sync() does all of the necessary work */
2027c478bd9Sstevel@tonic-gate 	if (cache_sync(hd, &mnt_cache) < 0) {
2037c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
2047c478bd9Sstevel@tonic-gate 		    "FILESYS: failed to synchronize cache (%s).\n",
2057c478bd9Sstevel@tonic-gate 		    strerror(errno));
2067c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
2077c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
2137c478bd9Sstevel@tonic-gate }
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate /*
2167c478bd9Sstevel@tonic-gate  * mnt_unregister()
2177c478bd9Sstevel@tonic-gate  *
2187c478bd9Sstevel@tonic-gate  *	Manually walk through the cache, unregistering all the special
2197c478bd9Sstevel@tonic-gate  *	files and mount points.
2207c478bd9Sstevel@tonic-gate  *
2217c478bd9Sstevel@tonic-gate  *	Locking: the cache is locked throughout the execution of this
2227c478bd9Sstevel@tonic-gate  *	routine because it reads and modifies cache links continuously.
2237c478bd9Sstevel@tonic-gate  */
2247c478bd9Sstevel@tonic-gate int
2257c478bd9Sstevel@tonic-gate mnt_unregister(rcm_handle_t *hd)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate 	uint32_t index;
2287c478bd9Sstevel@tonic-gate 	hashentry_t *entry;
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "FILESYS: unregister()\n");
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	/* Unregister everything in the cache */
2377c478bd9Sstevel@tonic-gate 	if (mnt_cache) {
2387c478bd9Sstevel@tonic-gate 		for (index = 0; index < mnt_cache->hash_size; index++) {
2397c478bd9Sstevel@tonic-gate 			for (entry = mnt_cache->mounts[index]; entry != NULL;
2407c478bd9Sstevel@tonic-gate 			    entry = entry->next) {
2417c478bd9Sstevel@tonic-gate 				unregister_rsrc(hd, entry->special);
2427c478bd9Sstevel@tonic-gate 			}
2437c478bd9Sstevel@tonic-gate 		}
2447c478bd9Sstevel@tonic-gate 	}
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	/* Destroy the cache */
2477c478bd9Sstevel@tonic-gate 	free_cache(&mnt_cache);
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
2527c478bd9Sstevel@tonic-gate }
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate /*
2557c478bd9Sstevel@tonic-gate  * mnt_offline()
2567c478bd9Sstevel@tonic-gate  *
25725e8c5aaSvikram  *	Filesystem resources cannot be offlined. They can however be retired
25825e8c5aaSvikram  *	if they don't provide a critical service. The offline entry point
25925e8c5aaSvikram  *	checks if this is a retire operation and if it is and the filesystem
26025e8c5aaSvikram  *	doesn't provide a critical service, the entry point returns success
26125e8c5aaSvikram  *	For all other cases, failure is returned.
2627c478bd9Sstevel@tonic-gate  *	Since no real action is taken, QUERY or not doesn't matter.
2637c478bd9Sstevel@tonic-gate  */
2647c478bd9Sstevel@tonic-gate int
2657c478bd9Sstevel@tonic-gate mnt_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
2667c478bd9Sstevel@tonic-gate     char **errorp, rcm_info_t **dependent_info)
2677c478bd9Sstevel@tonic-gate {
2687c478bd9Sstevel@tonic-gate 	char **dependents;
26925e8c5aaSvikram 	hashentry_t *entry;
27025e8c5aaSvikram 	int retval;
27125e8c5aaSvikram 	int i;
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
2747c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
2757c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
2767c478bd9Sstevel@tonic-gate 	assert(errorp != NULL);
2777c478bd9Sstevel@tonic-gate 
27825e8c5aaSvikram 	*errorp = NULL;
27925e8c5aaSvikram 
2807c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "FILESYS: offline(%s)\n", rsrc);
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	/* Retrieve necessary info from the cache */
28325e8c5aaSvikram 	if (use_cache(rsrc, errorp, &dependents) < 0) {
28425e8c5aaSvikram 		if (flags & RCM_RETIRE_REQUEST)
28525e8c5aaSvikram 			return (RCM_NO_CONSTRAINT);
28625e8c5aaSvikram 		else
2877c478bd9Sstevel@tonic-gate 			return (RCM_FAILURE);
28825e8c5aaSvikram 	}
28925e8c5aaSvikram 
29025e8c5aaSvikram 	if (flags & RCM_RETIRE_REQUEST) {
29125e8c5aaSvikram 		(void) mutex_lock(&cache_lock);
29225e8c5aaSvikram 		if ((entry = cache_lookup(mnt_cache, rsrc)) == NULL) {
29325e8c5aaSvikram 			rcm_log_message(RCM_ERROR, "FILESYS: "
29425e8c5aaSvikram 			    "failed to look up \"%s\" in cache (%s).\n",
29525e8c5aaSvikram 			    rsrc, strerror(errno));
29625e8c5aaSvikram 			(void) mutex_unlock(&cache_lock);
29725e8c5aaSvikram 			retval = RCM_NO_CONSTRAINT;
29825e8c5aaSvikram 			goto out;
29925e8c5aaSvikram 		}
30025e8c5aaSvikram 
30125e8c5aaSvikram 		if (strcmp(entry->fstype, "zfs") == 0) {
30225e8c5aaSvikram 			retval = RCM_NO_CONSTRAINT;
30325e8c5aaSvikram 			rcm_log_message(RCM_TRACE1,
30425e8c5aaSvikram 			    "FILESYS: zfs: NO_CONSTRAINT: %s\n", rsrc);
30525e8c5aaSvikram 		} else {
30625e8c5aaSvikram 			retval = RCM_SUCCESS;
30725e8c5aaSvikram 			for (i = 0; dependents[i] != NULL; i++) {
30825e8c5aaSvikram 				if (is_critical(dependents[i])) {
30925e8c5aaSvikram 					retval = RCM_FAILURE;
31025e8c5aaSvikram 					rcm_log_message(RCM_TRACE1, "FILESYS: "
31125e8c5aaSvikram 					    "CRITICAL %s\n", rsrc);
31225e8c5aaSvikram 					break;
31325e8c5aaSvikram 				}
31425e8c5aaSvikram 			}
31525e8c5aaSvikram 		}
31625e8c5aaSvikram 		(void) mutex_unlock(&cache_lock);
31725e8c5aaSvikram 		goto out;
31825e8c5aaSvikram 	}
31925e8c5aaSvikram 
32025e8c5aaSvikram 	retval = RCM_FAILURE;
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	/* Convert the gathered dependents into an error message */
3237c478bd9Sstevel@tonic-gate 	*errorp = create_message(MSG_HDR_STD, MSG_HDR_STD_MULTI, dependents);
3247c478bd9Sstevel@tonic-gate 	if (*errorp == NULL) {
3257c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
3267c478bd9Sstevel@tonic-gate 		    "FILESYS: failed to construct offline message (%s).\n",
3277c478bd9Sstevel@tonic-gate 		    strerror(errno));
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 
33025e8c5aaSvikram out:
33125e8c5aaSvikram 	free_list(dependents);
33225e8c5aaSvikram 	return (retval);
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate /*
3367c478bd9Sstevel@tonic-gate  * mnt_online()
3377c478bd9Sstevel@tonic-gate  *
3387c478bd9Sstevel@tonic-gate  *	Filesystem resources aren't offlined, so there's really nothing to do
3397c478bd9Sstevel@tonic-gate  *	here.
3407c478bd9Sstevel@tonic-gate  */
3417c478bd9Sstevel@tonic-gate int
3427c478bd9Sstevel@tonic-gate mnt_online(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag, char **errorp,
3437c478bd9Sstevel@tonic-gate     rcm_info_t **dependent_reason)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
3467c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
3477c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
3487c478bd9Sstevel@tonic-gate 	assert(errorp != NULL);
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "FILESYS: online(%s)\n", rsrc);
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
3537c478bd9Sstevel@tonic-gate }
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate /*
3567c478bd9Sstevel@tonic-gate  * mnt_getinfo()
3577c478bd9Sstevel@tonic-gate  *
3587c478bd9Sstevel@tonic-gate  *	Report how a given resource is in use by this module.  And also
3597c478bd9Sstevel@tonic-gate  *	possibly include dependent consumers of the mounted filesystems.
3607c478bd9Sstevel@tonic-gate  */
3617c478bd9Sstevel@tonic-gate int
3627c478bd9Sstevel@tonic-gate mnt_getinfo(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag, char **usagep,
3637c478bd9Sstevel@tonic-gate     char **errorp, nvlist_t *props, rcm_info_t **depend_info)
3647c478bd9Sstevel@tonic-gate {
3657c478bd9Sstevel@tonic-gate 	int rv = RCM_SUCCESS;
3667c478bd9Sstevel@tonic-gate 	char **dependents;
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
3697c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
3707c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
3717c478bd9Sstevel@tonic-gate 	assert(usagep != NULL);
3727c478bd9Sstevel@tonic-gate 	assert(errorp != NULL);
3737c478bd9Sstevel@tonic-gate 	assert(props != NULL);
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "FILESYS: getinfo(%s)\n", rsrc);
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	/* Retrieve necessary info from the cache */
3787c478bd9Sstevel@tonic-gate 	if (use_cache(rsrc, errorp, &dependents) < 0)
3797c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	/* Convert the gathered dependents into a usage message */
3827c478bd9Sstevel@tonic-gate 	*usagep = create_message(MSG_HDR_STD, MSG_HDR_STD_MULTI, dependents);
3837c478bd9Sstevel@tonic-gate 	if (*usagep == NULL) {
3847c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
3857c478bd9Sstevel@tonic-gate 		    "FILESYS: failed to construct usage message (%s).\n",
3867c478bd9Sstevel@tonic-gate 		    strerror(errno));
3877c478bd9Sstevel@tonic-gate 		*errorp = strdup(MSG_FAIL_USAGE);
3887c478bd9Sstevel@tonic-gate 		free_list(dependents);
3897c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	/* Recurse on dependents if necessary */
3937c478bd9Sstevel@tonic-gate 	if ((flag & RCM_INCLUDE_DEPENDENT) && (dependents != NULL)) {
3947c478bd9Sstevel@tonic-gate 		prune_dependents(dependents, rsrc);
3957c478bd9Sstevel@tonic-gate 		if (dependents[0] != NULL) {
3967c478bd9Sstevel@tonic-gate 			if ((rv = rcm_get_info_list(hd, dependents, flag,
3977c478bd9Sstevel@tonic-gate 			    depend_info)) != RCM_SUCCESS) {
3987c478bd9Sstevel@tonic-gate 				*errorp = strdup(MSG_FAIL_DEPENDENTS);
3997c478bd9Sstevel@tonic-gate 			}
4007c478bd9Sstevel@tonic-gate 		}
4017c478bd9Sstevel@tonic-gate 	}
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	/* Free up info retrieved from the cache */
4047c478bd9Sstevel@tonic-gate 	free_list(dependents);
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	return (rv);
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate /*
4107c478bd9Sstevel@tonic-gate  * mnt_suspend()
4117c478bd9Sstevel@tonic-gate  *
4127c478bd9Sstevel@tonic-gate  *	Notify all dependents that the resource is being suspended.
4137c478bd9Sstevel@tonic-gate  *	Since no real action is taken, QUERY or not doesn't matter.
4147c478bd9Sstevel@tonic-gate  */
4157c478bd9Sstevel@tonic-gate int
4167c478bd9Sstevel@tonic-gate mnt_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
4177c478bd9Sstevel@tonic-gate     uint_t flag, char **errorp, rcm_info_t **depend_info)
4187c478bd9Sstevel@tonic-gate {
4197c478bd9Sstevel@tonic-gate 	int rv = RCM_SUCCESS;
4207c478bd9Sstevel@tonic-gate 	char **dependents;
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
4237c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
4247c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
4257c478bd9Sstevel@tonic-gate 	assert(interval != NULL);
4267c478bd9Sstevel@tonic-gate 	assert(errorp != NULL);
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "FILESYS: suspend(%s)\n", rsrc);
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	/* Retrieve necessary info from the cache */
4317c478bd9Sstevel@tonic-gate 	if (use_cache(rsrc, errorp, &dependents) < 0)
4327c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	/* Unforced suspensions fail if any of the dependents are critical */
4357c478bd9Sstevel@tonic-gate 	if (detect_critical_failure(errorp, flag, dependents)) {
4367c478bd9Sstevel@tonic-gate 		free_list(dependents);
4377c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
4387c478bd9Sstevel@tonic-gate 	}
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	/* Recurse on dependents if necessary */
4417c478bd9Sstevel@tonic-gate 	if ((flag & RCM_INCLUDE_DEPENDENT) && (dependents != NULL)) {
4427c478bd9Sstevel@tonic-gate 		prune_dependents(dependents, rsrc);
4437c478bd9Sstevel@tonic-gate 		if (dependents[0] != NULL)
4447c478bd9Sstevel@tonic-gate 			if ((rv = rcm_request_suspend_list(hd, dependents, flag,
4457c478bd9Sstevel@tonic-gate 			    interval, depend_info)) != RCM_SUCCESS) {
4467c478bd9Sstevel@tonic-gate 				*errorp = strdup(MSG_FAIL_DEPENDENTS);
4477c478bd9Sstevel@tonic-gate 			}
4487c478bd9Sstevel@tonic-gate 	}
4497c478bd9Sstevel@tonic-gate 	free_list(dependents);
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	return (rv);
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate /*
4557c478bd9Sstevel@tonic-gate  * mnt_resume()
4567c478bd9Sstevel@tonic-gate  *
4577c478bd9Sstevel@tonic-gate  *	Resume all the dependents of a suspended filesystem.
4587c478bd9Sstevel@tonic-gate  */
4597c478bd9Sstevel@tonic-gate int
4607c478bd9Sstevel@tonic-gate mnt_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag, char **errorp,
4617c478bd9Sstevel@tonic-gate     rcm_info_t **depend_info)
4627c478bd9Sstevel@tonic-gate {
4637c478bd9Sstevel@tonic-gate 	int rv = RCM_SUCCESS;
4647c478bd9Sstevel@tonic-gate 	char **dependents;
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
4677c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
4687c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
4697c478bd9Sstevel@tonic-gate 	assert(errorp != NULL);
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "FILESYS: resume(%s)\n", rsrc);
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	/* Retrieve necessary info from the cache */
4747c478bd9Sstevel@tonic-gate 	if (use_cache(rsrc, errorp, &dependents) < 0)
4757c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	/* Recurse on dependents if necessary */
4787c478bd9Sstevel@tonic-gate 	if ((flag & RCM_INCLUDE_DEPENDENT) && (dependents != NULL)) {
4797c478bd9Sstevel@tonic-gate 		prune_dependents(dependents, rsrc);
4807c478bd9Sstevel@tonic-gate 		if (dependents[0] != NULL) {
4817c478bd9Sstevel@tonic-gate 			if ((rv = rcm_notify_resume_list(hd, dependents, flag,
4827c478bd9Sstevel@tonic-gate 			    depend_info)) != RCM_SUCCESS) {
4837c478bd9Sstevel@tonic-gate 				*errorp = strdup(MSG_FAIL_DEPENDENTS);
4847c478bd9Sstevel@tonic-gate 			}
4857c478bd9Sstevel@tonic-gate 		}
4867c478bd9Sstevel@tonic-gate 	}
4877c478bd9Sstevel@tonic-gate 	free_list(dependents);
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	return (rv);
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate 
49225e8c5aaSvikram static int
49325e8c5aaSvikram get_spec(char *line, char *spec, size_t ssz)
49425e8c5aaSvikram {
49525e8c5aaSvikram 	char	*cp;
49625e8c5aaSvikram 	char	*start;
49725e8c5aaSvikram 
49825e8c5aaSvikram 	if (strlcpy(spec, line, ssz) >= ssz) {
49925e8c5aaSvikram 		rcm_log_message(RCM_ERROR, "FILESYS: get_spec() failed: "
50025e8c5aaSvikram 		    "line: %s\n", line);
50125e8c5aaSvikram 		return (-1);
50225e8c5aaSvikram 	}
50325e8c5aaSvikram 
50425e8c5aaSvikram 	cp = spec;
50525e8c5aaSvikram 	while (*cp == ' ' || *cp == '\t')
50625e8c5aaSvikram 		cp++;
50725e8c5aaSvikram 
50825e8c5aaSvikram 	if (*cp == '#')
50925e8c5aaSvikram 		return (-1);
51025e8c5aaSvikram 
51125e8c5aaSvikram 	start = cp;
51225e8c5aaSvikram 
51325e8c5aaSvikram 	while (*cp != ' ' && *cp != '\t' && *cp != '\0')
51425e8c5aaSvikram 		cp++;
51525e8c5aaSvikram 	*cp = '\0';
51625e8c5aaSvikram 
51725e8c5aaSvikram 	(void) memmove(spec, start, strlen(start) + 1);
51825e8c5aaSvikram 
51925e8c5aaSvikram 	return (0);
52025e8c5aaSvikram }
52125e8c5aaSvikram 
52225e8c5aaSvikram static int
52325e8c5aaSvikram path_match(char *rsrc, char *spec)
52425e8c5aaSvikram {
52525e8c5aaSvikram 	char r[PATH_MAX];
52625e8c5aaSvikram 	char s[PATH_MAX];
52725e8c5aaSvikram 	size_t len;
52825e8c5aaSvikram 
52925e8c5aaSvikram 	if (realpath(rsrc, r) == NULL)
53025e8c5aaSvikram 		goto error;
53125e8c5aaSvikram 
53225e8c5aaSvikram 	if (realpath(spec, s) == NULL)
53325e8c5aaSvikram 		goto error;
53425e8c5aaSvikram 
53525e8c5aaSvikram 	len = strlen("/devices/");
53625e8c5aaSvikram 
53725e8c5aaSvikram 	if (strncmp(r, "/devices/", len) != 0) {
53825e8c5aaSvikram 		errno = ENXIO;
53925e8c5aaSvikram 		goto error;
54025e8c5aaSvikram 	}
54125e8c5aaSvikram 
54225e8c5aaSvikram 	if (strncmp(s, "/devices/", len) != 0) {
54325e8c5aaSvikram 		errno = ENXIO;
54425e8c5aaSvikram 		goto error;
54525e8c5aaSvikram 	}
54625e8c5aaSvikram 
54725e8c5aaSvikram 	len = strlen(r);
54825e8c5aaSvikram 	if (strncmp(r, s, len) == 0 && (s[len] == '\0' || s[len] == ':'))
54925e8c5aaSvikram 		return (0);
55025e8c5aaSvikram 	else
55125e8c5aaSvikram 		return (1);
55225e8c5aaSvikram 
55325e8c5aaSvikram error:
55425e8c5aaSvikram 	rcm_log_message(RCM_DEBUG, "FILESYS: path_match() failed "
55525e8c5aaSvikram 	    "rsrc=%s spec=%s: %s\n", rsrc, spec, strerror(errno));
55625e8c5aaSvikram 	return (-1);
55725e8c5aaSvikram }
55825e8c5aaSvikram 
55925e8c5aaSvikram #define	VFSTAB		"/etc/vfstab"
56025e8c5aaSvikram #define	RETIRED_PREFIX	"## RETIRED ##"
56125e8c5aaSvikram 
56225e8c5aaSvikram static int
56325e8c5aaSvikram disable_vfstab_entry(char *rsrc)
56425e8c5aaSvikram {
56525e8c5aaSvikram 	FILE	*vfp;
56625e8c5aaSvikram 	FILE	*tfp;
56725e8c5aaSvikram 	int	retval;
56825e8c5aaSvikram 	int	update;
56925e8c5aaSvikram 	char	tmp[PATH_MAX];
57025e8c5aaSvikram 	char	line[MNT_LINE_MAX + 1];
57125e8c5aaSvikram 
57225e8c5aaSvikram 	vfp = fopen(VFSTAB, "r");
57325e8c5aaSvikram 	if (vfp == NULL) {
57425e8c5aaSvikram 		rcm_log_message(RCM_ERROR, "FILESYS: failed to open /etc/vfstab"
57525e8c5aaSvikram 		    " for reading: %s\n", strerror(errno));
57625e8c5aaSvikram 		return (RCM_FAILURE);
57725e8c5aaSvikram 	}
57825e8c5aaSvikram 
57925e8c5aaSvikram 	(void) snprintf(tmp, sizeof (tmp), "/etc/vfstab.retire.%lu", getpid());
58025e8c5aaSvikram 
58125e8c5aaSvikram 	tfp = fopen(tmp, "w");
58225e8c5aaSvikram 	if (tfp == NULL) {
58325e8c5aaSvikram 		rcm_log_message(RCM_ERROR, "FILESYS: failed to open "
58425e8c5aaSvikram 		    "/etc/vfstab.retire for writing: %s\n", strerror(errno));
58525e8c5aaSvikram 		(void) fclose(vfp);
58625e8c5aaSvikram 		return (RCM_FAILURE);
58725e8c5aaSvikram 	}
58825e8c5aaSvikram 
58925e8c5aaSvikram 	retval = RCM_SUCCESS;
59025e8c5aaSvikram 	update = 0;
59125e8c5aaSvikram 	while (fgets(line, sizeof (line), vfp)) {
59225e8c5aaSvikram 
59325e8c5aaSvikram 		char	spec[MNT_LINE_MAX + 1];
59425e8c5aaSvikram 		char	newline[MNT_LINE_MAX + 1];
59525e8c5aaSvikram 		char	*l;
59625e8c5aaSvikram 
59725e8c5aaSvikram 		if (get_spec(line, spec, sizeof (spec)) == -1) {
59825e8c5aaSvikram 			l = line;
59925e8c5aaSvikram 			goto foot;
60025e8c5aaSvikram 		}
60125e8c5aaSvikram 
60225e8c5aaSvikram 		if (path_match(rsrc, spec) != 0) {
60325e8c5aaSvikram 			l = line;
60425e8c5aaSvikram 			goto foot;
60525e8c5aaSvikram 		}
60625e8c5aaSvikram 
60725e8c5aaSvikram 		update = 1;
60825e8c5aaSvikram 
60925e8c5aaSvikram 		/* Paths match. Disable this entry */
61025e8c5aaSvikram 		(void) snprintf(newline, sizeof (newline), "%s %s",
61125e8c5aaSvikram 		    RETIRED_PREFIX, line);
61225e8c5aaSvikram 
61325e8c5aaSvikram 		rcm_log_message(RCM_TRACE1, "FILESYS: disabling line\n\t%s\n",
61425e8c5aaSvikram 		    line);
61525e8c5aaSvikram 
61625e8c5aaSvikram 		l = newline;
61725e8c5aaSvikram foot:
61825e8c5aaSvikram 		if (fputs(l, tfp) == EOF) {
61925e8c5aaSvikram 			rcm_log_message(RCM_ERROR, "FILESYS: failed to write "
62025e8c5aaSvikram 			    "new vfstab: %s\n", strerror(errno));
62125e8c5aaSvikram 			update = 0;
62225e8c5aaSvikram 			retval = RCM_FAILURE;
62325e8c5aaSvikram 			break;
62425e8c5aaSvikram 		}
62525e8c5aaSvikram 	}
62625e8c5aaSvikram 
62725e8c5aaSvikram 	if (vfp)
62825e8c5aaSvikram 		(void) fclose(vfp);
62925e8c5aaSvikram 	if (tfp)
63025e8c5aaSvikram 		(void) fclose(tfp);
63125e8c5aaSvikram 
63225e8c5aaSvikram 	if (update) {
63325e8c5aaSvikram 		if (rename(tmp, VFSTAB) != 0) {
63425e8c5aaSvikram 			rcm_log_message(RCM_ERROR, "FILESYS: vfstab rename "
63525e8c5aaSvikram 			    "failed: %s\n", strerror(errno));
63625e8c5aaSvikram 			retval = RCM_FAILURE;
63725e8c5aaSvikram 		}
63825e8c5aaSvikram 	}
63925e8c5aaSvikram 
64025e8c5aaSvikram 	(void) unlink(tmp);
64125e8c5aaSvikram 
64225e8c5aaSvikram 	return (retval);
64325e8c5aaSvikram }
64425e8c5aaSvikram 
6457c478bd9Sstevel@tonic-gate /*
6467c478bd9Sstevel@tonic-gate  * mnt_remove()
6477c478bd9Sstevel@tonic-gate  *
64825e8c5aaSvikram  *	Remove will only be called in the retire case i.e. if RCM_RETIRE_NOTIFY
64925e8c5aaSvikram  *	flag is set.
6507c478bd9Sstevel@tonic-gate  *
65125e8c5aaSvikram  *	If the flag is not set, then return failure and log the mistake if a
65225e8c5aaSvikram  *	remove is ever received for a mounted filesystem resource.
6537c478bd9Sstevel@tonic-gate  */
6547c478bd9Sstevel@tonic-gate int
6557c478bd9Sstevel@tonic-gate mnt_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag, char **errorp,
6567c478bd9Sstevel@tonic-gate     rcm_info_t **depend_info)
6577c478bd9Sstevel@tonic-gate {
6587c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
6597c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
6607c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
6617c478bd9Sstevel@tonic-gate 	assert(errorp != NULL);
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "FILESYS: remove(%s)\n", rsrc);
6647c478bd9Sstevel@tonic-gate 
66525e8c5aaSvikram 	if (!(flag & RCM_RETIRE_NOTIFY)) {
6667c478bd9Sstevel@tonic-gate 		/* Log the mistake */
66725e8c5aaSvikram 		rcm_log_message(RCM_ERROR, "FILESYS: invalid remove of "
66825e8c5aaSvikram 		    "\"%s\"\n", rsrc);
6697c478bd9Sstevel@tonic-gate 		*errorp = strdup(MSG_FAIL_REMOVE);
6707c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
6717c478bd9Sstevel@tonic-gate 	}
6727c478bd9Sstevel@tonic-gate 
67325e8c5aaSvikram 	return (disable_vfstab_entry(rsrc));
67425e8c5aaSvikram }
67525e8c5aaSvikram 
6767c478bd9Sstevel@tonic-gate /*
6777c478bd9Sstevel@tonic-gate  * Cache management routines
6787c478bd9Sstevel@tonic-gate  */
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate /*
6817c478bd9Sstevel@tonic-gate  * cache_create()
6827c478bd9Sstevel@tonic-gate  *
6837c478bd9Sstevel@tonic-gate  *	This routine constructs a new cache of the current mnttab file.
6847c478bd9Sstevel@tonic-gate  *
6857c478bd9Sstevel@tonic-gate  *	Locking: the cache must be locked prior to calling this function.
6867c478bd9Sstevel@tonic-gate  *
6877c478bd9Sstevel@tonic-gate  *	Return Values: NULL with errno set on failure, new cache point on
6887c478bd9Sstevel@tonic-gate  *	success.
6897c478bd9Sstevel@tonic-gate  */
6907c478bd9Sstevel@tonic-gate static cache_t *
6917c478bd9Sstevel@tonic-gate cache_create()
6927c478bd9Sstevel@tonic-gate {
6937c478bd9Sstevel@tonic-gate 	FILE *fp;
6947c478bd9Sstevel@tonic-gate 	cache_t *cache;
6957c478bd9Sstevel@tonic-gate 	int i;
6967c478bd9Sstevel@tonic-gate 	uint32_t size;
6977c478bd9Sstevel@tonic-gate 	struct stat st;
6987c478bd9Sstevel@tonic-gate 	struct mnttab mt;
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	/*
7017c478bd9Sstevel@tonic-gate 	 * To keep the hash table relatively sparse, default values are
7027c478bd9Sstevel@tonic-gate 	 * used for smaller mnttab files and these values are scaled up
7037c478bd9Sstevel@tonic-gate 	 * as a fraction of the total mnttab file size for larger ones.
7047c478bd9Sstevel@tonic-gate 	 */
7057c478bd9Sstevel@tonic-gate 	if (stat(MNTTAB, &st) < 0) {
7067c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
7077c478bd9Sstevel@tonic-gate 		    "FILESYS: failed to stat \"%s\" (%s).\n", MNTTAB,
7087c478bd9Sstevel@tonic-gate 		    strerror(errno));
7097c478bd9Sstevel@tonic-gate 		errno = EBADF;
7107c478bd9Sstevel@tonic-gate 		return (NULL);
7117c478bd9Sstevel@tonic-gate 	}
7127c478bd9Sstevel@tonic-gate 	if (st.st_size > HASH_THRESHOLD) {
7137c478bd9Sstevel@tonic-gate 		size = st.st_size / HASH_THRESHOLD;
7147c478bd9Sstevel@tonic-gate 		for (i = 0; size > 1; i++, size >>= 1);
7157c478bd9Sstevel@tonic-gate 		for (; i > -1; i--, size <<= 1);
7167c478bd9Sstevel@tonic-gate 	} else {
7177c478bd9Sstevel@tonic-gate 		size = HASH_DEFAULT;
7187c478bd9Sstevel@tonic-gate 	}
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	/* Allocate a new empty cache */
7217c478bd9Sstevel@tonic-gate 	if ((cache = (cache_t *)calloc(1, sizeof (cache_t))) == NULL) {
7227c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
7237c478bd9Sstevel@tonic-gate 		    "FILESYS: failed to allocate cache (%s).\n",
7247c478bd9Sstevel@tonic-gate 		    strerror(errno));
7257c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
7267c478bd9Sstevel@tonic-gate 		return (NULL);
7277c478bd9Sstevel@tonic-gate 	}
7287c478bd9Sstevel@tonic-gate 	cache->hash_size = size;
7297c478bd9Sstevel@tonic-gate 	cache->timestamp = st.st_mtime;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	/* Allocate an empty hash table for the registered special devices */
7327c478bd9Sstevel@tonic-gate 	cache->mounts = (hashentry_t **)calloc(size, sizeof (hashentry_t *));
7337c478bd9Sstevel@tonic-gate 	if (cache->mounts == NULL) {
7347c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
7357c478bd9Sstevel@tonic-gate 		    "FILESYS: failed to allocate mount table (%s).\n",
7367c478bd9Sstevel@tonic-gate 		    strerror(errno));
7377c478bd9Sstevel@tonic-gate 		free_cache(&cache);
7387c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
7397c478bd9Sstevel@tonic-gate 		return (NULL);
7407c478bd9Sstevel@tonic-gate 	}
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	/* Open the mnttab file */
7437c478bd9Sstevel@tonic-gate 	if ((fp = fopen(MNTTAB, "r")) == NULL) {
7447c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
7457c478bd9Sstevel@tonic-gate 		    "FILESYS: failed to open \"%s\" (%s).\n", MNTTAB,
7467c478bd9Sstevel@tonic-gate 		    strerror(errno));
7477c478bd9Sstevel@tonic-gate 		free_cache(&cache);
7487c478bd9Sstevel@tonic-gate 		errno = EIO;
7497c478bd9Sstevel@tonic-gate 		return (NULL);
7507c478bd9Sstevel@tonic-gate 	}
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	/* Insert each mnttab entry into the cache */
7537c478bd9Sstevel@tonic-gate 	while (getmntent(fp, &mt) == 0) {
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 		/* Well, not each entry... some are meant to be ignored */
7567c478bd9Sstevel@tonic-gate 		if ((mt.mnt_mntopts != NULL) &&
7577c478bd9Sstevel@tonic-gate 		    (hasmntopt(&mt, OPT_IGNORE) != NULL))
7587c478bd9Sstevel@tonic-gate 			continue;
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 		if (cache_insert(cache, &mt) < 0) {
7617c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
7627c478bd9Sstevel@tonic-gate 			    "FILESYS: cache insertion failure (%s).\n",
7637c478bd9Sstevel@tonic-gate 			    strerror(errno));
7647c478bd9Sstevel@tonic-gate 			free_cache(&cache);
7657c478bd9Sstevel@tonic-gate 			(void) fclose(fp);
7667c478bd9Sstevel@tonic-gate 			errno = EFAULT;
7677c478bd9Sstevel@tonic-gate 			return (NULL);
7687c478bd9Sstevel@tonic-gate 		}
7697c478bd9Sstevel@tonic-gate 	}
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	/* Close the mnttab file */
7727c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	return (cache);
7757c478bd9Sstevel@tonic-gate }
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate /*
7787c478bd9Sstevel@tonic-gate  * free_cache()
7797c478bd9Sstevel@tonic-gate  *
7807c478bd9Sstevel@tonic-gate  *	Free up all the memory associated with a cache.
7817c478bd9Sstevel@tonic-gate  *
7827c478bd9Sstevel@tonic-gate  *	Locking: the cache must be locked before calling this function.
7837c478bd9Sstevel@tonic-gate  */
7847c478bd9Sstevel@tonic-gate static void
7857c478bd9Sstevel@tonic-gate free_cache(cache_t **cachep)
7867c478bd9Sstevel@tonic-gate {
7877c478bd9Sstevel@tonic-gate 	uint32_t index;
7887c478bd9Sstevel@tonic-gate 	hashentry_t *entry;
7897c478bd9Sstevel@tonic-gate 	hashentry_t *entry_tmp;
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	/* Do nothing with empty caches */
7927c478bd9Sstevel@tonic-gate 	if ((cachep == NULL) || (*cachep == NULL))
7937c478bd9Sstevel@tonic-gate 		return;
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	if ((*cachep)->mounts) {
7967c478bd9Sstevel@tonic-gate 		/* Walk through the hashtable, emptying it */
7977c478bd9Sstevel@tonic-gate 		for (index = 0; index < (*cachep)->hash_size; index++) {
7987c478bd9Sstevel@tonic-gate 			entry = (*cachep)->mounts[index];
7997c478bd9Sstevel@tonic-gate 			while (entry) {
8007c478bd9Sstevel@tonic-gate 				entry_tmp = entry->next;
8017c478bd9Sstevel@tonic-gate 				free_entry(&entry);
8027c478bd9Sstevel@tonic-gate 				entry = entry_tmp;
8037c478bd9Sstevel@tonic-gate 			}
8047c478bd9Sstevel@tonic-gate 		}
8057c478bd9Sstevel@tonic-gate 		free((*cachep)->mounts);
8067c478bd9Sstevel@tonic-gate 	}
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	free(*cachep);
8097c478bd9Sstevel@tonic-gate 	*cachep = NULL;
8107c478bd9Sstevel@tonic-gate }
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate /*
8137c478bd9Sstevel@tonic-gate  * free_entry()
8147c478bd9Sstevel@tonic-gate  *
8157c478bd9Sstevel@tonic-gate  *	Free up memory associated with a hashtable entry.
8167c478bd9Sstevel@tonic-gate  *
8177c478bd9Sstevel@tonic-gate  *	Locking: the cache must be locked before calling this function.
8187c478bd9Sstevel@tonic-gate  */
8197c478bd9Sstevel@tonic-gate static void
8207c478bd9Sstevel@tonic-gate free_entry(hashentry_t **entryp)
8217c478bd9Sstevel@tonic-gate {
8227c478bd9Sstevel@tonic-gate 	if (entryp) {
8237c478bd9Sstevel@tonic-gate 		if (*entryp) {
8247c478bd9Sstevel@tonic-gate 			if ((*entryp)->special)
8257c478bd9Sstevel@tonic-gate 				free((*entryp)->special);
82625e8c5aaSvikram 			if ((*entryp)->fstype)
82725e8c5aaSvikram 				free((*entryp)->fstype);
8287c478bd9Sstevel@tonic-gate 			free_list((*entryp)->mountps);
8297c478bd9Sstevel@tonic-gate 			free(*entryp);
8307c478bd9Sstevel@tonic-gate 		}
8317c478bd9Sstevel@tonic-gate 		*entryp = NULL;
8327c478bd9Sstevel@tonic-gate 	}
8337c478bd9Sstevel@tonic-gate }
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate /*
8367c478bd9Sstevel@tonic-gate  * free_list()
8377c478bd9Sstevel@tonic-gate  *
8387c478bd9Sstevel@tonic-gate  *	Free up memory associated with a null terminated list of names.
8397c478bd9Sstevel@tonic-gate  */
8407c478bd9Sstevel@tonic-gate static void
8417c478bd9Sstevel@tonic-gate free_list(char **list)
8427c478bd9Sstevel@tonic-gate {
8437c478bd9Sstevel@tonic-gate 	int i;
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	if (list) {
8467c478bd9Sstevel@tonic-gate 		for (i = 0; list[i] != NULL; i++)
8477c478bd9Sstevel@tonic-gate 			free(list[i]);
8487c478bd9Sstevel@tonic-gate 		free(list);
8497c478bd9Sstevel@tonic-gate 	}
8507c478bd9Sstevel@tonic-gate }
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate /*
8537c478bd9Sstevel@tonic-gate  * cache_sync()
8547c478bd9Sstevel@tonic-gate  *
8557c478bd9Sstevel@tonic-gate  *	Resynchronize the mnttab cache with the mnttab file.
8567c478bd9Sstevel@tonic-gate  *
8577c478bd9Sstevel@tonic-gate  *	Locking: the cache must be locked before calling this function.
8587c478bd9Sstevel@tonic-gate  *
8597c478bd9Sstevel@tonic-gate  *	Return Values: -1 with errno set on failure, 0 on success.
8607c478bd9Sstevel@tonic-gate  */
8617c478bd9Sstevel@tonic-gate static int
8627c478bd9Sstevel@tonic-gate cache_sync(rcm_handle_t *hd, cache_t **cachep)
8637c478bd9Sstevel@tonic-gate {
8647c478bd9Sstevel@tonic-gate 	uint32_t index;
8657c478bd9Sstevel@tonic-gate 	cache_t *new_cache;
8667c478bd9Sstevel@tonic-gate 	cache_t *old_cache;
8677c478bd9Sstevel@tonic-gate 	hashentry_t *entry;
8687c478bd9Sstevel@tonic-gate 	struct stat st;
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	/* Only accept valid arguments */
8717c478bd9Sstevel@tonic-gate 	if ((hd == NULL) || (cachep == NULL)) {
8727c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
8737c478bd9Sstevel@tonic-gate 		    "FILESYS: invalid arguments to cache_sync().\n");
8747c478bd9Sstevel@tonic-gate 		errno = EINVAL;
8757c478bd9Sstevel@tonic-gate 		return (-1);
8767c478bd9Sstevel@tonic-gate 	}
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	/* Do nothing if there's already an up-to-date cache */
8797c478bd9Sstevel@tonic-gate 	old_cache = *cachep;
8807c478bd9Sstevel@tonic-gate 	if (old_cache) {
8817c478bd9Sstevel@tonic-gate 		if (stat(MNTTAB, &st) == 0) {
8827c478bd9Sstevel@tonic-gate 			if (old_cache->timestamp >= st.st_mtime) {
8837c478bd9Sstevel@tonic-gate 				return (0);
8847c478bd9Sstevel@tonic-gate 			}
8857c478bd9Sstevel@tonic-gate 		} else {
8867c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_WARNING,
8877c478bd9Sstevel@tonic-gate 			    "FILESYS: failed to stat \"%s\", cache is stale "
8887c478bd9Sstevel@tonic-gate 			    "(%s).\n", MNTTAB, strerror(errno));
8897c478bd9Sstevel@tonic-gate 			errno = EIO;
8907c478bd9Sstevel@tonic-gate 			return (-1);
8917c478bd9Sstevel@tonic-gate 		}
8927c478bd9Sstevel@tonic-gate 	}
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 	/* Create a new cache based on the new mnttab file.  */
8957c478bd9Sstevel@tonic-gate 	if ((new_cache = cache_create()) == NULL) {
8967c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_WARNING,
8977c478bd9Sstevel@tonic-gate 		    "FILESYS: failed creating cache, cache is stale (%s).\n",
8987c478bd9Sstevel@tonic-gate 		    strerror(errno));
8997c478bd9Sstevel@tonic-gate 		errno = EIO;
9007c478bd9Sstevel@tonic-gate 		return (-1);
9017c478bd9Sstevel@tonic-gate 	}
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	/* Register any specials found in the new cache but not the old one */
9047c478bd9Sstevel@tonic-gate 	for (index = 0; index < new_cache->hash_size; index++) {
9057c478bd9Sstevel@tonic-gate 		for (entry = new_cache->mounts[index]; entry != NULL;
9067c478bd9Sstevel@tonic-gate 		    entry = entry->next) {
9077c478bd9Sstevel@tonic-gate 			if (cache_lookup(old_cache, entry->special) == NULL) {
9087c478bd9Sstevel@tonic-gate 				register_rsrc(hd, entry->special);
9097c478bd9Sstevel@tonic-gate 			}
9107c478bd9Sstevel@tonic-gate 		}
9117c478bd9Sstevel@tonic-gate 	}
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 	/* Pass the new cache pointer to the calling function */
9147c478bd9Sstevel@tonic-gate 	*cachep = new_cache;
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 	/* If there wasn't an old cache, return successfully now */
9177c478bd9Sstevel@tonic-gate 	if (old_cache == NULL)
9187c478bd9Sstevel@tonic-gate 		return (0);
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	/*
9217c478bd9Sstevel@tonic-gate 	 * If there was an old cache, then unregister whatever specials it
9227c478bd9Sstevel@tonic-gate 	 * contains that aren't in the new cache.  And then destroy the old
9237c478bd9Sstevel@tonic-gate 	 * cache.
9247c478bd9Sstevel@tonic-gate 	 */
9257c478bd9Sstevel@tonic-gate 	for (index = 0; index < old_cache->hash_size; index++) {
9267c478bd9Sstevel@tonic-gate 		for (entry = old_cache->mounts[index]; entry != NULL;
9277c478bd9Sstevel@tonic-gate 		    entry = entry->next) {
9287c478bd9Sstevel@tonic-gate 			if (cache_lookup(new_cache, entry->special) == NULL) {
9297c478bd9Sstevel@tonic-gate 				unregister_rsrc(hd, entry->special);
9307c478bd9Sstevel@tonic-gate 			}
9317c478bd9Sstevel@tonic-gate 		}
9327c478bd9Sstevel@tonic-gate 	}
9337c478bd9Sstevel@tonic-gate 	free_cache(&old_cache);
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 	return (0);
9367c478bd9Sstevel@tonic-gate }
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate /*
9397c478bd9Sstevel@tonic-gate  * cache_insert()
9407c478bd9Sstevel@tonic-gate  *
9417c478bd9Sstevel@tonic-gate  *	Given a cache and a mnttab entry, this routine inserts that entry in
94225e8c5aaSvikram  *	the cache.  The mnttab entry's special device and filesystem type
94325e8c5aaSvikram  *	is added to the 'mounts' hashtable of the cache, and the entry's
94425e8c5aaSvikram  *	mountp value is added to the list of associated mountpoints for the
94525e8c5aaSvikram  *	corresponding hashtable entry.
9467c478bd9Sstevel@tonic-gate  *
9477c478bd9Sstevel@tonic-gate  *	Locking: the cache must be locked before calling this function.
9487c478bd9Sstevel@tonic-gate  *
9497c478bd9Sstevel@tonic-gate  *	Return Values: -1 with errno set on failure, 0 on success.
9507c478bd9Sstevel@tonic-gate  */
9517c478bd9Sstevel@tonic-gate static int
9527c478bd9Sstevel@tonic-gate cache_insert(cache_t *cache, struct mnttab *mt)
9537c478bd9Sstevel@tonic-gate {
9547c478bd9Sstevel@tonic-gate 	uint32_t index;
9557c478bd9Sstevel@tonic-gate 	hashentry_t *entry;
9567c478bd9Sstevel@tonic-gate 	char **mountps;
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	/* Only accept valid arguments */
9597c478bd9Sstevel@tonic-gate 	if ((cache == NULL) ||
9607c478bd9Sstevel@tonic-gate 	    (cache->mounts == NULL) ||
9617c478bd9Sstevel@tonic-gate 	    (mt == NULL) ||
9627c478bd9Sstevel@tonic-gate 	    (mt->mnt_special == NULL) ||
96325e8c5aaSvikram 	    (mt->mnt_mountp == NULL) ||
96425e8c5aaSvikram 	    (mt->mnt_fstype == NULL)) {
9657c478bd9Sstevel@tonic-gate 		errno = EINVAL;
9667c478bd9Sstevel@tonic-gate 		return (-1);
9677c478bd9Sstevel@tonic-gate 	}
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	/*
9707c478bd9Sstevel@tonic-gate 	 * Disregard any non-loopback mounts whose special device names
9717c478bd9Sstevel@tonic-gate 	 * don't begin with "/dev".
9727c478bd9Sstevel@tonic-gate 	 */
9737c478bd9Sstevel@tonic-gate 	if ((strncmp(mt->mnt_special, "/dev", strlen("/dev")) != 0) &&
9747c478bd9Sstevel@tonic-gate 	    (strcmp(mt->mnt_fstype, "lofs") != 0))
9757c478bd9Sstevel@tonic-gate 		return (0);
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 	/*
9787c478bd9Sstevel@tonic-gate 	 * Find the special device's entry in the mounts hashtable, allocating
9797c478bd9Sstevel@tonic-gate 	 * a new entry if necessary.
9807c478bd9Sstevel@tonic-gate 	 */
9817c478bd9Sstevel@tonic-gate 	index = hash(cache->hash_size, mt->mnt_special);
9827c478bd9Sstevel@tonic-gate 	for (entry = cache->mounts[index]; entry != NULL; entry = entry->next) {
9837c478bd9Sstevel@tonic-gate 		if (strcmp(entry->special, mt->mnt_special) == 0)
9847c478bd9Sstevel@tonic-gate 			break;
9857c478bd9Sstevel@tonic-gate 	}
9867c478bd9Sstevel@tonic-gate 	if (entry == NULL) {
9877c478bd9Sstevel@tonic-gate 		entry = (hashentry_t *)calloc(1, sizeof (hashentry_t));
9887c478bd9Sstevel@tonic-gate 		if ((entry == NULL) ||
98925e8c5aaSvikram 		    ((entry->special = strdup(mt->mnt_special)) == NULL) ||
99025e8c5aaSvikram 		    ((entry->fstype = strdup(mt->mnt_fstype)) == NULL)) {
9917c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
9927c478bd9Sstevel@tonic-gate 			    "FILESYS: failed to allocate special device name "
99325e8c5aaSvikram 			    "or filesystem type: (%s).\n", strerror(errno));
9947c478bd9Sstevel@tonic-gate 			free_entry(&entry);
9957c478bd9Sstevel@tonic-gate 			errno = ENOMEM;
9967c478bd9Sstevel@tonic-gate 			return (-1);
9977c478bd9Sstevel@tonic-gate 		}
9987c478bd9Sstevel@tonic-gate 		entry->next = cache->mounts[index];
9997c478bd9Sstevel@tonic-gate 		cache->mounts[index] = entry;
10007c478bd9Sstevel@tonic-gate 	}
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	/*
10037c478bd9Sstevel@tonic-gate 	 * Keep entries in the list of mounts unique, so exit early if the
10047c478bd9Sstevel@tonic-gate 	 * mount is already in the list.
10057c478bd9Sstevel@tonic-gate 	 */
10067c478bd9Sstevel@tonic-gate 	for (index = 0; index < entry->n_mounts; index++) {
10077c478bd9Sstevel@tonic-gate 		if (strcmp(entry->mountps[index], mt->mnt_mountp) == 0)
10087c478bd9Sstevel@tonic-gate 			return (0);
10097c478bd9Sstevel@tonic-gate 	}
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 	/*
10127c478bd9Sstevel@tonic-gate 	 * Add this mountpoint to the list of mounts associated with the
10137c478bd9Sstevel@tonic-gate 	 * special device.
10147c478bd9Sstevel@tonic-gate 	 */
10157c478bd9Sstevel@tonic-gate 	mountps = (char **)realloc(entry->mountps,
10167c478bd9Sstevel@tonic-gate 	    (entry->n_mounts + 2) * sizeof (char *));
10177c478bd9Sstevel@tonic-gate 	if ((mountps == NULL) ||
10187c478bd9Sstevel@tonic-gate 	    ((mountps[entry->n_mounts] = strdup(mt->mnt_mountp)) == NULL)) {
10197c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
10207c478bd9Sstevel@tonic-gate 		    "FILESYS: failed to allocate mountpoint name (%s).\n",
10217c478bd9Sstevel@tonic-gate 		    strerror(errno));
10227c478bd9Sstevel@tonic-gate 		if (entry->n_mounts == 0) {
10237c478bd9Sstevel@tonic-gate 			cache->mounts[index] = entry->next;
10247c478bd9Sstevel@tonic-gate 			free_entry(&entry);
10257c478bd9Sstevel@tonic-gate 		}
10267c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
10277c478bd9Sstevel@tonic-gate 		return (-1);
10287c478bd9Sstevel@tonic-gate 	}
10297c478bd9Sstevel@tonic-gate 	mountps[entry->n_mounts + 1] = NULL;
10307c478bd9Sstevel@tonic-gate 	entry->n_mounts++;
10317c478bd9Sstevel@tonic-gate 	entry->mountps = mountps;
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	return (0);
10347c478bd9Sstevel@tonic-gate }
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate /*
10377c478bd9Sstevel@tonic-gate  * cache_lookup()
10387c478bd9Sstevel@tonic-gate  *
10397c478bd9Sstevel@tonic-gate  *	Searches the cached table of mounts for a special device entry.
10407c478bd9Sstevel@tonic-gate  *
10417c478bd9Sstevel@tonic-gate  *	Locking: the cache must be locked before calling this function.
10427c478bd9Sstevel@tonic-gate  *
10437c478bd9Sstevel@tonic-gate  *	Return Value: NULL with errno set if failure, pointer to existing
10447c478bd9Sstevel@tonic-gate  *	cache entry when successful.
10457c478bd9Sstevel@tonic-gate  */
10467c478bd9Sstevel@tonic-gate static hashentry_t *
10477c478bd9Sstevel@tonic-gate cache_lookup(cache_t *cache, char *rsrc)
10487c478bd9Sstevel@tonic-gate {
10497c478bd9Sstevel@tonic-gate 	uint32_t index;
10507c478bd9Sstevel@tonic-gate 	hashentry_t *entry;
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 	/* Only accept valid arguments */
10537c478bd9Sstevel@tonic-gate 	if ((cache == NULL) || (cache->mounts == NULL) || (rsrc == NULL)) {
10547c478bd9Sstevel@tonic-gate 		errno = EINVAL;
10557c478bd9Sstevel@tonic-gate 		return (NULL);
10567c478bd9Sstevel@tonic-gate 	}
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 	/* Search the cached mounts table for the resource's entry */
10597c478bd9Sstevel@tonic-gate 	index = hash(cache->hash_size, rsrc);
10607c478bd9Sstevel@tonic-gate 	if (cache->mounts[index]) {
10617c478bd9Sstevel@tonic-gate 		for (entry = cache->mounts[index]; entry != NULL;
10627c478bd9Sstevel@tonic-gate 		    entry = entry->next) {
10637c478bd9Sstevel@tonic-gate 			if (strcmp(entry->special, rsrc) == 0)
10647c478bd9Sstevel@tonic-gate 				return (entry);
10657c478bd9Sstevel@tonic-gate 		}
10667c478bd9Sstevel@tonic-gate 	}
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 	errno = ENOENT;
10697c478bd9Sstevel@tonic-gate 	return (NULL);
10707c478bd9Sstevel@tonic-gate }
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate /*
10737c478bd9Sstevel@tonic-gate  * Miscellaneous Functions
10747c478bd9Sstevel@tonic-gate  */
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate /*
10777c478bd9Sstevel@tonic-gate  * hash()
10787c478bd9Sstevel@tonic-gate  *
10797c478bd9Sstevel@tonic-gate  *	A naive hashing function that converts a string 's' to an index in a
10807c478bd9Sstevel@tonic-gate  * 	hash table of size 'h'.  It seems to spread entries around well enough.
10817c478bd9Sstevel@tonic-gate  */
10827c478bd9Sstevel@tonic-gate static uint32_t
10837c478bd9Sstevel@tonic-gate hash(uint32_t h, char *s)
10847c478bd9Sstevel@tonic-gate {
10857c478bd9Sstevel@tonic-gate 	uint32_t sum = 0;
10867c478bd9Sstevel@tonic-gate 	unsigned char *byte;
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 	if ((byte = (unsigned char *)s) != NULL) {
10897c478bd9Sstevel@tonic-gate 		while (*byte) {
10907c478bd9Sstevel@tonic-gate 			sum += 0x3F & (uint32_t)*byte;
10917c478bd9Sstevel@tonic-gate 			byte++;
10927c478bd9Sstevel@tonic-gate 		}
10937c478bd9Sstevel@tonic-gate 	}
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 	return (sum % h);
10967c478bd9Sstevel@tonic-gate }
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate /*
10997c478bd9Sstevel@tonic-gate  * register_rsrc()
11007c478bd9Sstevel@tonic-gate  *
11017c478bd9Sstevel@tonic-gate  *	Registers for any given resource, unless it's "/".
11027c478bd9Sstevel@tonic-gate  */
11037c478bd9Sstevel@tonic-gate static void
11047c478bd9Sstevel@tonic-gate register_rsrc(rcm_handle_t *hd, char *rsrc)
11057c478bd9Sstevel@tonic-gate {
11067c478bd9Sstevel@tonic-gate 	/* Only accept valid arguments */
11077c478bd9Sstevel@tonic-gate 	if ((hd == NULL) || (rsrc == NULL))
11087c478bd9Sstevel@tonic-gate 		return;
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 	/*
11117c478bd9Sstevel@tonic-gate 	 * Register any resource other than "/" or "/devices"
11127c478bd9Sstevel@tonic-gate 	 */
11137c478bd9Sstevel@tonic-gate 	if ((strcmp(rsrc, "/") != 0) && (strcmp(rsrc, "/devices") != 0)) {
11147c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG, "FILESYS: registering %s\n", rsrc);
11157c478bd9Sstevel@tonic-gate 		if (rcm_register_interest(hd, rsrc, 0, NULL) != RCM_SUCCESS) {
11167c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_WARNING,
11177c478bd9Sstevel@tonic-gate 			    "FILESYS: failed to register %s\n", rsrc);
11187c478bd9Sstevel@tonic-gate 		}
11197c478bd9Sstevel@tonic-gate 	}
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate }
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate /*
11247c478bd9Sstevel@tonic-gate  * unregister_rsrc()
11257c478bd9Sstevel@tonic-gate  *
11267c478bd9Sstevel@tonic-gate  *	Unregister a resource.  This does a little filtering since we know
11277c478bd9Sstevel@tonic-gate  *	"/" can't be registered, so we never bother unregistering for it.
11287c478bd9Sstevel@tonic-gate  */
11297c478bd9Sstevel@tonic-gate static void
11307c478bd9Sstevel@tonic-gate unregister_rsrc(rcm_handle_t *hd, char *rsrc)
11317c478bd9Sstevel@tonic-gate {
11327c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
11337c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate 	/* Unregister any resource other than "/" */
11367c478bd9Sstevel@tonic-gate 	if (strcmp(rsrc, "/") != 0) {
11377c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG, "FILESYS: unregistering %s\n", rsrc);
11387c478bd9Sstevel@tonic-gate 		(void) rcm_unregister_interest(hd, rsrc, 0);
11397c478bd9Sstevel@tonic-gate 	}
11407c478bd9Sstevel@tonic-gate }
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate /*
11437c478bd9Sstevel@tonic-gate  * create_message()
11447c478bd9Sstevel@tonic-gate  *
11457c478bd9Sstevel@tonic-gate  *	Given some header strings and a list of dependent names, this
11467c478bd9Sstevel@tonic-gate  *	constructs a single string.  If there's only one dependent, the
11477c478bd9Sstevel@tonic-gate  *	string consists of the first header and the only dependent appended
11487c478bd9Sstevel@tonic-gate  *	to the end of the string enclosed in quotemarks.  If there are
11497c478bd9Sstevel@tonic-gate  *	multiple dependents, then the string uses the second header and the
11507c478bd9Sstevel@tonic-gate  *	full list of dependents is appended at the end as a comma separated
11517c478bd9Sstevel@tonic-gate  *	list of names enclosed in quotemarks.
11527c478bd9Sstevel@tonic-gate  */
11537c478bd9Sstevel@tonic-gate static char *
11547c478bd9Sstevel@tonic-gate create_message(char *header, char *header_multi, char **dependents)
11557c478bd9Sstevel@tonic-gate {
11567c478bd9Sstevel@tonic-gate 	int i;
11577c478bd9Sstevel@tonic-gate 	size_t len;
11587c478bd9Sstevel@tonic-gate 	int ndependents;
11597c478bd9Sstevel@tonic-gate 	char *msg_buf;
11607c478bd9Sstevel@tonic-gate 	char *msg_header;
11617c478bd9Sstevel@tonic-gate 	char *separator = MSG_SEPARATOR;
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate 	assert(header != NULL);
11647c478bd9Sstevel@tonic-gate 	assert(header_multi != NULL);
11657c478bd9Sstevel@tonic-gate 	assert(dependents != NULL);
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate 	/* Count the number of dependents */
11687c478bd9Sstevel@tonic-gate 	for (ndependents = 0; dependents[ndependents] != NULL; ndependents++);
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate 	/* If there are no dependents, fail */
11717c478bd9Sstevel@tonic-gate 	if (ndependents == 0) {
11727c478bd9Sstevel@tonic-gate 		errno = ENOENT;
11737c478bd9Sstevel@tonic-gate 		return (NULL);
11747c478bd9Sstevel@tonic-gate 	}
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	/* Pick the appropriate header to use based on amount of dependents */
11777c478bd9Sstevel@tonic-gate 	if (ndependents == 1) {
11787c478bd9Sstevel@tonic-gate 		msg_header = header;
11797c478bd9Sstevel@tonic-gate 	} else {
11807c478bd9Sstevel@tonic-gate 		msg_header = header_multi;
11817c478bd9Sstevel@tonic-gate 	}
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	/* Compute the size required for the message buffer */
11847c478bd9Sstevel@tonic-gate 	len = strlen(msg_header) + 2;	/* +2 for the space and a NULL */
11857c478bd9Sstevel@tonic-gate 	for (i = 0; dependents[i] != NULL; i++)
11867c478bd9Sstevel@tonic-gate 		len += strlen(dependents[i]) + 2;	/* +2 for quotemarks */
11877c478bd9Sstevel@tonic-gate 	len += strlen(separator) * (ndependents - 1);
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 	/* Allocate the message buffer */
11907c478bd9Sstevel@tonic-gate 	if ((msg_buf = (char *)calloc(len, sizeof (char))) == NULL) {
11917c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
11927c478bd9Sstevel@tonic-gate 		    "FILESYS: failed to allocate message buffer (%s).\n",
11937c478bd9Sstevel@tonic-gate 		    strerror(errno));
11947c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
11957c478bd9Sstevel@tonic-gate 		return (NULL);
11967c478bd9Sstevel@tonic-gate 	}
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate 	/* Fill in the message buffer */
11997c478bd9Sstevel@tonic-gate 	(void) snprintf(msg_buf, len, "%s ", msg_header);
12007c478bd9Sstevel@tonic-gate 	for (i = 0; dependents[i] != NULL; i++) {
12017c478bd9Sstevel@tonic-gate 		(void) strlcat(msg_buf, "\"", len);
12027c478bd9Sstevel@tonic-gate 		(void) strlcat(msg_buf, dependents[i], len);
12037c478bd9Sstevel@tonic-gate 		(void) strlcat(msg_buf, "\"", len);
12047c478bd9Sstevel@tonic-gate 		if ((i + 1) < ndependents)
12057c478bd9Sstevel@tonic-gate 			(void) strlcat(msg_buf, separator, len);
12067c478bd9Sstevel@tonic-gate 	}
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate 	return (msg_buf);
12097c478bd9Sstevel@tonic-gate }
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate /*
12127c478bd9Sstevel@tonic-gate  * create_dependents()
12137c478bd9Sstevel@tonic-gate  *
12147c478bd9Sstevel@tonic-gate  *	Creates a copy of the list of dependent mounts associated with a
12157c478bd9Sstevel@tonic-gate  *	given hashtable entry from the cache.
12167c478bd9Sstevel@tonic-gate  *
12177c478bd9Sstevel@tonic-gate  *	Return Values: NULL with errno set on failure, the resulting list of
12187c478bd9Sstevel@tonic-gate  *	dependent resources when successful.
12197c478bd9Sstevel@tonic-gate  */
12207c478bd9Sstevel@tonic-gate static char **
12217c478bd9Sstevel@tonic-gate create_dependents(hashentry_t *entry)
12227c478bd9Sstevel@tonic-gate {
12237c478bd9Sstevel@tonic-gate 	int i;
12247c478bd9Sstevel@tonic-gate 	char **dependents;
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 	if (entry == NULL) {
12277c478bd9Sstevel@tonic-gate 		errno = EINVAL;
12287c478bd9Sstevel@tonic-gate 		return (NULL);
12297c478bd9Sstevel@tonic-gate 	}
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 	if (entry->n_mounts == 0) {
12327c478bd9Sstevel@tonic-gate 		errno = ENOENT;
12337c478bd9Sstevel@tonic-gate 		return (NULL);
12347c478bd9Sstevel@tonic-gate 	}
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 	/* Allocate space for the full dependency list */
12377c478bd9Sstevel@tonic-gate 	dependents = (char **)calloc(entry->n_mounts + 1, sizeof (char *));
12387c478bd9Sstevel@tonic-gate 	if (dependents == NULL) {
12397c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
12407c478bd9Sstevel@tonic-gate 		    "FILESYS: failed to allocate dependents (%s).\n",
12417c478bd9Sstevel@tonic-gate 		    strerror(errno));
12427c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
12437c478bd9Sstevel@tonic-gate 		return (NULL);
12447c478bd9Sstevel@tonic-gate 	}
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 	/* Copy all the dependent names into the new list of dependents */
12477c478bd9Sstevel@tonic-gate 	for (i = 0; i < entry->n_mounts; i++) {
12487c478bd9Sstevel@tonic-gate 		if ((dependents[i] = strdup(entry->mountps[i])) == NULL) {
12497c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
12507c478bd9Sstevel@tonic-gate 			    "FILESYS: failed to allocate dependent \"%s\" "
12517c478bd9Sstevel@tonic-gate 			    "(%s).\n", entry->mountps[i], strerror(errno));
12527c478bd9Sstevel@tonic-gate 			free_list(dependents);
12537c478bd9Sstevel@tonic-gate 			errno = ENOMEM;
12547c478bd9Sstevel@tonic-gate 			return (NULL);
12557c478bd9Sstevel@tonic-gate 		}
12567c478bd9Sstevel@tonic-gate 	}
12577c478bd9Sstevel@tonic-gate 
12587c478bd9Sstevel@tonic-gate 	return (dependents);
12597c478bd9Sstevel@tonic-gate }
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate /*
12627c478bd9Sstevel@tonic-gate  * detect_critical_failure()
12637c478bd9Sstevel@tonic-gate  *
12647c478bd9Sstevel@tonic-gate  *	Given a list of dependents, a place to store an error message, and
12657c478bd9Sstevel@tonic-gate  *	the flags associated with an operation, this function detects whether
12667c478bd9Sstevel@tonic-gate  *	or not the operation should fail due to the presence of any critical
12677c478bd9Sstevel@tonic-gate  *	filesystem resources.  When a failure is detected, an appropriate
12687c478bd9Sstevel@tonic-gate  *	error message is constructed and passed back to the caller.  This is
12697c478bd9Sstevel@tonic-gate  *	called during a suspend request operation.
12707c478bd9Sstevel@tonic-gate  *
12717c478bd9Sstevel@tonic-gate  *	Return Values: 0 when a critical resource failure shouldn't prevent
12727c478bd9Sstevel@tonic-gate  *	the operation, and 1 when such a failure condition does exist.
12737c478bd9Sstevel@tonic-gate  */
12747c478bd9Sstevel@tonic-gate static int
12757c478bd9Sstevel@tonic-gate detect_critical_failure(char **errorp, uint_t flags, char **dependents)
12767c478bd9Sstevel@tonic-gate {
12777c478bd9Sstevel@tonic-gate 	int i;
12787c478bd9Sstevel@tonic-gate 	int n_critical;
12797c478bd9Sstevel@tonic-gate 	char *tmp;
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate 	/* Do nothing if the operation is forced or there are no dependents */
12827c478bd9Sstevel@tonic-gate 	if ((errorp == NULL) || (flags & RCM_FORCE) || (dependents == NULL))
12837c478bd9Sstevel@tonic-gate 		return (0);
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 	/*
12867c478bd9Sstevel@tonic-gate 	 * Count how many of the dependents are critical, and shift the
12877c478bd9Sstevel@tonic-gate 	 * critical resources to the head of the list.
12887c478bd9Sstevel@tonic-gate 	 */
12897c478bd9Sstevel@tonic-gate 	if (dependents) {
12907c478bd9Sstevel@tonic-gate 		for (i = 0, n_critical = 0; dependents[i] != NULL; i++) {
12917c478bd9Sstevel@tonic-gate 			if (is_critical(dependents[i])) {
12927c478bd9Sstevel@tonic-gate 				if (n_critical != i) {
12937c478bd9Sstevel@tonic-gate 					tmp = dependents[n_critical];
12947c478bd9Sstevel@tonic-gate 					dependents[n_critical] = dependents[i];
12957c478bd9Sstevel@tonic-gate 					dependents[i] = tmp;
12967c478bd9Sstevel@tonic-gate 				}
12977c478bd9Sstevel@tonic-gate 				n_critical++;
12987c478bd9Sstevel@tonic-gate 			}
12997c478bd9Sstevel@tonic-gate 		}
13007c478bd9Sstevel@tonic-gate 	}
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 	/* If no criticals were found, do nothing and return */
13037c478bd9Sstevel@tonic-gate 	if (n_critical == 0)
13047c478bd9Sstevel@tonic-gate 		return (0);
13057c478bd9Sstevel@tonic-gate 
13067c478bd9Sstevel@tonic-gate 	/*
13077c478bd9Sstevel@tonic-gate 	 * Criticals were found.  Prune the list appropriately and construct
13087c478bd9Sstevel@tonic-gate 	 * an error message.
13097c478bd9Sstevel@tonic-gate 	 */
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 	/* Prune non-criticals out of the list */
13127c478bd9Sstevel@tonic-gate 	for (i = n_critical; dependents[i] != NULL; i++) {
13137c478bd9Sstevel@tonic-gate 		free(dependents[i]);
13147c478bd9Sstevel@tonic-gate 		dependents[i] = NULL;
13157c478bd9Sstevel@tonic-gate 	}
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate 	/* Construct the critical resource error message */
13187c478bd9Sstevel@tonic-gate 	*errorp = create_message(MSG_HDR_CRIT, MSG_HDR_CRIT_MULTI, dependents);
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate 	return (1);
13217c478bd9Sstevel@tonic-gate }
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate /*
13247c478bd9Sstevel@tonic-gate  * is_critical()
13257c478bd9Sstevel@tonic-gate  *
13267c478bd9Sstevel@tonic-gate  *	Test a resource to determine if it's critical to the system and thus
13277c478bd9Sstevel@tonic-gate  *	cannot be suspended.
13287c478bd9Sstevel@tonic-gate  *
13297c478bd9Sstevel@tonic-gate  *	Return Values: 1 if the named resource is critical, 0 if not.
13307c478bd9Sstevel@tonic-gate  */
13317c478bd9Sstevel@tonic-gate static int
13327c478bd9Sstevel@tonic-gate is_critical(char *rsrc)
13337c478bd9Sstevel@tonic-gate {
13347c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate 	if ((strcmp(rsrc, "/") == 0) ||
13377c478bd9Sstevel@tonic-gate 	    (strcmp(rsrc, "/usr") == 0) ||
133825e8c5aaSvikram 	    (strcmp(rsrc, "/lib") == 0) ||
13397c478bd9Sstevel@tonic-gate 	    (strcmp(rsrc, "/usr/lib") == 0) ||
134025e8c5aaSvikram 	    (strcmp(rsrc, "/bin") == 0) ||
13417c478bd9Sstevel@tonic-gate 	    (strcmp(rsrc, "/usr/bin") == 0) ||
13427c478bd9Sstevel@tonic-gate 	    (strcmp(rsrc, "/tmp") == 0) ||
13437c478bd9Sstevel@tonic-gate 	    (strcmp(rsrc, "/var") == 0) ||
13447c478bd9Sstevel@tonic-gate 	    (strcmp(rsrc, "/var/run") == 0) ||
13457c478bd9Sstevel@tonic-gate 	    (strcmp(rsrc, "/etc") == 0) ||
13467c478bd9Sstevel@tonic-gate 	    (strcmp(rsrc, "/etc/mnttab") == 0) ||
134725e8c5aaSvikram 	    (strcmp(rsrc, "/platform") == 0) ||
134825e8c5aaSvikram 	    (strcmp(rsrc, "/usr/platform") == 0) ||
134925e8c5aaSvikram 	    (strcmp(rsrc, "/sbin") == 0) ||
135025e8c5aaSvikram 	    (strcmp(rsrc, "/usr/sbin") == 0))
13517c478bd9Sstevel@tonic-gate 		return (1);
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 	return (0);
13547c478bd9Sstevel@tonic-gate }
13557c478bd9Sstevel@tonic-gate 
135625e8c5aaSvikram 
13577c478bd9Sstevel@tonic-gate /*
13587c478bd9Sstevel@tonic-gate  * use_cache()
13597c478bd9Sstevel@tonic-gate  *
13607c478bd9Sstevel@tonic-gate  *	This routine handles all the tasks necessary to lookup a resource
13617c478bd9Sstevel@tonic-gate  *	in the cache and extract a separate list of dependents for that
13627c478bd9Sstevel@tonic-gate  *	entry.  If an error occurs while doing this, an appropriate error
13637c478bd9Sstevel@tonic-gate  *	message is passed back to the caller.
13647c478bd9Sstevel@tonic-gate  *
13657c478bd9Sstevel@tonic-gate  *	Locking: the cache is locked for the whole duration of this function.
13667c478bd9Sstevel@tonic-gate  */
13677c478bd9Sstevel@tonic-gate static int
13687c478bd9Sstevel@tonic-gate use_cache(char *rsrc, char **errorp, char ***dependentsp)
13697c478bd9Sstevel@tonic-gate {
13707c478bd9Sstevel@tonic-gate 	hashentry_t *entry;
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
13737c478bd9Sstevel@tonic-gate 	if ((entry = cache_lookup(mnt_cache, rsrc)) == NULL) {
13747c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
13757c478bd9Sstevel@tonic-gate 		    "FILESYS: failed looking up \"%s\" in cache (%s).\n",
13767c478bd9Sstevel@tonic-gate 		    rsrc, strerror(errno));
13777c478bd9Sstevel@tonic-gate 		*errorp = strdup(MSG_FAIL_INTERNAL);
13787c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
13797c478bd9Sstevel@tonic-gate 		return (-1);
13807c478bd9Sstevel@tonic-gate 	}
13817c478bd9Sstevel@tonic-gate 	*dependentsp = create_dependents(entry);
13827c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate 	return (0);
13857c478bd9Sstevel@tonic-gate }
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate /*
13887c478bd9Sstevel@tonic-gate  * prune_dependents()
13897c478bd9Sstevel@tonic-gate  *
13907c478bd9Sstevel@tonic-gate  *	Before calling back into RCM with a list of dependents, the list
13917c478bd9Sstevel@tonic-gate  *	must be cleaned up a little.  To avoid infinite recursion, "/" and
13927c478bd9Sstevel@tonic-gate  *	the named resource must be pruned out of the list.
13937c478bd9Sstevel@tonic-gate  */
13947c478bd9Sstevel@tonic-gate static void
13957c478bd9Sstevel@tonic-gate prune_dependents(char **dependents, char *rsrc)
13967c478bd9Sstevel@tonic-gate {
13977c478bd9Sstevel@tonic-gate 	int i;
13987c478bd9Sstevel@tonic-gate 	int n;
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate 	if (dependents) {
14017c478bd9Sstevel@tonic-gate 
14027c478bd9Sstevel@tonic-gate 		/* Set 'n' to the total length of the list */
14037c478bd9Sstevel@tonic-gate 		for (n = 0; dependents[n] != NULL; n++);
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 		/*
14067c478bd9Sstevel@tonic-gate 		 * Move offending dependents to the tail of the list and
14077c478bd9Sstevel@tonic-gate 		 * then truncate the list.
14087c478bd9Sstevel@tonic-gate 		 */
14097c478bd9Sstevel@tonic-gate 		for (i = 0; dependents[i] != NULL; i++) {
14107c478bd9Sstevel@tonic-gate 			if ((strcmp(dependents[i], rsrc) == 0) ||
14117c478bd9Sstevel@tonic-gate 			    (strcmp(dependents[i], "/") == 0)) {
14127c478bd9Sstevel@tonic-gate 				free(dependents[i]);
14137c478bd9Sstevel@tonic-gate 				dependents[i] = dependents[n - 1];
14147c478bd9Sstevel@tonic-gate 				dependents[n] = NULL;
14157c478bd9Sstevel@tonic-gate 				i--;
14167c478bd9Sstevel@tonic-gate 				n--;
14177c478bd9Sstevel@tonic-gate 			}
14187c478bd9Sstevel@tonic-gate 		}
14197c478bd9Sstevel@tonic-gate 	}
14207c478bd9Sstevel@tonic-gate }
1421