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