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 */
48struct heuristic {
49	struct heuristic	*next;
50	char			*prog;
51	char			*type;
52};
53
54struct vfstab_list {
55	char	*special;
56	char	*mountp;
57	struct vfstab_list 	*next;
58};
59
60static struct vfstab_list	*vfstab_listp = NULL;
61static	mutex_t	vfstab_lock = DEFAULTMUTEX;
62
63static	time_t	timestamp = 0;
64
65static struct heuristic	*hlist = NULL;
66static int		initialized = 0;
67static mutex_t		init_lock = DEFAULTMUTEX;
68
69static int	has_fs(char *prog, char *slice);
70static int	load_heuristics();
71static int	add_use_record(struct vfstab *vp);
72static int	load_vfstab();
73static void	free_vfstab(struct vfstab_list *listp);
74
75/*
76 * Use the heuristics to check for a filesystem on the slice.
77 */
78int
79inuse_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
152static int
153has_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 */
190static int
191load_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
281static int
282load_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
306static int
307add_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
338static void
339free_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