Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / bsd / am-utils / dist / conf / autofs / autofs_linux.c
blob83e6b19daaa2168ebf87ad7dda6764dd20f0ae11
1 /* $NetBSD$ */
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.
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
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.
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.
43 * File: am-utils/conf/autofs/autofs_linux.c
48 * Automounter filesystem for Linux
51 #ifdef HAVE_CONFIG_H
52 # include <config.h>
53 #endif /* HAVE_CONFIG_H */
54 #include <am_defs.h>
55 #include <amd.h>
57 #ifdef HAVE_FS_AUTOFS
60 * MACROS:
63 #define AUTOFS_MIN_VERSION 3
64 #define AUTOFS_MAX_VERSION AUTOFS_MAX_PROTO_VERSION
68 * STRUCTURES:
72 * VARIABLES:
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;
82 static void
83 hash_init(void)
85 int i;
86 struct rlimit rlim;
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);
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++) {
100 hash[i] = NULL;
101 list[i] = -1;
106 static void
107 hash_insert(int fd, am_node *mp)
109 if (hash[fd] != 0)
110 plog(XLOG_ERROR, "file descriptor %d already in the hash", fd);
112 hash[fd] = mp;
113 list[numfds] = fd;
114 numfds++;
118 static void
119 hash_delete(int fd)
121 int i;
123 if (hash[fd] == 0)
124 plog(XLOG_WARNING, "file descriptor %d not in the hash", fd);
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;
137 autofs_get_fh(am_node *mp)
139 int fds[2];
140 autofs_fh_t *fh;
142 plog(XLOG_DEBUG, "autofs_get_fh for %s", mp->am_path);
143 if (pipe(fds) < 0)
144 return errno;
146 /* sanity check */
147 if (fds[0] > autofs_max_fds) {
148 close(fds[0]);
149 close(fds[1]);
150 return EMFILE;
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;
160 mp->am_autofs_fh = fh;
162 return 0;
166 void
167 autofs_mounted(am_node *mp)
169 autofs_fh_t *fh = mp->am_autofs_fh;
170 unsigned long timeout = gopt.am_timeo;
172 close(fh->kernelfd);
173 fh->kernelfd = -1;
175 autofs_get_mp(mp);
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);
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;
194 void
195 autofs_get_mp(am_node *mp)
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);
205 void
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) {
211 close(fh->ioctlfd);
212 fh->ioctlfd = -1;
215 * take the kernel fd out of the hash/fdset
216 * so select() doesn't go crazy if the umount succeeds
218 if (fh->fd >= 0)
219 hash_delete(fh->fd);
223 void
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");
231 if (fh) {
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)
238 close(fh->kernelfd);
240 if (fh->ioctlfd >= 0)
241 close(fh->ioctlfd);
243 if (fh->fd >= 0)
244 close(fh->fd);
246 pp = &fh->pending_mounts;
247 while (*pp) {
248 p = *pp;
249 XFREE(p->name);
250 *pp = p->next;
251 XFREE(p);
254 upp = &fh->pending_umounts;
255 while (*upp) {
256 up = *upp;
257 XFREE(up->name);
258 *upp = up->next;
259 XFREE(up);
262 XFREE(fh);
263 mp->am_autofs_fh = NULL;
268 void
269 autofs_add_fdset(fd_set *readfds)
271 int i;
272 for (i = 0; i < numfds; i++)
273 FD_SET(list[i], readfds);
277 static int
278 autofs_get_pkt(int fd, char *buf, int bytes)
280 int i;
282 do {
283 i = read(fd, buf, bytes);
285 if (i <= 0)
286 break;
288 buf += i;
289 bytes -= i;
290 } while (bytes);
292 return bytes;
296 static void
297 send_fail(int fd, unsigned long token)
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));
306 static void
307 send_ready(int fd, unsigned long token)
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));
316 static void
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))
324 pp = &(*pp)->next;
326 /* sanity check */
327 if (*pp == NULL)
328 return;
330 p = *pp;
331 plog(XLOG_INFO, "autofs: lookup of %s failed", name);
332 send_fail(fh->ioctlfd, p->wait_queue_token);
334 XFREE(p->name);
335 *pp = p->next;
336 XFREE(p);
340 static void
341 autofs_expire_one(am_node *mp, char *name, unsigned long token)
343 autofs_fh_t *fh;
344 am_node *ap;
345 struct autofs_pending_umount *p;
346 char *ap_path;
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)
356 p = p->next;
358 if (p) {
359 /* already pending */
360 dlog("Umounting of %s already pending", ap_path);
361 amd_stats.d_drops++;
362 goto out;
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;
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;
378 unmount_mp(ap);
380 out:
381 XFREE(ap_path);
385 static void
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
393 static void
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 */
401 static void
402 autofs_handle_missing(am_node *mp, struct autofs_packet_missing *pkt)
404 autofs_fh_t *fh;
405 mntfs *mf;
406 am_node *ap;
407 struct autofs_pending_mount *p;
408 int error;
410 mf = mp->am_mnt;
411 fh = mp->am_autofs_fh;
413 p = fh->pending_mounts;
414 while (p && p->wait_queue_token != pkt->wait_queue_token)
415 p = p->next;
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;
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);
434 if (ap && error < 0)
435 ap = mf->mf_ops->mount_child(ap, &error);
437 /* some of the rest can be done in amfs_auto_cont */
439 if (ap == 0) {
440 if (error < 0) {
441 dlog("Mount still pending, not sending autofs reply yet");
442 return;
444 autofs_lookup_failed(mp, pkt->name);
446 mp->am_stats.s_lookup++;
451 autofs_handle_fdset(fd_set *readfds, int nsel)
453 int i;
454 union autofs_packet_union pkt;
455 autofs_fh_t *fh;
456 am_node *mp;
458 for (i = 0; nsel && i < numfds; i++) {
459 if (!FD_ISSET(list[i], readfds))
460 continue;
462 nsel--;
463 FD_CLR(list[i], readfds);
464 mp = hash[list[i]];
465 fh = mp->am_autofs_fh;
467 if (autofs_get_pkt(fh->fd, (char *) &pkt,
468 sizeof(union autofs_packet_union)))
469 continue;
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);
488 return nsel;
493 create_autofs_service(void)
495 hash_init();
497 /* not the best place, but... */
498 if (linux_version_code() < KERNEL_VERSION(2,4,0))
499 bind_works = 0;
501 return 0;
506 destroy_autofs_service(void)
508 /* Nothing to do */
509 return 0;
513 static int
514 autofs_bind_umount(char *mountpoint)
516 int err = 1;
517 #ifdef MNT2_GEN_OPT_BIND
518 if (bind_works && gopt.flags & CFM_AUTOFS_USE_LOFS) {
519 struct stat buf;
521 if ((err = lstat(mountpoint, &buf)))
522 return errno;
523 if (S_ISLNK(buf.st_mode))
524 goto use_symlink;
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;
534 #endif /* MNT2_GEN_OPT_BIND */
535 use_symlink:
536 plog(XLOG_INFO, "autofs: deleting symlink %s", mountpoint);
537 err = unlink(mountpoint);
539 out:
540 if (err)
541 return errno;
542 return 0;
547 autofs_mount_fs(am_node *mp, mntfs *mf)
549 char *target, *target2 = NULL;
550 int err = 0;
552 if (mf->mf_flags & MFF_ON_AUTOFS) {
553 if ((err = mkdir(mp->am_path, 0555)))
554 return errno;
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);
564 if (err) {
565 if (mf->mf_flags & MFF_ON_AUTOFS)
566 rmdir(mp->am_path);
567 return err;
570 if (mf->mf_flags & MFF_ON_AUTOFS)
571 /* Nothing else to do */
572 return 0;
574 if (mp->am_link)
575 target = mp->am_link;
576 else
577 target = mf->mf_fo->opt_fs;
579 #ifdef MNT2_GEN_OPT_BIND
580 if (bind_works && gopt.flags & CFM_AUTOFS_USE_LOFS) {
581 struct stat buf;
584 * HACK ALERT!
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)
591 goto use_symlink;
593 if (target[0] != '/')
594 target2 = str3cat(NULL, mp->am_parent->am_path, "/", target);
595 else
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.
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;
622 if (err)
623 goto use_symlink;
625 if ((err = lstat(target2, &buf)))
626 goto use_symlink;
627 if (S_ISLNK(buf.st_mode))
628 goto use_symlink;
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;
638 goto out;
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);
645 out:
646 if (target2)
647 XFREE(target2);
649 if (err)
650 return errno;
651 return 0;
656 autofs_umount_fs(am_node *mp, mntfs *mf)
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;
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);
671 if (err)
672 return err;
673 if (mf->mf_flags & MFF_ON_AUTOFS)
674 rmdir(mp->am_path);
676 return 0;
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))
688 pp = &(*pp)->next;
690 /* sanity check */
691 if (*pp == NULL)
692 return -1;
694 p = *pp;
695 plog(XLOG_INFO, "autofs: unmounting %s succeeded", mp->am_path);
696 send_ready(fh->ioctlfd, p->wait_queue_token);
698 XFREE(p->name);
699 *pp = p->next;
700 XFREE(p);
701 return 0;
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))
713 pp = &(*pp)->next;
715 /* sanity check */
716 if (*pp == NULL)
717 return -1;
719 p = *pp;
720 plog(XLOG_INFO, "autofs: unmounting %s failed", mp->am_path);
721 send_fail(fh->ioctlfd, p->wait_queue_token);
723 XFREE(p->name);
724 *pp = p->next;
725 XFREE(p);
726 return 0;
730 void
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))
747 pp = &(*pp)->next;
749 /* sanity check */
750 if (*pp == NULL)
751 return;
753 p = *pp;
754 plog(XLOG_INFO, "autofs: mounting %s succeeded", mp->am_path);
755 send_ready(fh->ioctlfd, p->wait_queue_token);
757 XFREE(p->name);
758 *pp = p->next;
759 XFREE(p);
763 void
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))
771 pp = &(*pp)->next;
773 /* sanity check */
774 if (*pp == NULL)
775 return;
777 p = *pp;
778 plog(XLOG_INFO, "autofs: mounting %s failed", mp->am_path);
779 send_fail(fh->ioctlfd, p->wait_queue_token);
781 XFREE(p->name);
782 *pp = p->next;
783 XFREE(p);
787 void
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)
798 return 0;
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;
807 int now = 0;
809 while (ioctl(fh->ioctlfd, AUTOFS_IOC_EXPIRE_MULTI, &now) == 0);
810 return 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);
820 /* update the ttl */
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);
827 return;
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 */