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