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