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