autofs.c revision 270898
1151497Sru/*- 2151497Sru * Copyright (c) 2014 The FreeBSD Foundation 3151497Sru * All rights reserved. 4151497Sru * 5151497Sru * This software was developed by Edward Tomasz Napierala under sponsorship 6151497Sru * from the FreeBSD Foundation. 7151497Sru * 8151497Sru * Redistribution and use in source and binary forms, with or without 9151497Sru * modification, are permitted provided that the following conditions 10151497Sru * are met: 11151497Sru * 1. Redistributions of source code must retain the above copyright 12151497Sru * notice, this list of conditions and the following disclaimer. 13151497Sru * 2. Redistributions in binary form must reproduce the above copyright 14151497Sru * notice, this list of conditions and the following disclaimer in the 15151497Sru * documentation and/or other materials provided with the distribution. 16151497Sru * 17151497Sru * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18151497Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19151497Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20151497Sru * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21151497Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22151497Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23151497Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24151497Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25151497Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26151497Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27151497Sru * SUCH DAMAGE. 28151497Sru * 29151497Sru */ 30151497Sru/*- 31151497Sru * Copyright (c) 1989, 1991, 1993, 1995 32151497Sru * The Regents of the University of California. All rights reserved. 33151497Sru * 34151497Sru * This code is derived from software contributed to Berkeley by 35151497Sru * Rick Macklem at The University of Guelph. 36151497Sru * 37151497Sru * Redistribution and use in source and binary forms, with or without 38151497Sru * modification, are permitted provided that the following conditions 39151497Sru * are met: 40151497Sru * 1. Redistributions of source code must retain the above copyright 41151497Sru * notice, this list of conditions and the following disclaimer. 42151497Sru * 2. Redistributions in binary form must reproduce the above copyright 43151497Sru * notice, this list of conditions and the following disclaimer in the 44151497Sru * documentation and/or other materials provided with the distribution. 45151497Sru * 4. Neither the name of the University nor the names of its contributors 46151497Sru * may be used to endorse or promote products derived from this software 47151497Sru * without specific prior written permission. 48151497Sru * 49151497Sru * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50151497Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51151497Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52151497Sru * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53151497Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54151497Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55151497Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56151497Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57151497Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58151497Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59151497Sru * SUCH DAMAGE. 60151497Sru * 61151497Sru */ 62151497Sru 63151497Sru#include <sys/cdefs.h> 64151497Sru __FBSDID("$FreeBSD: stable/10/sys/fs/autofs/autofs.c 270898 2014-08-31 21:49:45Z trasz $"); 65151497Sru 66151497Sru#include <sys/param.h> 67151497Sru#include <sys/systm.h> 68151497Sru#include <sys/buf.h> 69151497Sru#include <sys/conf.h> 70151497Sru#include <sys/dirent.h> 71151497Sru#include <sys/ioccom.h> 72151497Sru#include <sys/kernel.h> 73151497Sru#include <sys/module.h> 74151497Sru#include <sys/mount.h> 75151497Sru#include <sys/refcount.h> 76151497Sru#include <sys/sx.h> 77151497Sru#include <sys/sysctl.h> 78151497Sru#include <sys/syscallsubr.h> 79151497Sru#include <sys/vnode.h> 80151497Sru#include <machine/atomic.h> 81151497Sru#include <vm/uma.h> 82151497Sru 83151497Sru#include <fs/autofs/autofs.h> 84151497Sru#include <fs/autofs/autofs_ioctl.h> 85151497Sru 86151497SruMALLOC_DEFINE(M_AUTOFS, "autofs", "Automounter filesystem"); 87151497Sru 88151497Sruuma_zone_t autofs_request_zone; 89151497Sruuma_zone_t autofs_node_zone; 90151497Sru 91151497Srustatic int autofs_open(struct cdev *dev, int flags, int fmt, 92151497Sru struct thread *td); 93151497Srustatic int autofs_close(struct cdev *dev, int flag, int fmt, 94151497Sru struct thread *td); 95151497Srustatic int autofs_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, 96151497Sru int mode, struct thread *td); 97151497Sru 98151497Srustatic struct cdevsw autofs_cdevsw = { 99151497Sru .d_version = D_VERSION, 100151497Sru .d_open = autofs_open, 101151497Sru .d_close = autofs_close, 102151497Sru .d_ioctl = autofs_ioctl, 103151497Sru .d_name = "autofs", 104151497Sru}; 105151497Sru 106151497Sru/* 107151497Sru * List of signals that can interrupt an autofs trigger. Might be a good 108151497Sru * idea to keep it synchronised with list in sys/fs/nfs/nfs_commonkrpc.c. 109151497Sru */ 110151497Sruint autofs_sig_set[] = { 111151497Sru SIGINT, 112151497Sru SIGTERM, 113151497Sru SIGHUP, 114151497Sru SIGKILL, 115151497Sru SIGQUIT 116151497Sru}; 117151497Sru 118151497Srustruct autofs_softc *sc; 119151497Sru 120151497SruSYSCTL_NODE(_vfs, OID_AUTO, autofs, CTLFLAG_RD, 0, "Automounter filesystem"); 121151497Sruint autofs_debug = 1; 122151497SruTUNABLE_INT("vfs.autofs.debug", &autofs_debug); 123151497SruSYSCTL_INT(_vfs_autofs, OID_AUTO, debug, CTLFLAG_RWTUN, 124151497Sru &autofs_debug, 1, "Enable debug messages"); 125151497Sruint autofs_mount_on_stat = 0; 126151497SruTUNABLE_INT("vfs.autofs.mount_on_stat", &autofs_mount_on_stat); 127151497SruSYSCTL_INT(_vfs_autofs, OID_AUTO, mount_on_stat, CTLFLAG_RWTUN, 128151497Sru &autofs_mount_on_stat, 0, "Trigger mount on stat(2) on mountpoint"); 129151497Sruint autofs_timeout = 30; 130151497SruTUNABLE_INT("vfs.autofs.timeout", &autofs_timeout); 131151497SruSYSCTL_INT(_vfs_autofs, OID_AUTO, timeout, CTLFLAG_RWTUN, 132151497Sru &autofs_timeout, 30, "Number of seconds to wait for automountd(8)"); 133151497Sruint autofs_cache = 600; 134151497SruTUNABLE_INT("vfs.autofs.cache", &autofs_cache); 135151497SruSYSCTL_INT(_vfs_autofs, OID_AUTO, cache, CTLFLAG_RWTUN, 136151497Sru &autofs_cache, 600, "Number of seconds to wait before reinvoking " 137151497Sru "automountd(8) for any given file or directory"); 138151497Sruint autofs_retry_attempts = 3; 139151497SruTUNABLE_INT("vfs.autofs.retry_attempts", &autofs_retry_attempts); 140151497SruSYSCTL_INT(_vfs_autofs, OID_AUTO, retry_attempts, CTLFLAG_RWTUN, 141151497Sru &autofs_retry_attempts, 3, "Number of attempts before failing mount"); 142151497Sruint autofs_retry_delay = 1; 143151497SruTUNABLE_INT("vfs.autofs.retry_delay", &autofs_retry_delay); 144151497SruSYSCTL_INT(_vfs_autofs, OID_AUTO, retry_delay, CTLFLAG_RWTUN, 145151497Sru &autofs_retry_delay, 1, "Number of seconds before retrying"); 146151497Sruint autofs_interruptible = 1; 147151497SruTUNABLE_INT("vfs.autofs.interruptible", &autofs_interruptible); 148151497SruSYSCTL_INT(_vfs_autofs, OID_AUTO, interruptible, CTLFLAG_RWTUN, 149151497Sru &autofs_interruptible, 1, "Allow requests to be interrupted by signal"); 150151497Sru 151151497Sruint 152151497Sruautofs_init(struct vfsconf *vfsp) 153151497Sru{ 154151497Sru int error; 155151497Sru 156151497Sru sc = malloc(sizeof(*sc), M_AUTOFS, M_WAITOK | M_ZERO); 157151497Sru 158151497Sru autofs_request_zone = uma_zcreate("autofs_request", 159151497Sru sizeof(struct autofs_request), NULL, NULL, NULL, NULL, 160151497Sru UMA_ALIGN_PTR, 0); 161151497Sru autofs_node_zone = uma_zcreate("autofs_node", 162151497Sru sizeof(struct autofs_node), NULL, NULL, NULL, NULL, 163151497Sru UMA_ALIGN_PTR, 0); 164151497Sru 165151497Sru TAILQ_INIT(&sc->sc_requests); 166151497Sru cv_init(&sc->sc_cv, "autofscv"); 167151497Sru sx_init(&sc->sc_lock, "autofslk"); 168151497Sru 169151497Sru error = make_dev_p(MAKEDEV_CHECKNAME, &sc->sc_cdev, &autofs_cdevsw, 170151497Sru NULL, UID_ROOT, GID_WHEEL, 0600, "autofs"); 171151497Sru if (error != 0) { 172151497Sru AUTOFS_WARN("failed to create device node, error %d", error); 173151497Sru free(sc, M_AUTOFS); 174151497Sru return (error); 175151497Sru } 176151497Sru sc->sc_cdev->si_drv1 = sc; 177151497Sru 178151497Sru return (0); 179151497Sru} 180151497Sru 181151497Sruint 182151497Sruautofs_uninit(struct vfsconf *vfsp) 183151497Sru{ 184151497Sru 185151497Sru sx_xlock(&sc->sc_lock); 186151497Sru if (sc->sc_dev_opened) { 187151497Sru sx_xunlock(&sc->sc_lock); 188151497Sru return (EBUSY); 189151497Sru } 190151497Sru if (sc->sc_cdev != NULL) 191151497Sru destroy_dev(sc->sc_cdev); 192151497Sru 193151497Sru uma_zdestroy(autofs_request_zone); 194151497Sru uma_zdestroy(autofs_node_zone); 195151497Sru 196151497Sru sx_xunlock(&sc->sc_lock); 197151497Sru /* 198151497Sru * XXX: Race with open? 199151497Sru */ 200151497Sru free(sc, M_AUTOFS); 201151497Sru 202151497Sru return (0); 203151497Sru} 204151497Sru 205151497Srubool 206151497Sruautofs_ignore_thread(const struct thread *td) 207151497Sru{ 208151497Sru struct proc *p; 209151497Sru 210151497Sru p = td->td_proc; 211151497Sru 212151497Sru if (sc->sc_dev_opened == false) 213151497Sru return (false); 214151497Sru 215151497Sru PROC_LOCK(p); 216151497Sru if (p->p_session->s_sid == sc->sc_dev_sid) { 217151497Sru PROC_UNLOCK(p); 218151497Sru return (true); 219151497Sru } 220151497Sru PROC_UNLOCK(p); 221151497Sru 222151497Sru return (false); 223151497Sru} 224151497Sru 225151497Srustatic char * 226151497Sruautofs_path(struct autofs_node *anp) 227151497Sru{ 228151497Sru struct autofs_mount *amp; 229151497Sru char *path, *tmp; 230151497Sru 231151497Sru amp = anp->an_mount; 232151497Sru 233151497Sru path = strdup("", M_AUTOFS); 234151497Sru for (; anp->an_parent != NULL; anp = anp->an_parent) { 235151497Sru tmp = malloc(strlen(anp->an_name) + strlen(path) + 2, 236151497Sru M_AUTOFS, M_WAITOK); 237151497Sru strcpy(tmp, anp->an_name); 238151497Sru strcat(tmp, "/"); 239151497Sru strcat(tmp, path); 240151497Sru free(path, M_AUTOFS); 241151497Sru path = tmp; 242151497Sru } 243151497Sru 244151497Sru tmp = malloc(strlen(amp->am_mountpoint) + strlen(path) + 2, 245151497Sru M_AUTOFS, M_WAITOK); 246151497Sru strcpy(tmp, amp->am_mountpoint); 247151497Sru strcat(tmp, "/"); 248151497Sru strcat(tmp, path); 249151497Sru free(path, M_AUTOFS); 250151497Sru path = tmp; 251151497Sru 252151497Sru return (path); 253151497Sru} 254151497Sru 255151497Srustatic void 256151497Sruautofs_callout(void *context) 257151497Sru{ 258151497Sru struct autofs_request *ar; 259151497Sru struct autofs_softc *sc; 260151497Sru 261151497Sru ar = context; 262151497Sru sc = ar->ar_mount->am_softc; 263151497Sru 264151497Sru sx_xlock(&sc->sc_lock); 265151497Sru AUTOFS_WARN("request %d for %s timed out after %d seconds", 266151497Sru ar->ar_id, ar->ar_path, autofs_timeout); 267151497Sru /* 268151497Sru * XXX: EIO perhaps? 269151497Sru */ 270151497Sru ar->ar_error = ETIMEDOUT; 271151497Sru ar->ar_done = true; 272151497Sru ar->ar_in_progress = false; 273151497Sru cv_broadcast(&sc->sc_cv); 274151497Sru sx_xunlock(&sc->sc_lock); 275151497Sru} 276151497Sru 277151497Srubool 278autofs_cached(struct autofs_node *anp, const char *component, int componentlen) 279{ 280 int error; 281 struct autofs_mount *amp; 282 283 amp = anp->an_mount; 284 285 AUTOFS_ASSERT_UNLOCKED(amp); 286 287 /* 288 * For top-level nodes we need to request automountd(8) 289 * assistance even if the node is marked as cached, 290 * but the requested subdirectory does not exist. This 291 * is necessary for wildcard indirect map keys to work. 292 */ 293 if (anp->an_parent == NULL && componentlen != 0) { 294 AUTOFS_LOCK(amp); 295 error = autofs_node_find(anp, component, componentlen, NULL); 296 AUTOFS_UNLOCK(amp); 297 if (error != 0) 298 return (false); 299 } 300 301 return (anp->an_cached); 302} 303 304static void 305autofs_cache_callout(void *context) 306{ 307 struct autofs_node *anp; 308 309 anp = context; 310 anp->an_cached = false; 311} 312 313/* 314 * The set/restore sigmask functions are used to (temporarily) overwrite 315 * the thread td_sigmask during triggering. 316 */ 317static void 318autofs_set_sigmask(sigset_t *oldset) 319{ 320 sigset_t newset; 321 int i; 322 323 SIGFILLSET(newset); 324 /* Remove the autofs set of signals from newset */ 325 PROC_LOCK(curproc); 326 mtx_lock(&curproc->p_sigacts->ps_mtx); 327 for (i = 0 ; i < sizeof(autofs_sig_set)/sizeof(int) ; i++) { 328 /* 329 * But make sure we leave the ones already masked 330 * by the process, i.e. remove the signal from the 331 * temporary signalmask only if it wasn't already 332 * in p_sigmask. 333 */ 334 if (!SIGISMEMBER(curthread->td_sigmask, autofs_sig_set[i]) && 335 !SIGISMEMBER(curproc->p_sigacts->ps_sigignore, 336 autofs_sig_set[i])) { 337 SIGDELSET(newset, autofs_sig_set[i]); 338 } 339 } 340 mtx_unlock(&curproc->p_sigacts->ps_mtx); 341 kern_sigprocmask(curthread, SIG_SETMASK, &newset, oldset, 342 SIGPROCMASK_PROC_LOCKED); 343 PROC_UNLOCK(curproc); 344} 345 346static void 347autofs_restore_sigmask(sigset_t *set) 348{ 349 350 kern_sigprocmask(curthread, SIG_SETMASK, set, NULL, 0); 351} 352 353static int 354autofs_trigger_one(struct autofs_node *anp, 355 const char *component, int componentlen) 356{ 357 sigset_t oldset; 358 struct autofs_mount *amp; 359 struct autofs_softc *sc; 360 struct autofs_node *firstanp; 361 struct autofs_request *ar; 362 char *key, *path; 363 int error = 0, request_error, last; 364 365 amp = VFSTOAUTOFS(anp->an_vnode->v_mount); 366 sc = amp->am_softc; 367 368 sx_assert(&sc->sc_lock, SA_XLOCKED); 369 370 if (anp->an_parent == NULL) { 371 key = strndup(component, componentlen, M_AUTOFS); 372 } else { 373 for (firstanp = anp; firstanp->an_parent->an_parent != NULL; 374 firstanp = firstanp->an_parent) 375 continue; 376 key = strdup(firstanp->an_name, M_AUTOFS); 377 } 378 379 path = autofs_path(anp); 380 381 TAILQ_FOREACH(ar, &sc->sc_requests, ar_next) { 382 if (strcmp(ar->ar_path, path) != 0) 383 continue; 384 if (strcmp(ar->ar_key, key) != 0) 385 continue; 386 387 KASSERT(strcmp(ar->ar_from, amp->am_from) == 0, 388 ("from changed; %s != %s", ar->ar_from, amp->am_from)); 389 KASSERT(strcmp(ar->ar_prefix, amp->am_prefix) == 0, 390 ("prefix changed; %s != %s", 391 ar->ar_prefix, amp->am_prefix)); 392 KASSERT(strcmp(ar->ar_options, amp->am_options) == 0, 393 ("options changed; %s != %s", 394 ar->ar_options, amp->am_options)); 395 396 break; 397 } 398 399 if (ar != NULL) { 400 refcount_acquire(&ar->ar_refcount); 401 } else { 402 ar = uma_zalloc(autofs_request_zone, M_WAITOK | M_ZERO); 403 ar->ar_mount = amp; 404 405 ar->ar_id = atomic_fetchadd_int(&sc->sc_last_request_id, 1); 406 strlcpy(ar->ar_from, amp->am_from, sizeof(ar->ar_from)); 407 strlcpy(ar->ar_path, path, sizeof(ar->ar_path)); 408 strlcpy(ar->ar_prefix, amp->am_prefix, sizeof(ar->ar_prefix)); 409 strlcpy(ar->ar_key, key, sizeof(ar->ar_key)); 410 strlcpy(ar->ar_options, 411 amp->am_options, sizeof(ar->ar_options)); 412 413 callout_init(&ar->ar_callout, 1); 414 callout_reset(&ar->ar_callout, 415 autofs_timeout * hz, autofs_callout, ar); 416 refcount_init(&ar->ar_refcount, 1); 417 TAILQ_INSERT_TAIL(&sc->sc_requests, ar, ar_next); 418 } 419 420 cv_broadcast(&sc->sc_cv); 421 while (ar->ar_done == false) { 422 if (autofs_interruptible != 0) { 423 autofs_set_sigmask(&oldset); 424 error = cv_wait_sig(&sc->sc_cv, &sc->sc_lock); 425 autofs_restore_sigmask(&oldset); 426 if (error != 0) { 427 /* 428 * XXX: For some reson this returns -1 429 * instead of EINTR, wtf?! 430 */ 431 error = EINTR; 432 AUTOFS_WARN("cv_wait_sig for %s failed " 433 "with error %d", ar->ar_path, error); 434 break; 435 } 436 } else { 437 cv_wait(&sc->sc_cv, &sc->sc_lock); 438 } 439 } 440 441 request_error = ar->ar_error; 442 if (request_error != 0) { 443 AUTOFS_WARN("request for %s completed with error %d", 444 ar->ar_path, request_error); 445 } 446 447 last = refcount_release(&ar->ar_refcount); 448 if (last) { 449 TAILQ_REMOVE(&sc->sc_requests, ar, ar_next); 450 /* 451 * XXX: Is it safe? 452 */ 453 sx_xunlock(&sc->sc_lock); 454 callout_drain(&ar->ar_callout); 455 sx_xlock(&sc->sc_lock); 456 uma_zfree(autofs_request_zone, ar); 457 } 458 459 /* 460 * Note that we do not do negative caching on purpose. This 461 * way the user can retry access at any time, e.g. after fixing 462 * the failure reason, without waiting for cache timer to expire. 463 */ 464 if (error == 0 && request_error == 0 && autofs_cache > 0) { 465 anp->an_cached = true; 466 callout_reset(&anp->an_callout, autofs_cache * hz, 467 autofs_cache_callout, anp); 468 } 469 470 free(key, M_AUTOFS); 471 free(path, M_AUTOFS); 472 473 if (error != 0) 474 return (error); 475 return (request_error); 476} 477 478/* 479 * Send request to automountd(8) and wait for completion. 480 */ 481int 482autofs_trigger(struct autofs_node *anp, 483 const char *component, int componentlen) 484{ 485 int error; 486 487 for (;;) { 488 error = autofs_trigger_one(anp, component, componentlen); 489 if (error == 0) { 490 anp->an_retries = 0; 491 return (0); 492 } 493 if (error == EINTR) { 494 AUTOFS_DEBUG("trigger interrupted by signal, " 495 "not retrying"); 496 anp->an_retries = 0; 497 return (error); 498 } 499 anp->an_retries++; 500 if (anp->an_retries >= autofs_retry_attempts) { 501 AUTOFS_DEBUG("trigger failed %d times; returning " 502 "error %d", anp->an_retries, error); 503 anp->an_retries = 0; 504 return (error); 505 506 } 507 AUTOFS_DEBUG("trigger failed with error %d; will retry in " 508 "%d seconds, %d attempts left", error, autofs_retry_delay, 509 autofs_retry_attempts - anp->an_retries); 510 sx_xunlock(&sc->sc_lock); 511 pause("autofs_retry", autofs_retry_delay * hz); 512 sx_xlock(&sc->sc_lock); 513 } 514} 515 516static int 517autofs_ioctl_request(struct autofs_softc *sc, struct autofs_daemon_request *adr) 518{ 519 struct autofs_request *ar; 520 int error; 521 522 sx_xlock(&sc->sc_lock); 523 for (;;) { 524 TAILQ_FOREACH(ar, &sc->sc_requests, ar_next) { 525 if (ar->ar_done) 526 continue; 527 if (ar->ar_in_progress) 528 continue; 529 530 break; 531 } 532 533 if (ar != NULL) 534 break; 535 536 error = cv_wait_sig(&sc->sc_cv, &sc->sc_lock); 537 if (error != 0) { 538 /* 539 * XXX: For some reson this returns -1 instead 540 * of EINTR, wtf?! 541 */ 542 error = EINTR; 543 sx_xunlock(&sc->sc_lock); 544 AUTOFS_DEBUG("failed with error %d", error); 545 return (error); 546 } 547 } 548 549 ar->ar_in_progress = true; 550 sx_xunlock(&sc->sc_lock); 551 552 adr->adr_id = ar->ar_id; 553 strlcpy(adr->adr_from, ar->ar_from, sizeof(adr->adr_from)); 554 strlcpy(adr->adr_path, ar->ar_path, sizeof(adr->adr_path)); 555 strlcpy(adr->adr_prefix, ar->ar_prefix, sizeof(adr->adr_prefix)); 556 strlcpy(adr->adr_key, ar->ar_key, sizeof(adr->adr_key)); 557 strlcpy(adr->adr_options, ar->ar_options, sizeof(adr->adr_options)); 558 559 PROC_LOCK(curproc); 560 sc->sc_dev_sid = curproc->p_session->s_sid; 561 PROC_UNLOCK(curproc); 562 563 return (0); 564} 565 566static int 567autofs_ioctl_done(struct autofs_softc *sc, struct autofs_daemon_done *add) 568{ 569 struct autofs_request *ar; 570 571 sx_xlock(&sc->sc_lock); 572 TAILQ_FOREACH(ar, &sc->sc_requests, ar_next) { 573 if (ar->ar_id == add->add_id) 574 break; 575 } 576 577 if (ar == NULL) { 578 sx_xunlock(&sc->sc_lock); 579 AUTOFS_DEBUG("id %d not found", add->add_id); 580 return (ESRCH); 581 } 582 583 ar->ar_error = add->add_error; 584 ar->ar_done = true; 585 ar->ar_in_progress = false; 586 cv_broadcast(&sc->sc_cv); 587 588 sx_xunlock(&sc->sc_lock); 589 590 return (0); 591} 592 593static int 594autofs_open(struct cdev *dev, int flags, int fmt, struct thread *td) 595{ 596 597 sx_xlock(&sc->sc_lock); 598 if (sc->sc_dev_opened) { 599 sx_xunlock(&sc->sc_lock); 600 return (EBUSY); 601 } 602 603 sc->sc_dev_opened = true; 604 sx_xunlock(&sc->sc_lock); 605 606 return (0); 607} 608 609static int 610autofs_close(struct cdev *dev, int flag, int fmt, struct thread *td) 611{ 612 613 sx_xlock(&sc->sc_lock); 614 KASSERT(sc->sc_dev_opened, ("not opened?")); 615 sc->sc_dev_opened = false; 616 sx_xunlock(&sc->sc_lock); 617 618 return (0); 619} 620 621static int 622autofs_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode, 623 struct thread *td) 624{ 625 626 KASSERT(sc->sc_dev_opened, ("not opened?")); 627 628 switch (cmd) { 629 case AUTOFSREQUEST: 630 return (autofs_ioctl_request(sc, 631 (struct autofs_daemon_request *)arg)); 632 case AUTOFSDONE: 633 return (autofs_ioctl_done(sc, 634 (struct autofs_daemon_done *)arg)); 635 default: 636 AUTOFS_DEBUG("invalid cmd %lx", cmd); 637 return (EINVAL); 638 } 639} 640