1 /* $NetBSD: autofs_linux.c,v 1.1.1.2 2009/03/20 20:26:51 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1999-2003 Ion Badulescu 5 * Copyright (c) 1997-2009 Erez Zadok 6 * Copyright (c) 1990 Jan-Simon Pendry 7 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 8 * Copyright (c) 1990 The Regents of the University of California. 9 * All rights reserved. 10 * 11 * This code is derived from software contributed to Berkeley by 12 * Jan-Simon Pendry at Imperial College, London. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgment: 24 * This product includes software developed by the University of 25 * California, Berkeley and its contributors. 26 * 4. Neither the name of the University nor the names of its contributors 27 * may be used to endorse or promote products derived from this software 28 * without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 * SUCH DAMAGE. 41 * 42 * 43 * File: am-utils/conf/autofs/autofs_linux.c 44 * 45 */ 46 47 /* 48 * Automounter filesystem for Linux 49 */ 50 51 #ifdef HAVE_CONFIG_H 52 # include <config.h> 53 #endif /* HAVE_CONFIG_H */ 54 #include <am_defs.h> 55 #include <amd.h> 56 57 #ifdef HAVE_FS_AUTOFS 58 59 /* 60 * MACROS: 61 */ 62 63 #define AUTOFS_MIN_VERSION 3 64 #define AUTOFS_MAX_VERSION AUTOFS_MAX_PROTO_VERSION 65 66 67 /* 68 * STRUCTURES: 69 */ 70 71 /* 72 * VARIABLES: 73 */ 74 75 static int autofs_max_fds; 76 static am_node **hash; 77 static int *list; 78 static int numfds = 0; 79 static int bind_works = 1; 80 81 82 static void 83 hash_init(void) 84 { 85 int i; 86 struct rlimit rlim; 87 88 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { 89 plog(XLOG_ERROR, "getrlimit failed, defaulting to 256 fd's"); 90 autofs_max_fds = 256; 91 } else { 92 autofs_max_fds = (rlim.rlim_cur > 1024) ? 1024 : rlim.rlim_cur; 93 plog(XLOG_INFO, "%d fd's available for autofs", autofs_max_fds); 94 } 95 96 list = malloc(autofs_max_fds * sizeof(*list)); 97 hash = malloc(autofs_max_fds * sizeof(*hash)); 98 99 for (i = 0 ; i < autofs_max_fds; i++) { 100 hash[i] = NULL; 101 list[i] = -1; 102 } 103 } 104 105 106 static void 107 hash_insert(int fd, am_node *mp) 108 { 109 if (hash[fd] != 0) 110 plog(XLOG_ERROR, "file descriptor %d already in the hash", fd); 111 112 hash[fd] = mp; 113 list[numfds] = fd; 114 numfds++; 115 } 116 117 118 static void 119 hash_delete(int fd) 120 { 121 int i; 122 123 if (hash[fd] == 0) 124 plog(XLOG_WARNING, "file descriptor %d not in the hash", fd); 125 126 hash[fd] = NULL; 127 numfds--; 128 for (i = 0; i < numfds; i++) 129 if (list[i] == fd) { 130 list[i] = list[numfds]; 131 break; 132 } 133 } 134 135 136 int 137 autofs_get_fh(am_node *mp) 138 { 139 int fds[2]; 140 autofs_fh_t *fh; 141 142 plog(XLOG_DEBUG, "autofs_get_fh for %s", mp->am_path); 143 if (pipe(fds) < 0) 144 return errno; 145 146 /* sanity check */ 147 if (fds[0] > autofs_max_fds) { 148 close(fds[0]); 149 close(fds[1]); 150 return EMFILE; 151 } 152 153 fh = ALLOC(autofs_fh_t); 154 fh->fd = fds[0]; 155 fh->kernelfd = fds[1]; 156 fh->ioctlfd = -1; 157 fh->pending_mounts = NULL; 158 fh->pending_umounts = NULL; 159 160 mp->am_autofs_fh = fh; 161 162 return 0; 163 } 164 165 166 void 167 autofs_mounted(am_node *mp) 168 { 169 autofs_fh_t *fh = mp->am_autofs_fh; 170 unsigned long timeout = gopt.am_timeo; 171 172 close(fh->kernelfd); 173 fh->kernelfd = -1; 174 175 autofs_get_mp(mp); 176 177 /* Get autofs protocol version */ 178 if (ioctl(fh->ioctlfd, AUTOFS_IOC_PROTOVER, &fh->version) < 0) { 179 plog(XLOG_ERROR, "AUTOFS_IOC_PROTOVER: %s", strerror(errno)); 180 fh->version = AUTOFS_MIN_VERSION; 181 plog(XLOG_ERROR, "autofs: assuming protocol version %d", fh->version); 182 } else 183 plog(XLOG_INFO, "autofs: using protocol version %d", fh->version); 184 185 /* set expiration timeout */ 186 if (ioctl(fh->ioctlfd, AUTOFS_IOC_SETTIMEOUT, &timeout) < 0) 187 plog(XLOG_ERROR, "AUTOFS_IOC_SETTIMEOUT: %s", strerror(errno)); 188 189 /* tell the daemon to call us for expirations */ 190 mp->am_autofs_ttl = clocktime(NULL) + gopt.am_timeo_w; 191 } 192 193 194 void 195 autofs_get_mp(am_node *mp) 196 { 197 autofs_fh_t *fh = mp->am_autofs_fh; 198 dlog("autofs: getting mount point"); 199 if (fh->ioctlfd < 0) 200 fh->ioctlfd = open(mp->am_path, O_RDONLY); 201 hash_insert(fh->fd, mp); 202 } 203 204 205 void 206 autofs_release_mp(am_node *mp) 207 { 208 autofs_fh_t *fh = mp->am_autofs_fh; 209 dlog("autofs: releasing mount point"); 210 if (fh->ioctlfd >= 0) { 211 close(fh->ioctlfd); 212 fh->ioctlfd = -1; 213 } 214 /* 215 * take the kernel fd out of the hash/fdset 216 * so select() doesn't go crazy if the umount succeeds 217 */ 218 if (fh->fd >= 0) 219 hash_delete(fh->fd); 220 } 221 222 223 void 224 autofs_release_fh(am_node *mp) 225 { 226 autofs_fh_t *fh = mp->am_autofs_fh; 227 struct autofs_pending_mount **pp, *p; 228 struct autofs_pending_umount **upp, *up; 229 230 dlog("autofs: releasing file handle"); 231 if (fh) { 232 /* 233 * if a mount succeeded, the kernel fd was closed on 234 * the amd side, so it might have been reused. 235 * we set it to -1 after closing it, to avoid the problem. 236 */ 237 if (fh->kernelfd >= 0) 238 close(fh->kernelfd); 239 240 if (fh->ioctlfd >= 0) 241 close(fh->ioctlfd); 242 243 if (fh->fd >= 0) 244 close(fh->fd); 245 246 pp = &fh->pending_mounts; 247 while (*pp) { 248 p = *pp; 249 XFREE(p->name); 250 *pp = p->next; 251 XFREE(p); 252 } 253 254 upp = &fh->pending_umounts; 255 while (*upp) { 256 up = *upp; 257 XFREE(up->name); 258 *upp = up->next; 259 XFREE(up); 260 } 261 262 XFREE(fh); 263 mp->am_autofs_fh = NULL; 264 } 265 } 266 267 268 void 269 autofs_add_fdset(fd_set *readfds) 270 { 271 int i; 272 for (i = 0; i < numfds; i++) 273 FD_SET(list[i], readfds); 274 } 275 276 277 static int 278 autofs_get_pkt(int fd, char *buf, int bytes) 279 { 280 int i; 281 282 do { 283 i = read(fd, buf, bytes); 284 285 if (i <= 0) 286 break; 287 288 buf += i; 289 bytes -= i; 290 } while (bytes); 291 292 return bytes; 293 } 294 295 296 static void 297 send_fail(int fd, unsigned long token) 298 { 299 if (token == 0) 300 return; 301 if (ioctl(fd, AUTOFS_IOC_FAIL, token) < 0) 302 plog(XLOG_ERROR, "AUTOFS_IOC_FAIL: %s", strerror(errno)); 303 } 304 305 306 static void 307 send_ready(int fd, unsigned long token) 308 { 309 if (token == 0) 310 return; 311 if (ioctl(fd, AUTOFS_IOC_READY, token) < 0) 312 plog(XLOG_ERROR, "AUTOFS_IOC_READY: %s", strerror(errno)); 313 } 314 315 316 static void 317 autofs_lookup_failed(am_node *mp, char *name) 318 { 319 autofs_fh_t *fh = mp->am_autofs_fh; 320 struct autofs_pending_mount **pp, *p; 321 322 pp = &fh->pending_mounts; 323 while (*pp && !STREQ((*pp)->name, name)) 324 pp = &(*pp)->next; 325 326 /* sanity check */ 327 if (*pp == NULL) 328 return; 329 330 p = *pp; 331 plog(XLOG_INFO, "autofs: lookup of %s failed", name); 332 send_fail(fh->ioctlfd, p->wait_queue_token); 333 334 XFREE(p->name); 335 *pp = p->next; 336 XFREE(p); 337 } 338 339 340 static void 341 autofs_expire_one(am_node *mp, char *name, unsigned long token) 342 { 343 autofs_fh_t *fh; 344 am_node *ap; 345 struct autofs_pending_umount *p; 346 char *ap_path; 347 348 fh = mp->am_autofs_fh; 349 350 ap_path = str3cat(NULL, mp->am_path, "/", name); 351 if (amuDebug(D_TRACE)) 352 plog(XLOG_DEBUG, "\tumount(%s)", ap_path); 353 354 p = fh->pending_umounts; 355 while (p && p->wait_queue_token != token) 356 p = p->next; 357 358 if (p) { 359 /* already pending */ 360 dlog("Umounting of %s already pending", ap_path); 361 amd_stats.d_drops++; 362 goto out; 363 } 364 365 ap = find_ap(ap_path); 366 if (ap == NULL) { 367 /* not found??? not sure what to do here... */ 368 send_fail(fh->ioctlfd, token); 369 goto out; 370 } 371 372 p = ALLOC(struct autofs_pending_umount); 373 p->wait_queue_token = token; 374 p->name = strdup(name); 375 p->next = fh->pending_umounts; 376 fh->pending_umounts = p; 377 378 unmount_mp(ap); 379 380 out: 381 XFREE(ap_path); 382 } 383 384 385 static void 386 autofs_handle_expire(am_node *mp, struct autofs_packet_expire *pkt) 387 { 388 autofs_expire_one(mp, pkt->name, 0); 389 } 390 391 392 #if AUTOFS_MAX_VERSION >= 4 393 static void 394 autofs_handle_expire_multi(am_node *mp, struct autofs_packet_expire_multi *pkt) 395 { 396 autofs_expire_one(mp, pkt->name, pkt->wait_queue_token); 397 } 398 #endif /* AUTOFS_MAX_VERSION >= 4 */ 399 400 401 static void 402 autofs_handle_missing(am_node *mp, struct autofs_packet_missing *pkt) 403 { 404 autofs_fh_t *fh; 405 mntfs *mf; 406 am_node *ap; 407 struct autofs_pending_mount *p; 408 int error; 409 410 mf = mp->am_mnt; 411 fh = mp->am_autofs_fh; 412 413 p = fh->pending_mounts; 414 while (p && p->wait_queue_token != pkt->wait_queue_token) 415 p = p->next; 416 417 if (p) { 418 /* already pending */ 419 dlog("Mounting of %s/%s already pending", 420 mp->am_path, pkt->name); 421 amd_stats.d_drops++; 422 return; 423 } 424 425 p = ALLOC(struct autofs_pending_mount); 426 p->wait_queue_token = pkt->wait_queue_token; 427 p->name = strdup(pkt->name); 428 p->next = fh->pending_mounts; 429 fh->pending_mounts = p; 430 431 if (amuDebug(D_TRACE)) 432 plog(XLOG_DEBUG, "\tlookup(%s, %s)", mp->am_path, pkt->name); 433 ap = mf->mf_ops->lookup_child(mp, pkt->name, &error, VLOOK_CREATE); 434 if (ap && error < 0) 435 ap = mf->mf_ops->mount_child(ap, &error); 436 437 /* some of the rest can be done in amfs_auto_cont */ 438 439 if (ap == 0) { 440 if (error < 0) { 441 dlog("Mount still pending, not sending autofs reply yet"); 442 return; 443 } 444 autofs_lookup_failed(mp, pkt->name); 445 } 446 mp->am_stats.s_lookup++; 447 } 448 449 450 int 451 autofs_handle_fdset(fd_set *readfds, int nsel) 452 { 453 int i; 454 union autofs_packet_union pkt; 455 autofs_fh_t *fh; 456 am_node *mp; 457 458 for (i = 0; nsel && i < numfds; i++) { 459 if (!FD_ISSET(list[i], readfds)) 460 continue; 461 462 nsel--; 463 FD_CLR(list[i], readfds); 464 mp = hash[list[i]]; 465 fh = mp->am_autofs_fh; 466 467 if (autofs_get_pkt(fh->fd, (char *) &pkt, 468 sizeof(union autofs_packet_union))) 469 continue; 470 471 switch (pkt.hdr.type) { 472 case autofs_ptype_missing: 473 autofs_handle_missing(mp, &pkt.missing); 474 break; 475 case autofs_ptype_expire: 476 autofs_handle_expire(mp, &pkt.expire); 477 break; 478 #if AUTOFS_MAX_VERSION >= 4 479 case autofs_ptype_expire_multi: 480 autofs_handle_expire_multi(mp, &pkt.expire_multi); 481 break; 482 #endif /* AUTOFS_MAX_VERSION >= 4 */ 483 default: 484 plog(XLOG_ERROR, "Unknown autofs packet type %d", 485 pkt.hdr.type); 486 } 487 } 488 return nsel; 489 } 490 491 492 int 493 create_autofs_service(void) 494 { 495 hash_init(); 496 497 /* not the best place, but... */ 498 if (linux_version_code() < KERNEL_VERSION(2,4,0)) 499 bind_works = 0; 500 501 return 0; 502 } 503 504 505 int 506 destroy_autofs_service(void) 507 { 508 /* Nothing to do */ 509 return 0; 510 } 511 512 513 static int 514 autofs_bind_umount(char *mountpoint) 515 { 516 int err = 1; 517 #ifdef MNT2_GEN_OPT_BIND 518 if (bind_works && gopt.flags & CFM_AUTOFS_USE_LOFS) { 519 struct stat buf; 520 521 if ((err = lstat(mountpoint, &buf))) 522 return errno; 523 if (S_ISLNK(buf.st_mode)) 524 goto use_symlink; 525 526 plog(XLOG_INFO, "autofs: un-bind-mounting %s", mountpoint); 527 err = umount_fs(mountpoint, mnttab_file_name, 1); 528 if (err) 529 plog(XLOG_INFO, "autofs: unmounting %s failed: %m", mountpoint); 530 else 531 err = rmdir(mountpoint); 532 goto out; 533 } 534 #endif /* MNT2_GEN_OPT_BIND */ 535 use_symlink: 536 plog(XLOG_INFO, "autofs: deleting symlink %s", mountpoint); 537 err = unlink(mountpoint); 538 539 out: 540 if (err) 541 return errno; 542 return 0; 543 } 544 545 546 int 547 autofs_mount_fs(am_node *mp, mntfs *mf) 548 { 549 char *target, *target2 = NULL; 550 int err = 0; 551 552 if (mf->mf_flags & MFF_ON_AUTOFS) { 553 if ((err = mkdir(mp->am_path, 0555))) 554 return errno; 555 } 556 557 /* 558 * For sublinks, we could end up here with an already mounted f/s. 559 * Don't do anything in that case. 560 */ 561 if (!(mf->mf_flags & MFF_MOUNTED)) 562 err = mf->mf_ops->mount_fs(mp, mf); 563 564 if (err) { 565 if (mf->mf_flags & MFF_ON_AUTOFS) 566 rmdir(mp->am_path); 567 return err; 568 } 569 570 if (mf->mf_flags & MFF_ON_AUTOFS) 571 /* Nothing else to do */ 572 return 0; 573 574 if (mp->am_link) 575 target = mp->am_link; 576 else 577 target = mf->mf_fo->opt_fs; 578 579 #ifdef MNT2_GEN_OPT_BIND 580 if (bind_works && gopt.flags & CFM_AUTOFS_USE_LOFS) { 581 struct stat buf; 582 583 /* 584 * HACK ALERT! 585 * 586 * Since the bind mount mechanism doesn't allow mountpoint crossing, 587 * we _must_ use symlinks for the host mount case. Otherwise we end up 588 * with a bunch of empty mountpoints... 589 */ 590 if (mf->mf_ops == &amfs_host_ops) 591 goto use_symlink; 592 593 if (target[0] != '/') 594 target2 = str3cat(NULL, mp->am_parent->am_path, "/", target); 595 else 596 target2 = strdup(target); 597 598 /* 599 * We need to stat() the destination, because the bind mount does not 600 * follow symlinks and/or allow for non-existent destinations. 601 * We fall back to symlinks if there are problems. 602 * 603 * We also need to temporarily change pgrp, otherwise our stat() won't 604 * trigger whatever cascading mounts are needed. 605 * 606 * WARNING: we will deadlock if this function is called from the master 607 * amd process and it happens to trigger another auto mount. Therefore, 608 * this function should be called only from a child amd process, or 609 * at the very least it should not be called from the parent unless we 610 * know for sure that it won't cause a recursive mount. We refuse to 611 * cause the recursive mount anyway if called from the parent amd. 612 */ 613 if (!foreground) { 614 pid_t pgrp = getpgrp(); 615 setpgrp(); 616 err = stat(target2, &buf); 617 if ((err = setpgid(0, pgrp))) { 618 plog(XLOG_ERROR, "autofs: cannot restore pgrp: %s", strerror(errno)); 619 plog(XLOG_ERROR, "autofs: aborting the mount"); 620 goto out; 621 } 622 if (err) 623 goto use_symlink; 624 } 625 if ((err = lstat(target2, &buf))) 626 goto use_symlink; 627 if (S_ISLNK(buf.st_mode)) 628 goto use_symlink; 629 630 plog(XLOG_INFO, "autofs: bind-mounting %s -> %s", mp->am_path, target2); 631 mkdir(mp->am_path, 0555); 632 err = mount_lofs(mp->am_path, target2, mf->mf_mopts, 1); 633 if (err) { 634 rmdir(mp->am_path); 635 plog(XLOG_INFO, "autofs: bind-mounting %s -> %s failed", mp->am_path, target2); 636 goto use_symlink; 637 } 638 goto out; 639 } 640 #endif /* MNT2_GEN_OPT_BIND */ 641 use_symlink: 642 plog(XLOG_INFO, "autofs: symlinking %s -> %s", mp->am_path, target); 643 err = symlink(target, mp->am_path); 644 645 out: 646 if (target2) 647 XFREE(target2); 648 649 if (err) 650 return errno; 651 return 0; 652 } 653 654 655 int 656 autofs_umount_fs(am_node *mp, mntfs *mf) 657 { 658 int err = 0; 659 if (!(mf->mf_flags & MFF_ON_AUTOFS)) { 660 err = autofs_bind_umount(mp->am_path); 661 if (err) 662 return err; 663 } 664 665 /* 666 * Multiple sublinks could reference this f/s. 667 * Don't actually unmount it unless we're holding the last reference. 668 */ 669 if (mf->mf_refc == 1) { 670 err = mf->mf_ops->umount_fs(mp, mf); 671 if (err) 672 return err; 673 if (mf->mf_flags & MFF_ON_AUTOFS) 674 rmdir(mp->am_path); 675 } 676 return 0; 677 } 678 679 680 int 681 autofs_umount_succeeded(am_node *mp) 682 { 683 autofs_fh_t *fh = mp->am_parent->am_autofs_fh; 684 struct autofs_pending_umount **pp, *p; 685 686 pp = &fh->pending_umounts; 687 while (*pp && !STREQ((*pp)->name, mp->am_name)) 688 pp = &(*pp)->next; 689 690 /* sanity check */ 691 if (*pp == NULL) 692 return -1; 693 694 p = *pp; 695 plog(XLOG_INFO, "autofs: unmounting %s succeeded", mp->am_path); 696 send_ready(fh->ioctlfd, p->wait_queue_token); 697 698 XFREE(p->name); 699 *pp = p->next; 700 XFREE(p); 701 return 0; 702 } 703 704 705 int 706 autofs_umount_failed(am_node *mp) 707 { 708 autofs_fh_t *fh = mp->am_parent->am_autofs_fh; 709 struct autofs_pending_umount **pp, *p; 710 711 pp = &fh->pending_umounts; 712 while (*pp && !STREQ((*pp)->name, mp->am_name)) 713 pp = &(*pp)->next; 714 715 /* sanity check */ 716 if (*pp == NULL) 717 return -1; 718 719 p = *pp; 720 plog(XLOG_INFO, "autofs: unmounting %s failed", mp->am_path); 721 send_fail(fh->ioctlfd, p->wait_queue_token); 722 723 XFREE(p->name); 724 *pp = p->next; 725 XFREE(p); 726 return 0; 727 } 728 729 730 void 731 autofs_mount_succeeded(am_node *mp) 732 { 733 autofs_fh_t *fh = mp->am_parent->am_autofs_fh; 734 struct autofs_pending_mount **pp, *p; 735 736 /* 737 * don't expire the entries -- the kernel will do it for us. 738 * 739 * but it won't do autofs filesystems, so we expire them the old 740 * fashioned way instead. 741 */ 742 if (!(mp->am_mnt->mf_flags & MFF_IS_AUTOFS)) 743 mp->am_flags |= AMF_NOTIMEOUT; 744 745 pp = &fh->pending_mounts; 746 while (*pp && !STREQ((*pp)->name, mp->am_name)) 747 pp = &(*pp)->next; 748 749 /* sanity check */ 750 if (*pp == NULL) 751 return; 752 753 p = *pp; 754 plog(XLOG_INFO, "autofs: mounting %s succeeded", mp->am_path); 755 send_ready(fh->ioctlfd, p->wait_queue_token); 756 757 XFREE(p->name); 758 *pp = p->next; 759 XFREE(p); 760 } 761 762 763 void 764 autofs_mount_failed(am_node *mp) 765 { 766 autofs_fh_t *fh = mp->am_parent->am_autofs_fh; 767 struct autofs_pending_mount **pp, *p; 768 769 pp = &fh->pending_mounts; 770 while (*pp && !STREQ((*pp)->name, mp->am_name)) 771 pp = &(*pp)->next; 772 773 /* sanity check */ 774 if (*pp == NULL) 775 return; 776 777 p = *pp; 778 plog(XLOG_INFO, "autofs: mounting %s failed", mp->am_path); 779 send_fail(fh->ioctlfd, p->wait_queue_token); 780 781 XFREE(p->name); 782 *pp = p->next; 783 XFREE(p); 784 } 785 786 787 void 788 autofs_get_opts(char *opts, size_t l, autofs_fh_t *fh) 789 { 790 xsnprintf(opts, l, "fd=%d,minproto=%d,maxproto=%d", 791 fh->kernelfd, AUTOFS_MIN_VERSION, AUTOFS_MAX_VERSION); 792 } 793 794 795 int 796 autofs_compute_mount_flags(mntent_t *mnt) 797 { 798 return 0; 799 } 800 801 802 #if AUTOFS_MAX_VERSION >= 4 803 static int autofs_timeout_mp_task(void *arg) 804 { 805 am_node *mp = (am_node *)arg; 806 autofs_fh_t *fh = mp->am_autofs_fh; 807 int now = 0; 808 809 while (ioctl(fh->ioctlfd, AUTOFS_IOC_EXPIRE_MULTI, &now) == 0); 810 return 0; 811 } 812 #endif /* AUTOFS_MAX_VERSION >= 4 */ 813 814 815 void autofs_timeout_mp(am_node *mp) 816 { 817 autofs_fh_t *fh = mp->am_autofs_fh; 818 time_t now = clocktime(NULL); 819 820 /* update the ttl */ 821 mp->am_autofs_ttl = now + gopt.am_timeo_w; 822 823 if (fh->version < 4) { 824 struct autofs_packet_expire pkt; 825 while (ioctl(fh->ioctlfd, AUTOFS_IOC_EXPIRE, &pkt) == 0) 826 autofs_handle_expire(mp, &pkt); 827 return; 828 } 829 830 #if AUTOFS_MAX_VERSION >= 4 831 run_task(autofs_timeout_mp_task, mp, NULL, NULL); 832 #endif /* AUTOFS_MAX_VERSION >= 4 */ 833 } 834 835 #endif /* HAVE_FS_AUTOFS */ 836