4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
27 #include <stdio_ext.h>
31 #include <sys/types.h>
34 #include <netconfig.h>
36 #include <sys/resource.h>
37 #include <sys/systeminfo.h>
40 #include <sys/sockio.h>
49 #include "automount.h"
51 #include <sys/mnttab.h>
52 #include <arpa/inet.h>
53 #include <rpcsvc/daemon_utils.h>
57 #include <sys/utsname.h>
58 #include <sys/thread.h>
59 #include <nfs/rnode.h>
66 static void autofs_doorfunc(void *, char *, size_t, door_desc_t
*, uint_t
);
67 static void autofs_setdoor(int);
68 static void autofs_mntinfo_1_r(autofs_lookupargs
*, autofs_mountres
*);
69 static void autofs_mount_1_free_r(struct autofs_mountres
*);
70 static void autofs_lookup_1_r(autofs_lookupargs
*, autofs_lookupres
*);
71 static void autofs_lookup_1_free_args(autofs_lookupargs
*);
72 static void autofs_unmount_1_r(umntrequest
*, umntres
*);
73 static void autofs_unmount_1_free_args(umntrequest
*);
74 static void autofs_readdir_1_r(autofs_rddirargs
*, autofs_rddirres
*);
75 static void autofs_readdir_1_free_r(struct autofs_rddirres
*);
76 static int decode_args(xdrproc_t
, autofs_door_args_t
*, caddr_t
*, int);
77 static bool_t
encode_res(xdrproc_t
, autofs_door_res_t
**, caddr_t
, int *);
79 static void warn_hup(int);
80 static void free_action_list();
81 static int start_autofs_svcs();
82 static void automountd_wait_for_cleanup(pid_t
);
85 * Private autofs system call
87 extern int _autofssys(int, void *);
89 #define CTIME_BUF_LEN 26
91 #define RESOURCE_FACTOR 8
93 #define AUTOFS_DOOR "/var/run/autofs_door"
96 static thread_key_t s_thr_key
;
98 struct autodir
*dir_head
;
99 struct autodir
*dir_tail
;
105 int automountd_nobrowse
= 0;
119 if (geteuid() != 0) {
120 (void) fprintf(stderr
, "%s must be run as root\n", argv
[0]);
125 * Read in the values from SMF first before we check
126 * commandline options so the options override the file.
129 ret
= autofs_smf_get_prop("automountd_verbose", defval
,
130 DEFAULT_INSTANCE
, SCF_TYPE_BOOLEAN
, AUTOMOUNTD
, &bufsz
);
132 if (strncasecmp("true", defval
, 4) == 0)
138 ret
= autofs_smf_get_prop("nobrowse", defval
, DEFAULT_INSTANCE
,
139 SCF_TYPE_BOOLEAN
, AUTOMOUNTD
, &bufsz
);
141 if (strncasecmp("true", defval
, 4) == 0)
142 automountd_nobrowse
= TRUE
;
144 automountd_nobrowse
= FALSE
;
147 ret
= autofs_smf_get_prop("trace", defval
, DEFAULT_INSTANCE
,
148 SCF_TYPE_INTEGER
, AUTOMOUNTD
, &bufsz
);
151 trace
= strtol(defval
, (char **)NULL
, 10);
155 put_automountd_env();
157 while ((c
= getopt(argc
, argv
, "vnTD:")) != EOF
) {
163 automountd_nobrowse
++;
169 (void) putenv(optarg
);
176 if (sysinfo(SI_HOSTNAME
, self
, sizeof (self
)) == -1) {
178 (void) fprintf(stderr
,
179 "automountd: can't determine hostname, error: %d\n",
187 perror("cannot fork");
195 openlog("automountd", LOG_PID
, LOG_DAEMON
);
196 (void) setlocale(LC_ALL
, "");
199 * Create the door_servers to manage fork/exec requests for
200 * mounts and executable automount maps
202 if ((did_fork_exec
= door_create(automountd_do_fork_exec
,
204 syslog(LOG_ERR
, "door_create failed: %m, Exiting.");
207 if ((did_exec_map
= door_create(automountd_do_exec_map
,
209 syslog(LOG_ERR
, "door_create failed: %m, Exiting.");
210 if (door_revoke(did_fork_exec
) == -1) {
211 syslog(LOG_ERR
, "failed to door_revoke(%d) %m",
217 * Before we become multithreaded we fork allowing the parent
218 * to become a door server to handle all mount and unmount
219 * requests. This works around a potential hang in using
220 * fork1() within a multithreaded environment
226 "can't fork the automountd mount process %m");
227 if (door_revoke(did_fork_exec
) == -1) {
228 syslog(LOG_ERR
, "failed to door_revoke(%d) %m",
231 if (door_revoke(did_exec_map
) == -1) {
232 syslog(LOG_ERR
, "failed to door_revoke(%d) %m",
236 } else if (pid
> 0) {
237 /* this is the door server process */
238 automountd_wait_for_cleanup(pid
);
242 (void) rwlock_init(&cache_lock
, USYNC_THREAD
, NULL
);
243 (void) rwlock_init(&autofs_rddir_cache_lock
, USYNC_THREAD
, NULL
);
246 * initialize the name services, use NULL arguments to ensure
247 * we don't initialize the stack of files used in file service
249 (void) ns_setup(NULL
, NULL
);
252 * we're using doors and its thread management now so we need to
253 * make sure we have more than the default of 256 file descriptors
256 rlset
.rlim_cur
= RLIM_INFINITY
;
257 rlset
.rlim_max
= RLIM_INFINITY
;
258 if (setrlimit(RLIMIT_NOFILE
, &rlset
) == -1)
259 syslog(LOG_ERR
, "setrlimit failed for %s: %s", AUTOMOUNTD
,
262 (void) enable_extended_FILE_stdio(-1, -1);
265 * establish our lock on the lock file and write our pid to it.
266 * exit if some other process holds the lock, or if there's any
267 * error in writing/locking the file.
269 pid
= _enter_daemon_lock(AUTOMOUNTD
);
274 syslog(LOG_ERR
, "error locking for %s: %m", AUTOMOUNTD
);
277 /* daemon was already running */
282 * If we coredump it'll be /core.
285 syslog(LOG_ERR
, "chdir /: %m");
288 * Create cache_cleanup thread
290 if (thr_create(NULL
, 0, (void *(*)(void *))cache_cleanup
, NULL
,
291 THR_DETACHED
| THR_DAEMON
| THR_NEW_LWP
, NULL
)) {
292 syslog(LOG_ERR
, "unable to create cache_cleanup thread");
296 /* other initializations */
297 (void) rwlock_init(&portmap_cache_lock
, USYNC_THREAD
, NULL
);
299 (void) signal(SIGHUP
, warn_hup
);
302 return (start_autofs_svcs());
307 * The old automounter supported a SIGHUP
308 * to allow it to resynchronize internal
309 * state with the /etc/mnttab.
310 * This is no longer relevant, but we
311 * need to catch the signal and warn
319 syslog(LOG_ERR
, "SIGHUP received: ignored");
320 (void) signal(SIGHUP
, warn_hup
);
326 (void) fprintf(stderr
, "Usage: automountd\n"
327 "\t[-T]\t\t(trace requests)\n"
328 "\t[-v]\t\t(verbose error msgs)\n"
329 "\t[-D n=s]\t(define env variable)\n");
336 autofs_rddirargs
*req
,
337 autofs_rddirres
*res
)
340 trace_prt(1, "READDIR REQUEST : %s @ %ld\n",
341 req
->rda_map
, req
->rda_offset
);
343 do_readdir(req
, res
);
345 trace_prt(1, "READDIR REPLY : status=%d\n", res
->rd_status
);
349 autofs_readdir_1_free_r(struct autofs_rddirres
*res
)
351 if (res
->rd_status
== AUTOFS_OK
) {
352 free(res
->rd_rddir
.rddir_entries
);
363 struct umntrequest
*ul
;
366 char ctime_buf
[CTIME_BUF_LEN
];
367 if (ctime_r(&timenow
, ctime_buf
) == NULL
)
370 trace_prt(1, "UNMOUNT REQUEST: %s", ctime_buf
);
371 for (ul
= m
; ul
; ul
= ul
->next
)
372 trace_prt(1, " resource=%s fstype=%s mntpnt=%s"
378 ul
->isdirect
? "direct" : "indirect");
382 res
->status
= do_unmount1(m
);
385 trace_prt(1, "UNMOUNT REPLY: status=%d\n", res
->status
);
390 autofs_lookupargs
*m
,
391 autofs_lookupres
*res
)
393 autofs_action_t action
;
398 char ctime_buf
[CTIME_BUF_LEN
];
399 if (ctime_r(&timenow
, ctime_buf
) == NULL
)
402 trace_prt(1, "LOOKUP REQUEST: %s", ctime_buf
);
403 trace_prt(1, " name=%s[%s] map=%s opts=%s path=%s direct=%d\n",
404 m
->name
, m
->subdir
, m
->map
, m
->opts
, m
->path
, m
->isdirect
);
407 bzero(&link
, sizeof (struct linka
));
409 status
= do_lookup1(m
->map
, m
->name
, m
->subdir
, m
->opts
, m
->path
,
410 (uint_t
)m
->isdirect
, m
->uid
, &action
, &link
);
413 * Return action list to kernel.
415 res
->lu_res
= AUTOFS_OK
;
416 if ((res
->lu_type
.action
= action
) == AUTOFS_LINK_RQ
) {
417 res
->lu_type
.lookup_result_type_u
.lt_linka
= link
;
423 res
->lu_res
= AUTOFS_NOENT
;
425 res
->lu_verbose
= verbose
;
428 trace_prt(1, "LOOKUP REPLY : status=%d\n", res
->lu_res
);
433 autofs_lookupargs
*m
,
434 autofs_mountres
*res
)
437 action_list
*alp
= NULL
;
440 char ctime_buf
[CTIME_BUF_LEN
];
441 if (ctime_r(&timenow
, ctime_buf
) == NULL
)
444 trace_prt(1, "MOUNT REQUEST: %s", ctime_buf
);
445 trace_prt(1, " name=%s[%s] map=%s opts=%s path=%s direct=%d\n",
446 m
->name
, m
->subdir
, m
->map
, m
->opts
, m
->path
, m
->isdirect
);
449 status
= do_mount1(m
->map
, m
->name
, m
->subdir
, m
->opts
, m
->path
,
450 (uint_t
)m
->isdirect
, m
->uid
, &alp
, DOMOUNT_USER
);
453 * An error occurred, free action list if allocated.
456 free_action_list(alp
);
462 * Return action list to kernel.
464 res
->mr_type
.status
= AUTOFS_ACTION
;
465 res
->mr_type
.mount_result_type_u
.list
= alp
;
468 * No work to do left for the kernel
470 res
->mr_type
.status
= AUTOFS_DONE
;
471 res
->mr_type
.mount_result_type_u
.error
= status
;
475 switch (res
->mr_type
.status
) {
478 "MOUNT REPLY : status=%d, AUTOFS_ACTION\n",
483 "MOUNT REPLY : status=%d, AUTOFS_DONE\n",
487 trace_prt(1, "MOUNT REPLY : status=%d, UNKNOWN\n",
492 if (status
&& verbose
) {
495 syslog(LOG_ERR
, "mount of %s failed", m
->path
);
499 "mount of %s/%s failed", m
->path
, m
->name
);
505 autofs_mount_1_free_r(struct autofs_mountres
*res
)
507 if (res
->mr_type
.status
== AUTOFS_ACTION
) {
509 trace_prt(1, "freeing action list\n");
510 free_action_list(res
->mr_type
.mount_result_type_u
.list
);
515 * Used for reporting messages from code shared with automount command.
516 * Formats message into a buffer and calls syslog.
518 * Print an error. Works like printf (fmt string and variable args)
519 * except that it will subsititute an error message for a "%m" string
523 pr_msg(const char *fmt
, ...)
526 char fmtbuff
[BUFSIZ
], buff
[BUFSIZ
];
533 for (p1
= fmt
; *p1
; p1
++) {
534 if (*p1
== '%' && *(p1
+ 1) == 'm') {
535 (void) strcpy(p2
, strerror(errno
));
542 if (p2
> fmtbuff
&& *(p2
-1) != '\n')
547 (void) vsprintf(buff
, fmtbuff
, ap
);
549 syslog(LOG_ERR
, buff
);
553 free_action_list(action_list
*alp
)
555 action_list
*p
, *next
= NULL
;
558 for (p
= alp
; p
!= NULL
; p
= next
) {
559 switch (p
->action
.action
) {
560 case AUTOFS_MOUNT_RQ
:
561 mp
= &(p
->action
.action_list_entry_u
.mounta
);
562 /* LINTED pointer alignment */
564 if (strcmp(mp
->fstype
, "autofs") == 0) {
565 free_autofs_args((autofs_args
*)
567 } else if (strncmp(mp
->fstype
, "nfs", 3) == 0) {
568 free_nfs_args((struct nfs_args
*)
578 "non AUTOFS_MOUNT_RQ requests not implemented\n");
582 "non AUTOFS_MOUNT_RQ requests not implemented\n");
591 autofs_lookup_1_free_args(autofs_lookupargs
*args
)
601 autofs_unmount_1_free_args(umntrequest
*args
)
603 free(args
->mntresource
);
608 autofs_unmount_1_free_args(args
->next
);
612 autofs_setdoor(int did
)
619 (void) _autofssys(AUTOFS_SETDOOR
, &did
);
623 autofs_get_buffer(size_t size
)
625 autofs_tsd_t
*tsd
= NULL
;
628 * Make sure the buffer size is aligned
630 (void) thr_getspecific(s_thr_key
, (void **)&tsd
);
632 tsd
= (autofs_tsd_t
*)malloc(sizeof (autofs_tsd_t
));
636 tsd
->atsd_buf
= malloc(size
);
637 if (tsd
->atsd_buf
!= NULL
)
638 tsd
->atsd_len
= size
;
641 (void) thr_setspecific(s_thr_key
, tsd
);
643 if (tsd
->atsd_buf
&& (tsd
->atsd_len
< size
)) {
645 tsd
->atsd_buf
= malloc(size
);
646 if (tsd
->atsd_buf
!= NULL
)
647 tsd
->atsd_len
= size
;
654 bzero(tsd
->atsd_buf
, size
);
655 return (tsd
->atsd_buf
);
658 gettext("Can't Allocate tsd buffer, size %d"), size
);
664 * Each request will automatically spawn a new thread with this
665 * as its entry point.
681 autofs_lookupargs
*xdrargs
;
682 autofs_lookupres lookup_res
;
683 autofs_rddirargs
*rddir_args
;
684 autofs_rddirres rddir_res
;
685 autofs_mountres mount_res
;
686 umntrequest
*umnt_args
;
688 autofs_door_res_t
*door_res
;
689 autofs_door_res_t failed_res
;
691 if (arg_size
< sizeof (autofs_door_args_t
)) {
692 failed_res
.res_status
= EINVAL
;
693 error
= door_return((char *)&failed_res
,
694 sizeof (autofs_door_res_t
), NULL
, 0);
696 * If we got here the door_return() failed.
698 syslog(LOG_ERR
, "Bad argument, door_return failure %d", error
);
702 timenow
= time(NULL
);
704 which
= ((autofs_door_args_t
*)argp
)->cmd
;
707 if (error
= decode_args(xdr_autofs_lookupargs
,
708 (autofs_door_args_t
*)argp
, (caddr_t
*)&xdrargs
,
709 sizeof (autofs_lookupargs
))) {
711 "error allocating lookup arguments buffer");
712 failed_res
.res_status
= error
;
713 failed_res
.xdr_len
= 0;
714 res
= (caddr_t
)&failed_res
;
718 bzero(&lookup_res
, sizeof (autofs_lookupres
));
720 autofs_lookup_1_r(xdrargs
, &lookup_res
);
722 autofs_lookup_1_free_args(xdrargs
);
725 if (!encode_res(xdr_autofs_lookupres
, &door_res
,
726 (caddr_t
)&lookup_res
, &res_size
)) {
728 "error allocating lookup results buffer");
729 failed_res
.res_status
= EINVAL
;
730 failed_res
.xdr_len
= 0;
731 res
= (caddr_t
)&failed_res
;
733 door_res
->res_status
= 0;
734 res
= (caddr_t
)door_res
;
739 if (error
= decode_args(xdr_autofs_lookupargs
,
740 (autofs_door_args_t
*)argp
, (caddr_t
*)&xdrargs
,
741 sizeof (autofs_lookupargs
))) {
743 "error allocating lookup arguments buffer");
744 failed_res
.res_status
= error
;
745 failed_res
.xdr_len
= 0;
746 res
= (caddr_t
)&failed_res
;
751 autofs_mntinfo_1_r((autofs_lookupargs
*)xdrargs
, &mount_res
);
753 autofs_lookup_1_free_args(xdrargs
);
757 * Only reason we would get a NULL res is because
758 * we could not allocate a results buffer. Use
759 * a local one to return the error EAGAIN as has
760 * always been done when memory allocations fail.
762 if (!encode_res(xdr_autofs_mountres
, &door_res
,
763 (caddr_t
)&mount_res
, &res_size
)) {
765 "error allocating mount results buffer");
766 failed_res
.res_status
= EAGAIN
;
767 failed_res
.xdr_len
= 0;
768 res
= (caddr_t
)&failed_res
;
770 door_res
->res_status
= 0;
771 res
= (caddr_t
)door_res
;
773 autofs_mount_1_free_r(&mount_res
);
777 if (error
= decode_args(xdr_umntrequest
,
778 (autofs_door_args_t
*)argp
,
779 (caddr_t
*)&umnt_args
, sizeof (umntrequest
))) {
781 "error allocating unmount argument buffer");
782 failed_res
.res_status
= error
;
783 failed_res
.xdr_len
= 0;
784 res
= (caddr_t
)&failed_res
;
785 res_size
= sizeof (autofs_door_res_t
);
789 autofs_unmount_1_r(umnt_args
, &umount_res
);
791 error
= umount_res
.status
;
793 autofs_unmount_1_free_args(umnt_args
);
796 if (!encode_res(xdr_umntres
, &door_res
, (caddr_t
)&umount_res
,
799 "error allocating unmount results buffer");
800 failed_res
.res_status
= EINVAL
;
801 failed_res
.xdr_len
= 0;
802 res
= (caddr_t
)&failed_res
;
803 res_size
= sizeof (autofs_door_res_t
);
805 door_res
->res_status
= 0;
806 res
= (caddr_t
)door_res
;
811 if (error
= decode_args(xdr_autofs_rddirargs
,
812 (autofs_door_args_t
*)argp
,
813 (caddr_t
*)&rddir_args
,
814 sizeof (autofs_rddirargs
))) {
816 "error allocating readdir argument buffer");
817 failed_res
.res_status
= error
;
818 failed_res
.xdr_len
= 0;
819 res
= (caddr_t
)&failed_res
;
820 res_size
= sizeof (autofs_door_res_t
);
824 autofs_readdir_1_r(rddir_args
, &rddir_res
);
826 free(rddir_args
->rda_map
);
829 if (!encode_res(xdr_autofs_rddirres
, &door_res
,
830 (caddr_t
)&rddir_res
, &res_size
)) {
832 "error allocating readdir results buffer");
833 failed_res
.res_status
= ENOMEM
;
834 failed_res
.xdr_len
= 0;
835 res
= (caddr_t
)&failed_res
;
836 res_size
= sizeof (autofs_door_res_t
);
838 door_res
->res_status
= 0;
839 res
= (caddr_t
)door_res
;
841 autofs_readdir_1_free_r(&rddir_res
);
844 case AUTOFS_DUMP_DEBUG
:
845 check_leaks("/var/tmp/automountd.leak");
846 error
= door_return(NULL
, 0, NULL
, 0);
848 * If we got here, door_return() failed
850 syslog(LOG_ERR
, "dump debug door_return failure %d",
859 failed_res
.res_status
= EINVAL
;
860 res
= (char *)&failed_res
;
861 res_size
= sizeof (autofs_door_res_t
);
867 error
= door_return(res
, res_size
, NULL
, 0);
869 if (errno
== E2BIG
) {
871 * Failed due to encoded results being bigger than the
872 * kernel expected bufsize. Passing actual results size
873 * back down to kernel.
875 failed_res
.res_status
= EOVERFLOW
;
876 failed_res
.xdr_len
= srsz
;
877 res
= (caddr_t
)&failed_res
;
878 res_size
= sizeof (autofs_door_res_t
);
880 syslog(LOG_ERR
, "door_return failed %d, buffer %p, "
881 "buffer size %d", error
, (void *)res
, res_size
);
885 (void) door_return(res
, res_size
, NULL
, 0);
890 start_autofs_svcs(void)
897 if ((doorfd
= door_create(autofs_doorfunc
, NULL
,
898 DOOR_REFUSE_DESC
| DOOR_NO_CANCEL
)) == -1) {
899 syslog(LOG_ERR
, gettext("Unable to create door\n"));
905 * Create a file system path for the door
907 if ((dfd
= open(AUTOFS_DOOR
, O_RDWR
|O_CREAT
|O_TRUNC
,
908 S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IROTH
)) == -1) {
909 syslog(LOG_ERR
, "Unable to open %s: %m\n", AUTOFS_DOOR
);
910 (void) close(doorfd
);
915 * stale associations clean up
917 (void) fdetach(AUTOFS_DOOR
);
920 * Register in the namespace to the kernel to door_ki_open.
922 if (fattach(doorfd
, AUTOFS_DOOR
) == -1) {
923 syslog(LOG_ERR
, "Unable to fattach door %m\n", AUTOFS_DOOR
);
925 (void) close(doorfd
);
931 * Pass door name to kernel for door_ki_open
933 autofs_setdoor(doorfd
);
935 (void) thr_keycreate(&s_thr_key
, NULL
);
938 * Wait for incoming calls
945 syslog(LOG_ERR
, gettext("Door server exited"));
952 autofs_door_args_t
*argp
,
958 caddr_t tmpargs
= (caddr_t
)&((autofs_door_args_t
*)argp
)->xdr_arg
;
959 size_t arg_size
= ((autofs_door_args_t
*)argp
)->xdr_len
;
961 xdrmem_create(&xdrs
, tmpargs
, arg_size
, XDR_DECODE
);
963 *xdrargs
= malloc(size
);
964 if (*xdrargs
== NULL
) {
965 syslog(LOG_ERR
, "error allocating arguments buffer");
969 bzero(*xdrargs
, size
);
971 if (!(*xdrfunc
)(&xdrs
, *xdrargs
)) {
974 syslog(LOG_ERR
, "error decoding arguments");
985 autofs_door_res_t
**results
,
991 *size
= xdr_sizeof((*xdrfunc
), resp
);
992 *results
= autofs_get_buffer(
993 sizeof (autofs_door_res_t
) + *size
);
994 if (*results
== NULL
) {
995 (*results
)->res_status
= ENOMEM
;
998 (*results
)->xdr_len
= *size
;
999 *size
= sizeof (autofs_door_res_t
) + (*results
)->xdr_len
;
1000 xdrmem_create(&xdrs
, (caddr_t
)((*results
)->xdr_res
),
1001 (*results
)->xdr_len
, XDR_ENCODE
);
1002 if (!(*xdrfunc
)(&xdrs
, resp
)) {
1003 (*results
)->res_status
= EINVAL
;
1004 syslog(LOG_ERR
, "error encoding results");
1007 (*results
)->res_status
= 0;
1012 automountd_wait_for_cleanup(pid_t pid
)
1018 * Wait for the main automountd process to exit so we cleanup
1020 (void) waitpid(pid
, &status
, 0);
1022 child_exitval
= WEXITSTATUS(status
);
1025 * Shutdown the door server for mounting and unmounting
1028 if (door_revoke(did_fork_exec
) == -1) {
1029 syslog(LOG_ERR
, "failed to door_revoke(%d) %m", did_fork_exec
);
1031 if (door_revoke(did_exec_map
) == -1) {
1032 syslog(LOG_ERR
, "failed to door_revoke(%d) %m", did_exec_map
);
1034 exit(child_exitval
);