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