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 *
rcm_mod_init()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 *
rcm_mod_info()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
rcm_mod_fini()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
mnt_register(rcm_handle_t * hd)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
mnt_unregister(rcm_handle_t * hd)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
mnt_offline(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,rcm_info_t ** dependent_info)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
mnt_online(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flag,char ** errorp,rcm_info_t ** dependent_reason)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
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)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
mnt_suspend(rcm_handle_t * hd,char * rsrc,id_t id,timespec_t * interval,uint_t flag,char ** errorp,rcm_info_t ** depend_info)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
mnt_resume(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flag,char ** errorp,rcm_info_t ** depend_info)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
get_spec(char * line,char * spec,size_t ssz)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
path_match(char * rsrc,char * spec)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
disable_vfstab_entry(char * rsrc)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
mnt_remove(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flag,char ** errorp,rcm_info_t ** depend_info)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 *
cache_create()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
free_cache(cache_t ** cachep)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
free_entry(hashentry_t ** entryp)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
free_list(char ** list)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
cache_sync(rcm_handle_t * hd,cache_t ** cachep)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
cache_insert(cache_t * cache,struct mnttab * mt)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 *
cache_lookup(cache_t * cache,char * rsrc)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
hash(uint32_t h,char * s)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
register_rsrc(rcm_handle_t * hd,char * rsrc)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
unregister_rsrc(rcm_handle_t * hd,char * rsrc)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 *
create_message(char * header,char * header_multi,char ** dependents)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 **
create_dependents(hashentry_t * entry)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
detect_critical_failure(char ** errorp,uint_t flags,char ** dependents)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
is_critical(char * rsrc)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
use_cache(char * rsrc,char ** errorp,char *** dependentsp)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
prune_dependents(char ** dependents,char * rsrc)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