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.
11 * This code is derived from software contributed to Berkeley by
12 * Jan-Simon Pendry at Imperial College, London.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
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.
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
43 * File: am-utils/conf/autofs/autofs_linux.c
48 * Automounter filesystem for Linux
53 #endif /* HAVE_CONFIG_H */
63 #define AUTOFS_MIN_VERSION 3
64 #define AUTOFS_MAX_VERSION AUTOFS_MAX_PROTO_VERSION
75 static int autofs_max_fds
;
76 static am_node
**hash
;
78 static int numfds
= 0;
79 static int bind_works
= 1;
88 if (getrlimit(RLIMIT_NOFILE
, &rlim
) < 0) {
89 plog(XLOG_ERROR
, "getrlimit failed, defaulting to 256 fd's");
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
);
96 list
= malloc(autofs_max_fds
* sizeof(*list
));
97 hash
= malloc(autofs_max_fds
* sizeof(*hash
));
99 for (i
= 0 ; i
< autofs_max_fds
; i
++) {
107 hash_insert(int fd
, am_node
*mp
)
110 plog(XLOG_ERROR
, "file descriptor %d already in the hash", fd
);
124 plog(XLOG_WARNING
, "file descriptor %d not in the hash", fd
);
128 for (i
= 0; i
< numfds
; i
++)
130 list
[i
] = list
[numfds
];
137 autofs_get_fh(am_node
*mp
)
142 plog(XLOG_DEBUG
, "autofs_get_fh for %s", mp
->am_path
);
147 if (fds
[0] > autofs_max_fds
) {
153 fh
= ALLOC(autofs_fh_t
);
155 fh
->kernelfd
= fds
[1];
157 fh
->pending_mounts
= NULL
;
158 fh
->pending_umounts
= NULL
;
160 mp
->am_autofs_fh
= fh
;
167 autofs_mounted(am_node
*mp
)
169 autofs_fh_t
*fh
= mp
->am_autofs_fh
;
170 unsigned long timeout
= gopt
.am_timeo
;
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
);
183 plog(XLOG_INFO
, "autofs: using protocol version %d", fh
->version
);
185 /* set expiration timeout */
186 if (ioctl(fh
->ioctlfd
, AUTOFS_IOC_SETTIMEOUT
, &timeout
) < 0)
187 plog(XLOG_ERROR
, "AUTOFS_IOC_SETTIMEOUT: %s", strerror(errno
));
189 /* tell the daemon to call us for expirations */
190 mp
->am_autofs_ttl
= clocktime(NULL
) + gopt
.am_timeo_w
;
195 autofs_get_mp(am_node
*mp
)
197 autofs_fh_t
*fh
= mp
->am_autofs_fh
;
198 dlog("autofs: getting mount point");
200 fh
->ioctlfd
= open(mp
->am_path
, O_RDONLY
);
201 hash_insert(fh
->fd
, mp
);
206 autofs_release_mp(am_node
*mp
)
208 autofs_fh_t
*fh
= mp
->am_autofs_fh
;
209 dlog("autofs: releasing mount point");
210 if (fh
->ioctlfd
>= 0) {
215 * take the kernel fd out of the hash/fdset
216 * so select() doesn't go crazy if the umount succeeds
224 autofs_release_fh(am_node
*mp
)
226 autofs_fh_t
*fh
= mp
->am_autofs_fh
;
227 struct autofs_pending_mount
**pp
, *p
;
228 struct autofs_pending_umount
**upp
, *up
;
230 dlog("autofs: releasing file handle");
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.
237 if (fh
->kernelfd
>= 0)
240 if (fh
->ioctlfd
>= 0)
246 pp
= &fh
->pending_mounts
;
254 upp
= &fh
->pending_umounts
;
263 mp
->am_autofs_fh
= NULL
;
269 autofs_add_fdset(fd_set
*readfds
)
272 for (i
= 0; i
< numfds
; i
++)
273 FD_SET(list
[i
], readfds
);
278 autofs_get_pkt(int fd
, char *buf
, int bytes
)
283 i
= read(fd
, buf
, bytes
);
297 send_fail(int fd
, unsigned long token
)
301 if (ioctl(fd
, AUTOFS_IOC_FAIL
, token
) < 0)
302 plog(XLOG_ERROR
, "AUTOFS_IOC_FAIL: %s", strerror(errno
));
307 send_ready(int fd
, unsigned long token
)
311 if (ioctl(fd
, AUTOFS_IOC_READY
, token
) < 0)
312 plog(XLOG_ERROR
, "AUTOFS_IOC_READY: %s", strerror(errno
));
317 autofs_lookup_failed(am_node
*mp
, char *name
)
319 autofs_fh_t
*fh
= mp
->am_autofs_fh
;
320 struct autofs_pending_mount
**pp
, *p
;
322 pp
= &fh
->pending_mounts
;
323 while (*pp
&& !STREQ((*pp
)->name
, name
))
331 plog(XLOG_INFO
, "autofs: lookup of %s failed", name
);
332 send_fail(fh
->ioctlfd
, p
->wait_queue_token
);
341 autofs_expire_one(am_node
*mp
, char *name
, unsigned long token
)
345 struct autofs_pending_umount
*p
;
348 fh
= mp
->am_autofs_fh
;
350 ap_path
= str3cat(NULL
, mp
->am_path
, "/", name
);
351 if (amuDebug(D_TRACE
))
352 plog(XLOG_DEBUG
, "\tumount(%s)", ap_path
);
354 p
= fh
->pending_umounts
;
355 while (p
&& p
->wait_queue_token
!= token
)
359 /* already pending */
360 dlog("Umounting of %s already pending", ap_path
);
365 ap
= find_ap(ap_path
);
367 /* not found??? not sure what to do here... */
368 send_fail(fh
->ioctlfd
, token
);
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
;
386 autofs_handle_expire(am_node
*mp
, struct autofs_packet_expire
*pkt
)
388 autofs_expire_one(mp
, pkt
->name
, 0);
392 #if AUTOFS_MAX_VERSION >= 4
394 autofs_handle_expire_multi(am_node
*mp
, struct autofs_packet_expire_multi
*pkt
)
396 autofs_expire_one(mp
, pkt
->name
, pkt
->wait_queue_token
);
398 #endif /* AUTOFS_MAX_VERSION >= 4 */
402 autofs_handle_missing(am_node
*mp
, struct autofs_packet_missing
*pkt
)
407 struct autofs_pending_mount
*p
;
411 fh
= mp
->am_autofs_fh
;
413 p
= fh
->pending_mounts
;
414 while (p
&& p
->wait_queue_token
!= pkt
->wait_queue_token
)
418 /* already pending */
419 dlog("Mounting of %s/%s already pending",
420 mp
->am_path
, pkt
->name
);
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
;
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
);
435 ap
= mf
->mf_ops
->mount_child(ap
, &error
);
437 /* some of the rest can be done in amfs_auto_cont */
441 dlog("Mount still pending, not sending autofs reply yet");
444 autofs_lookup_failed(mp
, pkt
->name
);
446 mp
->am_stats
.s_lookup
++;
451 autofs_handle_fdset(fd_set
*readfds
, int nsel
)
454 union autofs_packet_union pkt
;
458 for (i
= 0; nsel
&& i
< numfds
; i
++) {
459 if (!FD_ISSET(list
[i
], readfds
))
463 FD_CLR(list
[i
], readfds
);
465 fh
= mp
->am_autofs_fh
;
467 if (autofs_get_pkt(fh
->fd
, (char *) &pkt
,
468 sizeof(union autofs_packet_union
)))
471 switch (pkt
.hdr
.type
) {
472 case autofs_ptype_missing
:
473 autofs_handle_missing(mp
, &pkt
.missing
);
475 case autofs_ptype_expire
:
476 autofs_handle_expire(mp
, &pkt
.expire
);
478 #if AUTOFS_MAX_VERSION >= 4
479 case autofs_ptype_expire_multi
:
480 autofs_handle_expire_multi(mp
, &pkt
.expire_multi
);
482 #endif /* AUTOFS_MAX_VERSION >= 4 */
484 plog(XLOG_ERROR
, "Unknown autofs packet type %d",
493 create_autofs_service(void)
497 /* not the best place, but... */
498 if (linux_version_code() < KERNEL_VERSION(2,4,0))
506 destroy_autofs_service(void)
514 autofs_bind_umount(char *mountpoint
)
517 #ifdef MNT2_GEN_OPT_BIND
518 if (bind_works
&& gopt
.flags
& CFM_AUTOFS_USE_LOFS
) {
521 if ((err
= lstat(mountpoint
, &buf
)))
523 if (S_ISLNK(buf
.st_mode
))
526 plog(XLOG_INFO
, "autofs: un-bind-mounting %s", mountpoint
);
527 err
= umount_fs(mountpoint
, mnttab_file_name
, 1);
529 plog(XLOG_INFO
, "autofs: unmounting %s failed: %m", mountpoint
);
531 err
= rmdir(mountpoint
);
534 #endif /* MNT2_GEN_OPT_BIND */
536 plog(XLOG_INFO
, "autofs: deleting symlink %s", mountpoint
);
537 err
= unlink(mountpoint
);
547 autofs_mount_fs(am_node
*mp
, mntfs
*mf
)
549 char *target
, *target2
= NULL
;
552 if (mf
->mf_flags
& MFF_ON_AUTOFS
) {
553 if ((err
= mkdir(mp
->am_path
, 0555)))
558 * For sublinks, we could end up here with an already mounted f/s.
559 * Don't do anything in that case.
561 if (!(mf
->mf_flags
& MFF_MOUNTED
))
562 err
= mf
->mf_ops
->mount_fs(mp
, mf
);
565 if (mf
->mf_flags
& MFF_ON_AUTOFS
)
570 if (mf
->mf_flags
& MFF_ON_AUTOFS
)
571 /* Nothing else to do */
575 target
= mp
->am_link
;
577 target
= mf
->mf_fo
->opt_fs
;
579 #ifdef MNT2_GEN_OPT_BIND
580 if (bind_works
&& gopt
.flags
& CFM_AUTOFS_USE_LOFS
) {
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...
590 if (mf
->mf_ops
== &amfs_host_ops
)
593 if (target
[0] != '/')
594 target2
= str3cat(NULL
, mp
->am_parent
->am_path
, "/", target
);
596 target2
= strdup(target
);
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.
603 * We also need to temporarily change pgrp, otherwise our stat() won't
604 * trigger whatever cascading mounts are needed.
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.
614 pid_t pgrp
= getpgrp();
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");
625 if ((err
= lstat(target2
, &buf
)))
627 if (S_ISLNK(buf
.st_mode
))
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);
635 plog(XLOG_INFO
, "autofs: bind-mounting %s -> %s failed", mp
->am_path
, target2
);
640 #endif /* MNT2_GEN_OPT_BIND */
642 plog(XLOG_INFO
, "autofs: symlinking %s -> %s", mp
->am_path
, target
);
643 err
= symlink(target
, mp
->am_path
);
656 autofs_umount_fs(am_node
*mp
, mntfs
*mf
)
659 if (!(mf
->mf_flags
& MFF_ON_AUTOFS
)) {
660 err
= autofs_bind_umount(mp
->am_path
);
666 * Multiple sublinks could reference this f/s.
667 * Don't actually unmount it unless we're holding the last reference.
669 if (mf
->mf_refc
== 1) {
670 err
= mf
->mf_ops
->umount_fs(mp
, mf
);
673 if (mf
->mf_flags
& MFF_ON_AUTOFS
)
681 autofs_umount_succeeded(am_node
*mp
)
683 autofs_fh_t
*fh
= mp
->am_parent
->am_autofs_fh
;
684 struct autofs_pending_umount
**pp
, *p
;
686 pp
= &fh
->pending_umounts
;
687 while (*pp
&& !STREQ((*pp
)->name
, mp
->am_name
))
695 plog(XLOG_INFO
, "autofs: unmounting %s succeeded", mp
->am_path
);
696 send_ready(fh
->ioctlfd
, p
->wait_queue_token
);
706 autofs_umount_failed(am_node
*mp
)
708 autofs_fh_t
*fh
= mp
->am_parent
->am_autofs_fh
;
709 struct autofs_pending_umount
**pp
, *p
;
711 pp
= &fh
->pending_umounts
;
712 while (*pp
&& !STREQ((*pp
)->name
, mp
->am_name
))
720 plog(XLOG_INFO
, "autofs: unmounting %s failed", mp
->am_path
);
721 send_fail(fh
->ioctlfd
, p
->wait_queue_token
);
731 autofs_mount_succeeded(am_node
*mp
)
733 autofs_fh_t
*fh
= mp
->am_parent
->am_autofs_fh
;
734 struct autofs_pending_mount
**pp
, *p
;
737 * don't expire the entries -- the kernel will do it for us.
739 * but it won't do autofs filesystems, so we expire them the old
740 * fashioned way instead.
742 if (!(mp
->am_mnt
->mf_flags
& MFF_IS_AUTOFS
))
743 mp
->am_flags
|= AMF_NOTIMEOUT
;
745 pp
= &fh
->pending_mounts
;
746 while (*pp
&& !STREQ((*pp
)->name
, mp
->am_name
))
754 plog(XLOG_INFO
, "autofs: mounting %s succeeded", mp
->am_path
);
755 send_ready(fh
->ioctlfd
, p
->wait_queue_token
);
764 autofs_mount_failed(am_node
*mp
)
766 autofs_fh_t
*fh
= mp
->am_parent
->am_autofs_fh
;
767 struct autofs_pending_mount
**pp
, *p
;
769 pp
= &fh
->pending_mounts
;
770 while (*pp
&& !STREQ((*pp
)->name
, mp
->am_name
))
778 plog(XLOG_INFO
, "autofs: mounting %s failed", mp
->am_path
);
779 send_fail(fh
->ioctlfd
, p
->wait_queue_token
);
788 autofs_get_opts(char *opts
, size_t l
, autofs_fh_t
*fh
)
790 xsnprintf(opts
, l
, "fd=%d,minproto=%d,maxproto=%d",
791 fh
->kernelfd
, AUTOFS_MIN_VERSION
, AUTOFS_MAX_VERSION
);
796 autofs_compute_mount_flags(mntent_t
*mnt
)
802 #if AUTOFS_MAX_VERSION >= 4
803 static int autofs_timeout_mp_task(void *arg
)
805 am_node
*mp
= (am_node
*)arg
;
806 autofs_fh_t
*fh
= mp
->am_autofs_fh
;
809 while (ioctl(fh
->ioctlfd
, AUTOFS_IOC_EXPIRE_MULTI
, &now
) == 0);
812 #endif /* AUTOFS_MAX_VERSION >= 4 */
815 void autofs_timeout_mp(am_node
*mp
)
817 autofs_fh_t
*fh
= mp
->am_autofs_fh
;
818 time_t now
= clocktime(NULL
);
821 mp
->am_autofs_ttl
= now
+ gopt
.am_timeo_w
;
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
);
830 #if AUTOFS_MAX_VERSION >= 4
831 run_task(autofs_timeout_mp_task
, mp
, NULL
, NULL
);
832 #endif /* AUTOFS_MAX_VERSION >= 4 */
835 #endif /* HAVE_FS_AUTOFS */