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 2004 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 break; 146 } 147 listp = listp->next; 148 } 149 } 150 (void) mutex_unlock(&vfstab_lock); 151 return (found); 152 } 153 154 static int 155 has_fs(char *prog, char *slice) 156 { 157 pid_t pid; 158 int loc; 159 mode_t mode = S_IRUSR | S_IWUSR; 160 161 switch ((pid = fork1())) { 162 case 0: 163 /* child process */ 164 165 closefrom(1); 166 (void) open("/dev/null", O_WRONLY, mode); 167 (void) open("/dev/null", O_WRONLY, mode); 168 (void) execl(prog, "fstyp", slice, NULL); 169 _exit(1); 170 break; 171 172 case -1: 173 return (0); 174 175 default: 176 /* parent process */ 177 break; 178 } 179 180 (void) waitpid(pid, &loc, 0); 181 182 if (WIFEXITED(loc) && WEXITSTATUS(loc) == 0) { 183 return (1); 184 } 185 186 return (0); 187 } 188 189 /* 190 * Create a list of filesystem heuristic programs. 191 */ 192 static int 193 load_heuristics() 194 { 195 DIR *dirp; 196 197 if ((dirp = opendir("/usr/lib/fs")) != NULL) { 198 struct dirent *dp; 199 200 while ((dp = readdir(dirp)) != NULL) { 201 char path[MAXPATHLEN]; 202 struct stat buf; 203 DIR *subdirp; 204 205 /* skip known dirs */ 206 if (strcmp(dp->d_name, ".") == 0 || 207 strcmp(dp->d_name, "..") == 0) { 208 continue; 209 } 210 211 (void) snprintf(path, sizeof (path), "/usr/lib/fs/%s", 212 dp->d_name); 213 214 if (stat(path, &buf) != 0 || !(buf.st_mode & S_IFDIR)) { 215 continue; 216 } 217 218 if ((subdirp = opendir(path)) != NULL) { 219 struct dirent *sdp; 220 221 while ((sdp = readdir(subdirp)) != NULL) { 222 223 if (strcmp(sdp->d_name, "fstyp") == 0) { 224 char progpath[MAXPATHLEN]; 225 226 (void) snprintf(progpath, sizeof (progpath), 227 "/usr/lib/fs/%s/fstyp", dp->d_name); 228 229 if (stat(progpath, &buf) == 0 && 230 buf.st_mode & S_IFREG) { 231 232 struct heuristic *hp; 233 234 hp = (struct heuristic *) 235 malloc(sizeof (struct heuristic)); 236 237 if (hp == NULL) { 238 (void) closedir(subdirp); 239 (void) closedir(dirp); 240 return (ENOMEM); 241 } 242 243 if ((hp->prog = strdup(progpath)) == NULL) { 244 (void) closedir(subdirp); 245 (void) closedir(dirp); 246 return (ENOMEM); 247 } 248 249 if ((hp->type = strdup(dp->d_name)) == NULL) { 250 (void) closedir(subdirp); 251 (void) closedir(dirp); 252 return (ENOMEM); 253 } 254 255 hp->next = hlist; 256 hlist = hp; 257 } 258 259 break; 260 } 261 } 262 263 (void) closedir(subdirp); 264 } 265 } 266 267 (void) closedir(dirp); 268 } 269 270 return (0); 271 } 272 273 static int 274 load_vfstab() 275 { 276 FILE *fp; 277 struct vfstab vp; 278 int status = 1; 279 280 fp = fopen(VFSTAB, "r"); 281 if (fp != NULL) { 282 (void) memset(&vp, 0, sizeof (struct vfstab)); 283 while (getvfsent(fp, &vp) == 0) { 284 status = add_use_record(&vp); 285 if (status != 0) { 286 (void) fclose(fp); 287 return (status); 288 } 289 (void) memset(&vp, 0, sizeof (struct vfstab)); 290 } 291 (void) fclose(fp); 292 status = 0; 293 } 294 295 return (status); 296 } 297 298 static int 299 add_use_record(struct vfstab *vp) 300 { 301 struct vfstab_list *vfsp; 302 303 vfsp = (struct vfstab_list *)malloc(sizeof (struct vfstab_list)); 304 if (vfsp == NULL) { 305 return (ENOMEM); 306 } 307 308 vfsp->special = strdup(vp->vfs_special); 309 if (vfsp->special == NULL) { 310 free(vfsp); 311 return (ENOMEM); 312 } 313 314 if (vp->vfs_mountp != NULL) { 315 vfsp->mountp = strdup(vp->vfs_mountp); 316 if (vfsp->mountp == NULL) { 317 free(vfsp); 318 return (ENOMEM); 319 } 320 } else { 321 vfsp->mountp = NULL; 322 } 323 324 vfsp->next = vfstab_listp; 325 vfstab_listp = vfsp; 326 327 return (0); 328 } 329 330 static void 331 free_vfstab(struct vfstab_list *listp) 332 { 333 struct vfstab_list *nextp; 334 335 while (listp != NULL) { 336 nextp = listp->next; 337 free((void *)listp->special); 338 free((void *)listp->mountp); 339 free((void *)listp); 340 listp = nextp; 341 } 342 343 vfstab_listp = NULL; 344 } 345