10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*3377Seschrock  * Common Development and Distribution License (the "License").
6*3377Seschrock  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*3377Seschrock  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <dirent.h>
290Sstevel@tonic-gate #include <stdlib.h>
300Sstevel@tonic-gate #include <stdio.h>
310Sstevel@tonic-gate #include <string.h>
320Sstevel@tonic-gate #include <synch.h>
330Sstevel@tonic-gate #include <unistd.h>
340Sstevel@tonic-gate #include <sys/errno.h>
350Sstevel@tonic-gate #include <sys/types.h>
360Sstevel@tonic-gate #include <sys/stat.h>
370Sstevel@tonic-gate #include <sys/vfstab.h>
380Sstevel@tonic-gate #include <fcntl.h>
390Sstevel@tonic-gate #include <sys/wait.h>
400Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
410Sstevel@tonic-gate 
420Sstevel@tonic-gate #include "libdiskmgt.h"
430Sstevel@tonic-gate #include "disks_private.h"
440Sstevel@tonic-gate 
450Sstevel@tonic-gate /*
460Sstevel@tonic-gate  * The list of filesystem heuristic programs.
470Sstevel@tonic-gate  */
480Sstevel@tonic-gate struct heuristic {
490Sstevel@tonic-gate 	struct heuristic	*next;
500Sstevel@tonic-gate 	char			*prog;
510Sstevel@tonic-gate 	char			*type;
520Sstevel@tonic-gate };
530Sstevel@tonic-gate 
540Sstevel@tonic-gate struct vfstab_list {
550Sstevel@tonic-gate 	char	*special;
560Sstevel@tonic-gate 	char	*mountp;
570Sstevel@tonic-gate 	struct vfstab_list 	*next;
580Sstevel@tonic-gate };
590Sstevel@tonic-gate 
600Sstevel@tonic-gate static struct vfstab_list	*vfstab_listp = NULL;
610Sstevel@tonic-gate static	mutex_t	vfstab_lock = DEFAULTMUTEX;
620Sstevel@tonic-gate 
630Sstevel@tonic-gate static	time_t	timestamp = 0;
640Sstevel@tonic-gate 
650Sstevel@tonic-gate static struct heuristic	*hlist = NULL;
660Sstevel@tonic-gate static int		initialized = 0;
670Sstevel@tonic-gate static mutex_t		init_lock = DEFAULTMUTEX;
680Sstevel@tonic-gate 
690Sstevel@tonic-gate static int	has_fs(char *prog, char *slice);
700Sstevel@tonic-gate static int	load_heuristics();
710Sstevel@tonic-gate static int	add_use_record(struct vfstab *vp);
720Sstevel@tonic-gate static int	load_vfstab();
730Sstevel@tonic-gate static void	free_vfstab(struct vfstab_list *listp);
740Sstevel@tonic-gate 
750Sstevel@tonic-gate /*
760Sstevel@tonic-gate  * Use the heuristics to check for a filesystem on the slice.
770Sstevel@tonic-gate  */
780Sstevel@tonic-gate int
790Sstevel@tonic-gate inuse_fs(char *slice, nvlist_t *attrs, int *errp)
800Sstevel@tonic-gate {
810Sstevel@tonic-gate 	struct 	heuristic	*hp;
820Sstevel@tonic-gate 	time_t	curr_time;
830Sstevel@tonic-gate 	int	found = 0;
840Sstevel@tonic-gate 
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	*errp = 0;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	if (slice == NULL) {
890Sstevel@tonic-gate 	    return (0);
900Sstevel@tonic-gate 	}
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	/*
930Sstevel@tonic-gate 	 * We get the list of heuristic programs one time.
940Sstevel@tonic-gate 	 */
950Sstevel@tonic-gate 	(void) mutex_lock(&init_lock);
960Sstevel@tonic-gate 	if (!initialized) {
970Sstevel@tonic-gate 	    *errp = load_heuristics();
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	    if (*errp == 0) {
1000Sstevel@tonic-gate 		initialized = 1;
1010Sstevel@tonic-gate 	    }
1020Sstevel@tonic-gate 	}
1030Sstevel@tonic-gate 	(void) mutex_unlock(&init_lock);
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 	/* Run each of the heuristics. */
1060Sstevel@tonic-gate 	for (hp = hlist; hp; hp = hp->next) {
1070Sstevel@tonic-gate 	    if (has_fs(hp->prog, slice)) {
1080Sstevel@tonic-gate 		libdiskmgt_add_str(attrs, DM_USED_BY, DM_USE_FS, errp);
1090Sstevel@tonic-gate 		libdiskmgt_add_str(attrs, DM_USED_NAME, hp->type, errp);
1100Sstevel@tonic-gate 		found = 1;
1110Sstevel@tonic-gate 	    }
1120Sstevel@tonic-gate 	}
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 	if (*errp != 0)
1150Sstevel@tonic-gate 		return (found);
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	/*
1180Sstevel@tonic-gate 	 * Second heuristic used is the check for an entry in vfstab
1190Sstevel@tonic-gate 	 */
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	(void) mutex_lock(&vfstab_lock);
1220Sstevel@tonic-gate 	curr_time = time(NULL);
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	if (timestamp < curr_time && (curr_time - timestamp) > 60) {
1250Sstevel@tonic-gate 		free_vfstab(vfstab_listp);
1260Sstevel@tonic-gate 		*errp = load_vfstab();
1270Sstevel@tonic-gate 		timestamp = curr_time;
1280Sstevel@tonic-gate 	}
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	if (*errp == 0) {
1310Sstevel@tonic-gate 	    struct vfstab_list	*listp;
1320Sstevel@tonic-gate 	    listp = vfstab_listp;
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	    while (listp != NULL) {
1350Sstevel@tonic-gate 		if (strcmp(slice, listp->special) == 0) {
1360Sstevel@tonic-gate 		    char *mountp = "";
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 		    if (listp->mountp != NULL)
1390Sstevel@tonic-gate 			mountp = listp->mountp;
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 		    libdiskmgt_add_str(attrs, DM_USED_BY, DM_USE_VFSTAB, errp);
1420Sstevel@tonic-gate 		    libdiskmgt_add_str(attrs, DM_USED_NAME, mountp, errp);
1430Sstevel@tonic-gate 		    found = 1;
1440Sstevel@tonic-gate 		}
1450Sstevel@tonic-gate 		listp = listp->next;
1460Sstevel@tonic-gate 	    }
1470Sstevel@tonic-gate 	}
1480Sstevel@tonic-gate 	(void) mutex_unlock(&vfstab_lock);
1490Sstevel@tonic-gate 	return (found);
1500Sstevel@tonic-gate }
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate static int
1530Sstevel@tonic-gate has_fs(char *prog, char *slice)
1540Sstevel@tonic-gate {
1550Sstevel@tonic-gate 	pid_t	pid;
1560Sstevel@tonic-gate 	int	loc;
1570Sstevel@tonic-gate 	mode_t	mode = S_IRUSR | S_IWUSR;
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 	switch ((pid = fork1())) {
1600Sstevel@tonic-gate 	case 0:
1610Sstevel@tonic-gate 	    /* child process */
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	    closefrom(1);
1640Sstevel@tonic-gate 	    (void) open("/dev/null", O_WRONLY, mode);
1650Sstevel@tonic-gate 	    (void) open("/dev/null", O_WRONLY, mode);
1660Sstevel@tonic-gate 	    (void) execl(prog, "fstyp", slice, NULL);
1670Sstevel@tonic-gate 	    _exit(1);
1680Sstevel@tonic-gate 	    break;
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	case -1:
1710Sstevel@tonic-gate 	    return (0);
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	default:
1740Sstevel@tonic-gate 	    /* parent process */
1750Sstevel@tonic-gate 	    break;
1760Sstevel@tonic-gate 	}
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	(void) waitpid(pid, &loc, 0);
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	if (WIFEXITED(loc) && WEXITSTATUS(loc) == 0) {
1810Sstevel@tonic-gate 	    return (1);
1820Sstevel@tonic-gate 	}
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 	return (0);
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate /*
1880Sstevel@tonic-gate  * Create a list of filesystem heuristic programs.
1890Sstevel@tonic-gate  */
1900Sstevel@tonic-gate static int
1910Sstevel@tonic-gate load_heuristics()
1920Sstevel@tonic-gate {
1930Sstevel@tonic-gate 	DIR	*dirp;
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	if ((dirp = opendir("/usr/lib/fs")) != NULL) {
1960Sstevel@tonic-gate 	    struct dirent   *dp;
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	    while ((dp = readdir(dirp)) != NULL) {
1990Sstevel@tonic-gate 		char		path[MAXPATHLEN];
2000Sstevel@tonic-gate 		struct stat	buf;
2010Sstevel@tonic-gate 		DIR		*subdirp;
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 		/* skip known dirs */
2040Sstevel@tonic-gate 		if (strcmp(dp->d_name, ".") == 0 ||
2050Sstevel@tonic-gate 		    strcmp(dp->d_name, "..") == 0) {
2060Sstevel@tonic-gate 		    continue;
2070Sstevel@tonic-gate 		}
2080Sstevel@tonic-gate 
209*3377Seschrock 		/*
210*3377Seschrock 		 * Skip checking for ZFS filesystems.  We know that
211*3377Seschrock 		 * inuse_zpool() will have already been called, which does a
212*3377Seschrock 		 * better job of checking anyway.  More importantly, an unused
213*3377Seschrock 		 * hot spare will still claim to have a ZFS filesystem because
214*3377Seschrock 		 * it doesn't do the same level of checks.
215*3377Seschrock 		 */
216*3377Seschrock 		if (strcmp(dp->d_name, "zfs") == 0)
217*3377Seschrock 			continue;
218*3377Seschrock 
2190Sstevel@tonic-gate 		(void) snprintf(path, sizeof (path), "/usr/lib/fs/%s",
2200Sstevel@tonic-gate 		    dp->d_name);
2210Sstevel@tonic-gate 
222871Scasper 		if (stat(path, &buf) != 0 || !S_ISDIR(buf.st_mode)) {
2230Sstevel@tonic-gate 		    continue;
2240Sstevel@tonic-gate 		}
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 		if ((subdirp = opendir(path)) != NULL) {
2270Sstevel@tonic-gate 		    struct dirent   *sdp;
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 		    while ((sdp = readdir(subdirp)) != NULL) {
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 			if (strcmp(sdp->d_name, "fstyp") == 0) {
2320Sstevel@tonic-gate 			    char progpath[MAXPATHLEN];
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 			    (void) snprintf(progpath, sizeof (progpath),
2350Sstevel@tonic-gate 				"/usr/lib/fs/%s/fstyp", dp->d_name);
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 			    if (stat(progpath, &buf) == 0 &&
238871Scasper 				S_ISREG(buf.st_mode)) {
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 				struct heuristic *hp;
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 				hp = (struct heuristic *)
2430Sstevel@tonic-gate 				    malloc(sizeof (struct heuristic));
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 				if (hp == NULL) {
2460Sstevel@tonic-gate 				    (void) closedir(subdirp);
2470Sstevel@tonic-gate 				    (void) closedir(dirp);
2480Sstevel@tonic-gate 				    return (ENOMEM);
2490Sstevel@tonic-gate 				}
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 				if ((hp->prog = strdup(progpath)) == NULL) {
2520Sstevel@tonic-gate 				    (void) closedir(subdirp);
2530Sstevel@tonic-gate 				    (void) closedir(dirp);
2540Sstevel@tonic-gate 				    return (ENOMEM);
2550Sstevel@tonic-gate 				}
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 				if ((hp->type = strdup(dp->d_name)) == NULL) {
2580Sstevel@tonic-gate 				    (void) closedir(subdirp);
2590Sstevel@tonic-gate 				    (void) closedir(dirp);
2600Sstevel@tonic-gate 				    return (ENOMEM);
2610Sstevel@tonic-gate 				}
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 				hp->next = hlist;
2640Sstevel@tonic-gate 				hlist = hp;
2650Sstevel@tonic-gate 			    }
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 			    break;
2680Sstevel@tonic-gate 			}
2690Sstevel@tonic-gate 		    }
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 		    (void) closedir(subdirp);
2720Sstevel@tonic-gate 		}
2730Sstevel@tonic-gate 	    }
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	    (void) closedir(dirp);
2760Sstevel@tonic-gate 	}
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	return (0);
2790Sstevel@tonic-gate }
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate static int
2820Sstevel@tonic-gate load_vfstab()
2830Sstevel@tonic-gate {
2840Sstevel@tonic-gate 	FILE	*fp;
2850Sstevel@tonic-gate 	struct	vfstab vp;
2860Sstevel@tonic-gate 	int	status = 1;
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	fp = fopen(VFSTAB, "r");
2890Sstevel@tonic-gate 	if (fp != NULL) {
2900Sstevel@tonic-gate 	    (void) memset(&vp, 0, sizeof (struct vfstab));
2910Sstevel@tonic-gate 	    while (getvfsent(fp, &vp) == 0) {
2920Sstevel@tonic-gate 		    status = add_use_record(&vp);
2930Sstevel@tonic-gate 		    if (status != 0) {
2940Sstevel@tonic-gate 			(void) fclose(fp);
2950Sstevel@tonic-gate 			return (status);
2960Sstevel@tonic-gate 		    }
2970Sstevel@tonic-gate 		(void) memset(&vp, 0, sizeof (struct vfstab));
2980Sstevel@tonic-gate 	    }
2990Sstevel@tonic-gate 	    (void) fclose(fp);
3000Sstevel@tonic-gate 	    status = 0;
3010Sstevel@tonic-gate 	}
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	return (status);
3040Sstevel@tonic-gate }
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate static int
3070Sstevel@tonic-gate add_use_record(struct vfstab *vp)
3080Sstevel@tonic-gate {
3090Sstevel@tonic-gate 	struct 	vfstab_list	*vfsp;
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	vfsp = (struct vfstab_list *)malloc(sizeof (struct vfstab_list));
3120Sstevel@tonic-gate 	if (vfsp == NULL) {
3130Sstevel@tonic-gate 	    return (ENOMEM);
3140Sstevel@tonic-gate 	}
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	vfsp->special = strdup(vp->vfs_special);
3170Sstevel@tonic-gate 	if (vfsp->special == NULL) {
3180Sstevel@tonic-gate 	    free(vfsp);
3190Sstevel@tonic-gate 	    return (ENOMEM);
3200Sstevel@tonic-gate 	}
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	if (vp->vfs_mountp != NULL) {
3230Sstevel@tonic-gate 	    vfsp->mountp = strdup(vp->vfs_mountp);
3240Sstevel@tonic-gate 	    if (vfsp->mountp == NULL) {
3250Sstevel@tonic-gate 		free(vfsp);
3260Sstevel@tonic-gate 		return (ENOMEM);
3270Sstevel@tonic-gate 	    }
3280Sstevel@tonic-gate 	} else {
3290Sstevel@tonic-gate 	    vfsp->mountp = NULL;
3300Sstevel@tonic-gate 	}
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	vfsp->next = vfstab_listp;
3330Sstevel@tonic-gate 	vfstab_listp = vfsp;
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	return (0);
3360Sstevel@tonic-gate }
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate static void
3390Sstevel@tonic-gate free_vfstab(struct vfstab_list *listp)
3400Sstevel@tonic-gate {
3410Sstevel@tonic-gate 	struct vfstab_list	*nextp;
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	while (listp != NULL) {
3440Sstevel@tonic-gate 	    nextp = listp->next;
3450Sstevel@tonic-gate 	    free((void *)listp->special);
3460Sstevel@tonic-gate 	    free((void *)listp->mountp);
3470Sstevel@tonic-gate 	    free((void *)listp);
3480Sstevel@tonic-gate 	    listp = nextp;
3490Sstevel@tonic-gate 	}
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	vfstab_listp = NULL;
3520Sstevel@tonic-gate }
353