1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <dirent.h> 29 #include <stdlib.h> 30 #include <stdio.h> 31 #include <string.h> 32 #include <synch.h> 33 #include <unistd.h> 34 #include <sys/errno.h> 35 #include <sys/types.h> 36 #include <sys/stat.h> 37 #include <sys/vfstab.h> 38 #include <fcntl.h> 39 #include <sys/wait.h> 40 #include <sys/fs/ufs_fs.h> 41 42 #include "libdiskmgt.h" 43 #include "disks_private.h" 44 45 /* 46 * The list of filesystem heuristic programs. 47 */ 48 struct heuristic { 49 struct heuristic *next; 50 char *prog; 51 char *type; 52 }; 53 54 struct vfstab_list { 55 char *special; 56 char *mountp; 57 struct vfstab_list *next; 58 }; 59 60 static struct vfstab_list *vfstab_listp = NULL; 61 static mutex_t vfstab_lock = DEFAULTMUTEX; 62 63 static time_t timestamp = 0; 64 65 static struct heuristic *hlist = NULL; 66 static int initialized = 0; 67 static mutex_t init_lock = DEFAULTMUTEX; 68 69 static int has_fs(char *prog, char *slice); 70 static int load_heuristics(); 71 static int add_use_record(struct vfstab *vp); 72 static int load_vfstab(); 73 static void free_vfstab(struct vfstab_list *listp); 74 75 /* 76 * Use the heuristics to check for a filesystem on the slice. 77 */ 78 int 79 inuse_fs(char *slice, nvlist_t *attrs, int *errp) 80 { 81 struct heuristic *hp; 82 time_t curr_time; 83 int found = 0; 84 85 86 *errp = 0; 87 88 if (slice == NULL) { 89 return (0); 90 } 91 92 /* 93 * We get the list of heuristic programs one time. 94 */ 95 (void) mutex_lock(&init_lock); 96 if (!initialized) { 97 *errp = load_heuristics(); 98 99 if (*errp == 0) { 100 initialized = 1; 101 } 102 } 103 (void) mutex_unlock(&init_lock); 104 105 /* Run each of the heuristics. */ 106 for (hp = hlist; hp; hp = hp->next) { 107 if (has_fs(hp->prog, slice)) { 108 libdiskmgt_add_str(attrs, DM_USED_BY, DM_USE_FS, errp); 109 libdiskmgt_add_str(attrs, DM_USED_NAME, hp->type, errp); 110 found = 1; 111 } 112 } 113 114 if (*errp != 0) 115 return (found); 116 117 /* 118 * Second heuristic used is the check for an entry in vfstab 119 */ 120 121 (void) mutex_lock(&vfstab_lock); 122 curr_time = time(NULL); 123 124 if (timestamp < curr_time && (curr_time - timestamp) > 60) { 125 free_vfstab(vfstab_listp); 126 *errp = load_vfstab(); 127 timestamp = curr_time; 128 } 129 130 if (*errp == 0) { 131 struct vfstab_list *listp; 132 listp = vfstab_listp; 133 134 while (listp != NULL) { 135 if (strcmp(slice, listp->special) == 0) { 136 char *mountp = ""; 137 138 if (listp->mountp != NULL) 139 mountp = listp->mountp; 140 141 libdiskmgt_add_str(attrs, DM_USED_BY, DM_USE_VFSTAB, errp); 142 libdiskmgt_add_str(attrs, DM_USED_NAME, mountp, errp); 143 found = 1; 144 } 145 listp = listp->next; 146 } 147 } 148 (void) mutex_unlock(&vfstab_lock); 149 return (found); 150 } 151 152 static int 153 has_fs(char *prog, char *slice) 154 { 155 pid_t pid; 156 int loc; 157 mode_t mode = S_IRUSR | S_IWUSR; 158 159 switch ((pid = fork1())) { 160 case 0: 161 /* child process */ 162 163 closefrom(1); 164 (void) open("/dev/null", O_WRONLY, mode); 165 (void) open("/dev/null", O_WRONLY, mode); 166 (void) execl(prog, "fstyp", slice, NULL); 167 _exit(1); 168 break; 169 170 case -1: 171 return (0); 172 173 default: 174 /* parent process */ 175 break; 176 } 177 178 (void) waitpid(pid, &loc, 0); 179 180 if (WIFEXITED(loc) && WEXITSTATUS(loc) == 0) { 181 return (1); 182 } 183 184 return (0); 185 } 186 187 /* 188 * Create a list of filesystem heuristic programs. 189 */ 190 static int 191 load_heuristics() 192 { 193 DIR *dirp; 194 195 if ((dirp = opendir("/usr/lib/fs")) != NULL) { 196 struct dirent *dp; 197 198 while ((dp = readdir(dirp)) != NULL) { 199 char path[MAXPATHLEN]; 200 struct stat buf; 201 DIR *subdirp; 202 203 /* skip known dirs */ 204 if (strcmp(dp->d_name, ".") == 0 || 205 strcmp(dp->d_name, "..") == 0) { 206 continue; 207 } 208 209 /* 210 * Skip checking for ZFS filesystems. We know that 211 * inuse_zpool() will have already been called, which does a 212 * better job of checking anyway. More importantly, an unused 213 * hot spare will still claim to have a ZFS filesystem because 214 * it doesn't do the same level of checks. 215 */ 216 if (strcmp(dp->d_name, "zfs") == 0) 217 continue; 218 219 (void) snprintf(path, sizeof (path), "/usr/lib/fs/%s", 220 dp->d_name); 221 222 if (stat(path, &buf) != 0 || !S_ISDIR(buf.st_mode)) { 223 continue; 224 } 225 226 if ((subdirp = opendir(path)) != NULL) { 227 struct dirent *sdp; 228 229 while ((sdp = readdir(subdirp)) != NULL) { 230 231 if (strcmp(sdp->d_name, "fstyp") == 0) { 232 char progpath[MAXPATHLEN]; 233 234 (void) snprintf(progpath, sizeof (progpath), 235 "/usr/lib/fs/%s/fstyp", dp->d_name); 236 237 if (stat(progpath, &buf) == 0 && 238 S_ISREG(buf.st_mode)) { 239 240 struct heuristic *hp; 241 242 hp = (struct heuristic *) 243 malloc(sizeof (struct heuristic)); 244 245 if (hp == NULL) { 246 (void) closedir(subdirp); 247 (void) closedir(dirp); 248 return (ENOMEM); 249 } 250 251 if ((hp->prog = strdup(progpath)) == NULL) { 252 (void) closedir(subdirp); 253 (void) closedir(dirp); 254 return (ENOMEM); 255 } 256 257 if ((hp->type = strdup(dp->d_name)) == NULL) { 258 (void) closedir(subdirp); 259 (void) closedir(dirp); 260 return (ENOMEM); 261 } 262 263 hp->next = hlist; 264 hlist = hp; 265 } 266 267 break; 268 } 269 } 270 271 (void) closedir(subdirp); 272 } 273 } 274 275 (void) closedir(dirp); 276 } 277 278 return (0); 279 } 280 281 static int 282 load_vfstab() 283 { 284 FILE *fp; 285 struct vfstab vp; 286 int status = 1; 287 288 fp = fopen(VFSTAB, "r"); 289 if (fp != NULL) { 290 (void) memset(&vp, 0, sizeof (struct vfstab)); 291 while (getvfsent(fp, &vp) == 0) { 292 status = add_use_record(&vp); 293 if (status != 0) { 294 (void) fclose(fp); 295 return (status); 296 } 297 (void) memset(&vp, 0, sizeof (struct vfstab)); 298 } 299 (void) fclose(fp); 300 status = 0; 301 } 302 303 return (status); 304 } 305 306 static int 307 add_use_record(struct vfstab *vp) 308 { 309 struct vfstab_list *vfsp; 310 311 vfsp = (struct vfstab_list *)malloc(sizeof (struct vfstab_list)); 312 if (vfsp == NULL) { 313 return (ENOMEM); 314 } 315 316 vfsp->special = strdup(vp->vfs_special); 317 if (vfsp->special == NULL) { 318 free(vfsp); 319 return (ENOMEM); 320 } 321 322 if (vp->vfs_mountp != NULL) { 323 vfsp->mountp = strdup(vp->vfs_mountp); 324 if (vfsp->mountp == NULL) { 325 free(vfsp); 326 return (ENOMEM); 327 } 328 } else { 329 vfsp->mountp = NULL; 330 } 331 332 vfsp->next = vfstab_listp; 333 vfstab_listp = vfsp; 334 335 return (0); 336 } 337 338 static void 339 free_vfstab(struct vfstab_list *listp) 340 { 341 struct vfstab_list *nextp; 342 343 while (listp != NULL) { 344 nextp = listp->next; 345 free((void *)listp->special); 346 free((void *)listp->mountp); 347 free((void *)listp); 348 listp = nextp; 349 } 350 351 vfstab_listp = NULL; 352 } 353