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