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