xref: /illumos-gate/usr/src/lib/libdiskmgt/common/inuse_mnt.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 /*
30  * Creates and maintains a cache of mount points.
31  */
32 
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <synch.h>
37 #include <thread.h>
38 #include <unistd.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42 #include <sys/mnttab.h>
43 #include <sys/swap.h>
44 
45 #include "libdiskmgt.h"
46 #include "disks_private.h"
47 
48 /*
49  * The list of mount point entries in /etc/mnttab
50  */
51 
52 struct mntpnt_list {
53 	struct mntpnt_list	*next;
54 	char			*special;
55 	char			*mountp;
56 };
57 
58 static struct mntpnt_list	*mntpoint_listp = NULL;
59 static rwlock_t			mntpoint_lock = DEFAULTRWLOCK;
60 static int			initialized = 0;
61 static mutex_t			init_lock = DEFAULTMUTEX;
62 
63 static boolean_t	diff_mnttab(int send_event, struct mntpnt_list *firstp,
64 			    struct mntpnt_list *secondp);
65 static void		free_mnttab(struct mntpnt_list *listp);
66 static boolean_t	in_list(struct mntpnt_list *elementp,
67 			    struct mntpnt_list *listp);
68 static int		load_mnttab(int send_event);
69 static void		watch_mnttab();
70 
71 /*
72  * Search the list of devices from /etc/mnttab to find the mount point
73  * for the specified device.
74  */
75 int
76 inuse_mnt(char *slice, nvlist_t *attrs, int *errp)
77 {
78 	struct mntpnt_list	*listp;
79 	int			found = 0;
80 
81 	*errp = 0;
82 	if (slice == NULL) {
83 	    return (found);
84 	}
85 
86 	(void) mutex_lock(&init_lock);
87 	if (!initialized) {
88 	    thread_t	mnttab_thread;
89 
90 	    /* load the mntpnt cache */
91 	    *errp = load_mnttab(B_FALSE);
92 
93 	    if (*errp == 0) {
94 		/* start a thread to monitor the mnttab */
95 		*errp = thr_create(NULL, NULL, (void *(*)(void *))watch_mnttab,
96 		    NULL, THR_NEW_LWP | THR_DAEMON, &mnttab_thread);
97 	    }
98 
99 	    if (*errp == 0) {
100 		initialized = 1;
101 	    }
102 	}
103 	(void) mutex_unlock(&init_lock);
104 
105 	(void) rw_rdlock(&mntpoint_lock);
106 	listp = mntpoint_listp;
107 	while (listp != NULL) {
108 	    if (libdiskmgt_str_eq(slice, listp->special)) {
109 		libdiskmgt_add_str(attrs, DM_USED_BY, DM_USE_MOUNT, errp);
110 		libdiskmgt_add_str(attrs, DM_USED_NAME, listp->mountp, errp);
111 		found = 1;
112 		break;
113 	    }
114 	    listp = listp->next;
115 	}
116 	(void) rw_unlock(&mntpoint_lock);
117 
118 	return (found);
119 }
120 
121 /*
122  * Return true if the lists are different.  Send an event for each different
123  * device.
124  */
125 static boolean_t
126 diff_mnttab(int send_event, struct mntpnt_list *firstp,
127     struct mntpnt_list *secondp)
128 {
129 	boolean_t		different = B_FALSE;
130 	struct mntpnt_list	*listp;
131 
132 	listp = firstp;
133 	while (listp != NULL) {
134 	    if (! in_list(listp, secondp)) {
135 		/* not in new list, so was mounted and now unmounted */
136 		if (send_event) {
137 		    events_new_slice_event(listp->special, DM_EV_TCHANGE);
138 		}
139 		different = B_TRUE;
140 	    }
141 	    listp = listp->next;
142 	}
143 
144 	listp = secondp;
145 	while (listp != NULL) {
146 	    if (! in_list(listp, firstp)) {
147 		/* not in orig list, so this is a new mount */
148 		if (send_event) {
149 		    events_new_slice_event(listp->special, DM_EV_TCHANGE);
150 		}
151 		different = B_TRUE;
152 	    }
153 	    listp = listp->next;
154 	}
155 
156 	return (different);
157 }
158 
159 /*
160  * free_mnttab()
161  *
162  * Free the list of metadevices from /etc/mnttab.
163  */
164 static void
165 free_mnttab(struct mntpnt_list	*listp) {
166 
167 	struct mntpnt_list	*nextp;
168 
169 	while (listp != NULL) {
170 		nextp = listp->next;
171 		free((void *)listp->special);
172 		free((void *)listp->mountp);
173 		free((void *)listp);
174 		listp = nextp;
175 	}
176 }
177 
178 /*
179  * Return true if the element is in the list.
180  */
181 static boolean_t
182 in_list(struct mntpnt_list *elementp, struct mntpnt_list *listp)
183 {
184 	while (listp != NULL) {
185 	    if (libdiskmgt_str_eq(elementp->special, listp->special) &&
186 		libdiskmgt_str_eq(elementp->mountp, listp->mountp)) {
187 		return (B_TRUE);
188 	    }
189 	    listp = listp->next;
190 	}
191 
192 	return (B_FALSE);
193 }
194 
195 /*
196  * load_mnttab()
197  *
198  * Create a list of devices from /etc/mnttab and swap.
199  * return 1 if the list has changed, 0 if the list is still the same
200  */
201 static int
202 load_mnttab(int send_event)
203 {
204 
205 	struct mntpnt_list	*currp;
206 	FILE			*fp;
207 	struct mntpnt_list	*headp;
208 	int			num;
209 	struct mntpnt_list	*prevp;
210 
211 	headp = NULL;
212 	prevp = NULL;
213 
214 	/* get the mnttab entries */
215 	if ((fp = fopen("/etc/mnttab", "r")) != NULL) {
216 
217 		struct mnttab	entry;
218 
219 		while (getmntent(fp, &entry) == 0) {
220 
221 			/*
222 			 * Ignore entries that are incomplete or that are not
223 			 * devices (skips network mounts, automounter entries,
224 			 * /proc, etc.).
225 			 */
226 			if (entry.mnt_special == NULL ||
227 				entry.mnt_mountp == NULL ||
228 				strncmp(entry.mnt_special, "/dev", 4) != 0) {
229 				continue;
230 			}
231 
232 			currp = (struct mntpnt_list *)calloc((size_t)1,
233 				(size_t)sizeof (struct mntpnt_list));
234 
235 			if (currp == NULL) {
236 				/*
237 				 * out of memory, free what we have and return
238 				 */
239 				free_mnttab(headp);
240 				(void) fclose(fp);
241 				return (ENOMEM);
242 			}
243 
244 			if (headp == NULL) {
245 				headp = currp;
246 			} else {
247 				prevp->next = currp;
248 			}
249 
250 			currp->next = NULL;
251 
252 			currp->special = strdup(entry.mnt_special);
253 			if (currp->special == NULL) {
254 				/*
255 				 * out of memory, free what we have and return
256 				 */
257 				free_mnttab(headp);
258 				(void) fclose(fp);
259 				return (ENOMEM);
260 			}
261 
262 			currp->mountp = strdup(entry.mnt_mountp);
263 			if (currp->mountp == NULL) {
264 				/*
265 				 * out of memory, free what we have and return
266 				 */
267 				free_mnttab(headp);
268 				(void) fclose(fp);
269 				return (ENOMEM);
270 			}
271 
272 			prevp = currp;
273 		}
274 
275 		(void) fclose(fp);
276 	}
277 
278 	/* get the swap entries */
279 	if ((num = swapctl(SC_GETNSWP, NULL)) > -1) {
280 
281 	    struct swaptable 	*st;
282 	    struct swapent	*swapent;
283 	    int			i;
284 	    char		*path;
285 	    char		*pathstart;
286 	    char		fullpath[MAXPATHLEN+1];
287 
288 	    st = malloc((size_t)((num * sizeof (swapent_t)) + sizeof (int)));
289 	    if (st == NULL) {
290 		/* out of memory, free what we have and return */
291 		free_mnttab(headp);
292 		return (ENOMEM);
293 	    }
294 
295 	    path = malloc(num * MAXPATHLEN);
296 	    if (path == NULL) {
297 		/* out of memory, free what we have and return */
298 		free(st);
299 		free_mnttab(headp);
300 		return (ENOMEM);
301 	    }
302 	    pathstart = path;
303 
304 	    swapent = st->swt_ent;
305 	    for (i = 0; i < num; i++, swapent++) {
306 		swapent->ste_path = path;
307 		path += MAXPATHLEN;
308 	    }
309 
310 	    st->swt_n = num;
311 	    if ((num = swapctl(SC_LIST, st)) >= 0) {
312 		swapent = st->swt_ent;
313 		for (i = 0; i < num; i++, swapent++) {
314 
315 		    currp = (struct mntpnt_list *)
316 			calloc((size_t)1, (size_t)sizeof (struct mntpnt_list));
317 
318 		    if (currp == NULL) {
319 			/* out of memory, free what we have and return */
320 			free((void *)st);
321 			free((void *)pathstart);
322 			free_mnttab(headp);
323 			return (ENOMEM);
324 		    }
325 
326 		    if (headp == NULL) {
327 			headp = currp;
328 		    } else {
329 			prevp->next = currp;
330 		    }
331 
332 		    currp->next = NULL;
333 
334 		    if (*swapent->ste_path != '/') {
335 			(void) snprintf(fullpath, sizeof (fullpath), "/dev/%s",
336 			    swapent->ste_path);
337 		    } else {
338 			(void) strlcpy(fullpath, swapent->ste_path,
339 			    sizeof (fullpath));
340 		    }
341 
342 		    currp->special = strdup(fullpath);
343 		    if (currp->special == NULL) {
344 			/* out of memory, free what we have and return */
345 			free(st);
346 			free(pathstart);
347 			free_mnttab(headp);
348 			return (ENOMEM);
349 		    }
350 
351 		    currp->mountp = strdup("swap");
352 		    if (currp->mountp == NULL) {
353 			/* out of memory, free what we have and return */
354 			free(st);
355 			free(pathstart);
356 			free_mnttab(headp);
357 			return (ENOMEM);
358 		    }
359 
360 		    prevp = currp;
361 		}
362 	    }
363 
364 	    free(st);
365 	    free(pathstart);
366 	}
367 
368 	/* note that we unlock the mutex in both paths of this if statement */
369 	(void) rw_wrlock(&mntpoint_lock);
370 	if (diff_mnttab(send_event, mntpoint_listp, headp) == B_TRUE) {
371 		struct mntpnt_list	*tmpp;
372 
373 		tmpp = mntpoint_listp;
374 		mntpoint_listp = headp;
375 		(void) rw_unlock(&mntpoint_lock);
376 
377 		/* free the old list */
378 		free_mnttab(tmpp);
379 	} else {
380 		(void) rw_unlock(&mntpoint_lock);
381 		/* no change that we care about, so keep the current list */
382 		free_mnttab(headp);
383 	}
384 	return (0);
385 }
386 
387 /*
388  * This is a thread that runs forever, watching for changes in the mnttab
389  * that would cause us to flush and reload the cache of mnt entries.  Only
390  * changes to /dev devices will cause the cache to be flushed and reloaded.
391  */
392 static void
393 watch_mnttab()
394 {
395 	struct pollfd fds[1];
396 	int res;
397 
398 	if ((fds[0].fd = open("/etc/mnttab", O_RDONLY)) != -1) {
399 
400 	    char buf[81];
401 
402 	    /* do the initial read so we don't get the event right away */
403 	    (void) read(fds[0].fd, buf, (size_t)(sizeof (buf) - 1));
404 	    (void) lseek(fds[0].fd, 0, SEEK_SET);
405 
406 	    fds[0].events = POLLRDBAND;
407 	    while (res = poll(fds, (nfds_t)1, -1)) {
408 		if (res <= 0)
409 		    continue;
410 
411 		(void) load_mnttab(B_TRUE);
412 
413 		(void) read(fds[0].fd, buf, (size_t)(sizeof (buf) - 1));
414 		(void) lseek(fds[0].fd, 0, SEEK_SET);
415 	    }
416 	}
417 }
418