xref: /illumos-gate/usr/src/lib/libdiskmgt/common/inuse_fs.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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