Merge commit 'ad3ad82ad2fb99c424a8482bd1908d08b990ccea'
[unleashed.git] / usr / src / cmd / fs.d / autofs / autod_main.c
blob4d0d3db77b3fabd595202e216be3ee306cfc8631
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <stdio.h>
27 #include <stdio_ext.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <signal.h>
31 #include <sys/types.h>
32 #include <memory.h>
33 #include <stropts.h>
34 #include <netconfig.h>
35 #include <stdarg.h>
36 #include <sys/resource.h>
37 #include <sys/systeminfo.h>
38 #include <syslog.h>
39 #include <errno.h>
40 #include <sys/sockio.h>
41 #include <rpc/xdr.h>
42 #include <net/if.h>
43 #include <netdir.h>
44 #include <string.h>
45 #include <thread.h>
46 #include <locale.h>
47 #include <door.h>
48 #include <limits.h>
49 #include "automount.h"
50 #include <sys/vfs.h>
51 #include <sys/mnttab.h>
52 #include <arpa/inet.h>
53 #include <rpcsvc/daemon_utils.h>
54 #include <deflt.h>
55 #include <strings.h>
56 #include <priv.h>
57 #include <sys/utsname.h>
58 #include <sys/thread.h>
59 #include <nfs/rnode.h>
60 #include <nfs/nfs.h>
61 #include <wait.h>
62 #include <libshare.h>
63 #include <libscf.h>
64 #include "smfcfg.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 *);
78 static void usage();
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
92 #ifdef DEBUG
93 #define AUTOFS_DOOR "/var/run/autofs_door"
94 #endif /* DEBUG */
96 static thread_key_t s_thr_key;
98 struct autodir *dir_head;
99 struct autodir *dir_tail;
100 char self[64];
102 time_t timenow;
103 int verbose = 0;
104 int trace = 0;
105 int automountd_nobrowse = 0;
108 main(argc, argv)
109 int argc;
110 char *argv[];
113 pid_t pid;
114 int c, error;
115 struct rlimit rlset;
116 char defval[6];
117 int ret = 0, bufsz;
119 if (geteuid() != 0) {
120 (void) fprintf(stderr, "%s must be run as root\n", argv[0]);
121 exit(1);
125 * Read in the values from SMF first before we check
126 * commandline options so the options override the file.
128 bufsz = 6;
129 ret = autofs_smf_get_prop("automountd_verbose", defval,
130 DEFAULT_INSTANCE, SCF_TYPE_BOOLEAN, AUTOMOUNTD, &bufsz);
131 if (ret == SA_OK) {
132 if (strncasecmp("true", defval, 4) == 0)
133 verbose = TRUE;
134 else
135 verbose = FALSE;
137 bufsz = 6;
138 ret = autofs_smf_get_prop("nobrowse", defval, DEFAULT_INSTANCE,
139 SCF_TYPE_BOOLEAN, AUTOMOUNTD, &bufsz);
140 if (ret == SA_OK) {
141 if (strncasecmp("true", defval, 4) == 0)
142 automountd_nobrowse = TRUE;
143 else
144 automountd_nobrowse = FALSE;
146 bufsz = 6;
147 ret = autofs_smf_get_prop("trace", defval, DEFAULT_INSTANCE,
148 SCF_TYPE_INTEGER, AUTOMOUNTD, &bufsz);
149 if (ret == SA_OK) {
150 errno = 0;
151 trace = strtol(defval, (char **)NULL, 10);
152 if (errno != 0)
153 trace = 0;
155 put_automountd_env();
157 while ((c = getopt(argc, argv, "vnTD:")) != EOF) {
158 switch (c) {
159 case 'v':
160 verbose++;
161 break;
162 case 'n':
163 automountd_nobrowse++;
164 break;
165 case 'T':
166 trace++;
167 break;
168 case 'D':
169 (void) putenv(optarg);
170 break;
171 default:
172 usage();
176 if (sysinfo(SI_HOSTNAME, self, sizeof (self)) == -1) {
177 error = errno;
178 (void) fprintf(stderr,
179 "automountd: can't determine hostname, error: %d\n",
180 error);
181 exit(1);
184 #ifndef DEBUG
185 pid = fork();
186 if (pid < 0) {
187 perror("cannot fork");
188 exit(1);
190 if (pid)
191 exit(0);
192 #endif
194 (void) setsid();
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,
203 NULL, 0)) == -1) {
204 syslog(LOG_ERR, "door_create failed: %m, Exiting.");
205 exit(errno);
207 if ((did_exec_map = door_create(automountd_do_exec_map,
208 NULL, 0)) == -1) {
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",
212 did_fork_exec);
214 exit(errno);
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
223 pid = fork1();
224 if (pid < 0) {
225 syslog(LOG_ERR,
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",
229 did_fork_exec);
231 if (door_revoke(did_exec_map) == -1) {
232 syslog(LOG_ERR, "failed to door_revoke(%d) %m",
233 did_exec_map);
235 exit(1);
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
254 * available.
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,
260 strerror(errno));
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);
270 switch (pid) {
271 case 0:
272 break;
273 case -1:
274 syslog(LOG_ERR, "error locking for %s: %m", AUTOMOUNTD);
275 exit(2);
276 default:
277 /* daemon was already running */
278 exit(0);
282 * If we coredump it'll be /core.
284 if (chdir("/") < 0)
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");
293 exit(1);
296 /* other initializations */
297 (void) rwlock_init(&portmap_cache_lock, USYNC_THREAD, NULL);
299 (void) signal(SIGHUP, warn_hup);
301 /* start services */
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
312 * the user.
314 /* ARGSUSED */
315 static void
316 warn_hup(i)
317 int i;
319 syslog(LOG_ERR, "SIGHUP received: ignored");
320 (void) signal(SIGHUP, warn_hup);
323 static void
324 usage()
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");
330 exit(1);
331 /* NOTREACHED */
334 static void
335 autofs_readdir_1_r(
336 autofs_rddirargs *req,
337 autofs_rddirres *res)
339 if (trace > 0)
340 trace_prt(1, "READDIR REQUEST : %s @ %ld\n",
341 req->rda_map, req->rda_offset);
343 do_readdir(req, res);
344 if (trace > 0)
345 trace_prt(1, "READDIR REPLY : status=%d\n", res->rd_status);
348 static void
349 autofs_readdir_1_free_r(struct autofs_rddirres *res)
351 if (res->rd_status == AUTOFS_OK) {
352 free(res->rd_rddir.rddir_entries);
357 /* ARGSUSED */
358 static void
359 autofs_unmount_1_r(
360 umntrequest *m,
361 umntres *res)
363 struct umntrequest *ul;
365 if (trace > 0) {
366 char ctime_buf[CTIME_BUF_LEN];
367 if (ctime_r(&timenow, ctime_buf) == NULL)
368 ctime_buf[0] = '\0';
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"
373 " mntopts=%s %s\n",
374 ul->mntresource,
375 ul->fstype,
376 ul->mntpnt,
377 ul->mntopts,
378 ul->isdirect ? "direct" : "indirect");
382 res->status = do_unmount1(m);
384 if (trace > 0)
385 trace_prt(1, "UNMOUNT REPLY: status=%d\n", res->status);
388 static void
389 autofs_lookup_1_r(
390 autofs_lookupargs *m,
391 autofs_lookupres *res)
393 autofs_action_t action;
394 struct linka link;
395 int status;
397 if (trace > 0) {
398 char ctime_buf[CTIME_BUF_LEN];
399 if (ctime_r(&timenow, ctime_buf) == NULL)
400 ctime_buf[0] = '\0';
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);
411 if (status == 0) {
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;
419 } else {
421 * Entry not found
423 res->lu_res = AUTOFS_NOENT;
425 res->lu_verbose = verbose;
427 if (trace > 0)
428 trace_prt(1, "LOOKUP REPLY : status=%d\n", res->lu_res);
431 static void
432 autofs_mntinfo_1_r(
433 autofs_lookupargs *m,
434 autofs_mountres *res)
436 int status;
437 action_list *alp = NULL;
439 if (trace > 0) {
440 char ctime_buf[CTIME_BUF_LEN];
441 if (ctime_r(&timenow, ctime_buf) == NULL)
442 ctime_buf[0] = '\0';
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);
451 if (status != 0) {
453 * An error occurred, free action list if allocated.
455 if (alp != NULL) {
456 free_action_list(alp);
457 alp = NULL;
460 if (alp != NULL) {
462 * Return action list to kernel.
464 res->mr_type.status = AUTOFS_ACTION;
465 res->mr_type.mount_result_type_u.list = alp;
466 } else {
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;
474 if (trace > 0) {
475 switch (res->mr_type.status) {
476 case AUTOFS_ACTION:
477 trace_prt(1,
478 "MOUNT REPLY : status=%d, AUTOFS_ACTION\n",
479 status);
480 break;
481 case AUTOFS_DONE:
482 trace_prt(1,
483 "MOUNT REPLY : status=%d, AUTOFS_DONE\n",
484 status);
485 break;
486 default:
487 trace_prt(1, "MOUNT REPLY : status=%d, UNKNOWN\n",
488 status);
492 if (status && verbose) {
493 if (m->isdirect) {
494 /* direct mount */
495 syslog(LOG_ERR, "mount of %s failed", m->path);
496 } else {
497 /* indirect mount */
498 syslog(LOG_ERR,
499 "mount of %s/%s failed", m->path, m->name);
504 static void
505 autofs_mount_1_free_r(struct autofs_mountres *res)
507 if (res->mr_type.status == AUTOFS_ACTION) {
508 if (trace > 2)
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
520 * (like syslog).
522 void
523 pr_msg(const char *fmt, ...)
525 va_list ap;
526 char fmtbuff[BUFSIZ], buff[BUFSIZ];
527 const char *p1;
528 char *p2;
530 p2 = fmtbuff;
531 fmt = gettext(fmt);
533 for (p1 = fmt; *p1; p1++) {
534 if (*p1 == '%' && *(p1 + 1) == 'm') {
535 (void) strcpy(p2, strerror(errno));
536 p2 += strlen(p2);
537 p1++;
538 } else {
539 *p2++ = *p1;
542 if (p2 > fmtbuff && *(p2-1) != '\n')
543 *p2++ = '\n';
544 *p2 = '\0';
546 va_start(ap, fmt);
547 (void) vsprintf(buff, fmtbuff, ap);
548 va_end(ap);
549 syslog(LOG_ERR, buff);
552 static void
553 free_action_list(action_list *alp)
555 action_list *p, *next = NULL;
556 struct mounta *mp;
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 */
563 if (mp->fstype) {
564 if (strcmp(mp->fstype, "autofs") == 0) {
565 free_autofs_args((autofs_args *)
566 mp->dataptr);
567 } else if (strncmp(mp->fstype, "nfs", 3) == 0) {
568 free_nfs_args((struct nfs_args *)
569 mp->dataptr);
572 mp->dataptr = NULL;
573 mp->datalen = 0;
574 free_mounta(mp);
575 break;
576 case AUTOFS_LINK_RQ:
577 syslog(LOG_ERR,
578 "non AUTOFS_MOUNT_RQ requests not implemented\n");
579 break;
580 default:
581 syslog(LOG_ERR,
582 "non AUTOFS_MOUNT_RQ requests not implemented\n");
583 break;
585 next = p->next;
586 free(p);
590 static void
591 autofs_lookup_1_free_args(autofs_lookupargs *args)
593 free(args->map);
594 free(args->path);
595 free(args->name);
596 free(args->subdir);
597 free(args->opts);
600 static void
601 autofs_unmount_1_free_args(umntrequest *args)
603 free(args->mntresource);
604 free(args->mntpnt);
605 free(args->fstype);
606 free(args->mntopts);
607 if (args->next)
608 autofs_unmount_1_free_args(args->next);
611 static void
612 autofs_setdoor(int did)
615 if (did < 0) {
616 did = 0;
619 (void) _autofssys(AUTOFS_SETDOOR, &did);
622 void *
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);
631 if (tsd == NULL) {
632 tsd = (autofs_tsd_t *)malloc(sizeof (autofs_tsd_t));
633 if (tsd == NULL) {
634 return (NULL);
636 tsd->atsd_buf = malloc(size);
637 if (tsd->atsd_buf != NULL)
638 tsd->atsd_len = size;
639 else
640 tsd->atsd_len = 0;
641 (void) thr_setspecific(s_thr_key, tsd);
642 } else {
643 if (tsd->atsd_buf && (tsd->atsd_len < size)) {
644 free(tsd->atsd_buf);
645 tsd->atsd_buf = malloc(size);
646 if (tsd->atsd_buf != NULL)
647 tsd->atsd_len = size;
648 else {
649 tsd->atsd_len = 0;
653 if (tsd->atsd_buf) {
654 bzero(tsd->atsd_buf, size);
655 return (tsd->atsd_buf);
656 } else {
657 syslog(LOG_ERR,
658 gettext("Can't Allocate tsd buffer, size %d"), size);
659 return (NULL);
664 * Each request will automatically spawn a new thread with this
665 * as its entry point.
667 /* ARGUSED */
668 static void
669 autofs_doorfunc(
670 void *cookie,
671 char *argp,
672 size_t arg_size,
673 door_desc_t *dp,
674 uint_t n_desc)
676 char *res;
677 int res_size;
678 int which;
679 int error = 0;
680 int srsz = 0;
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;
687 umntres umount_res;
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);
699 return;
702 timenow = time(NULL);
704 which = ((autofs_door_args_t *)argp)->cmd;
705 switch (which) {
706 case AUTOFS_LOOKUP:
707 if (error = decode_args(xdr_autofs_lookupargs,
708 (autofs_door_args_t *)argp, (caddr_t *)&xdrargs,
709 sizeof (autofs_lookupargs))) {
710 syslog(LOG_ERR,
711 "error allocating lookup arguments buffer");
712 failed_res.res_status = error;
713 failed_res.xdr_len = 0;
714 res = (caddr_t)&failed_res;
715 res_size = 0;
716 break;
718 bzero(&lookup_res, sizeof (autofs_lookupres));
720 autofs_lookup_1_r(xdrargs, &lookup_res);
722 autofs_lookup_1_free_args(xdrargs);
723 free(xdrargs);
725 if (!encode_res(xdr_autofs_lookupres, &door_res,
726 (caddr_t)&lookup_res, &res_size)) {
727 syslog(LOG_ERR,
728 "error allocating lookup results buffer");
729 failed_res.res_status = EINVAL;
730 failed_res.xdr_len = 0;
731 res = (caddr_t)&failed_res;
732 } else {
733 door_res->res_status = 0;
734 res = (caddr_t)door_res;
736 break;
738 case AUTOFS_MNTINFO:
739 if (error = decode_args(xdr_autofs_lookupargs,
740 (autofs_door_args_t *)argp, (caddr_t *)&xdrargs,
741 sizeof (autofs_lookupargs))) {
742 syslog(LOG_ERR,
743 "error allocating lookup arguments buffer");
744 failed_res.res_status = error;
745 failed_res.xdr_len = 0;
746 res = (caddr_t)&failed_res;
747 res_size = 0;
748 break;
751 autofs_mntinfo_1_r((autofs_lookupargs *)xdrargs, &mount_res);
753 autofs_lookup_1_free_args(xdrargs);
754 free(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)) {
764 syslog(LOG_ERR,
765 "error allocating mount results buffer");
766 failed_res.res_status = EAGAIN;
767 failed_res.xdr_len = 0;
768 res = (caddr_t)&failed_res;
769 } else {
770 door_res->res_status = 0;
771 res = (caddr_t)door_res;
773 autofs_mount_1_free_r(&mount_res);
774 break;
776 case AUTOFS_UNMOUNT:
777 if (error = decode_args(xdr_umntrequest,
778 (autofs_door_args_t *)argp,
779 (caddr_t *)&umnt_args, sizeof (umntrequest))) {
780 syslog(LOG_ERR,
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);
786 break;
789 autofs_unmount_1_r(umnt_args, &umount_res);
791 error = umount_res.status;
793 autofs_unmount_1_free_args(umnt_args);
794 free(umnt_args);
796 if (!encode_res(xdr_umntres, &door_res, (caddr_t)&umount_res,
797 &res_size)) {
798 syslog(LOG_ERR,
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);
804 } else {
805 door_res->res_status = 0;
806 res = (caddr_t)door_res;
808 break;
810 case AUTOFS_READDIR:
811 if (error = decode_args(xdr_autofs_rddirargs,
812 (autofs_door_args_t *)argp,
813 (caddr_t *)&rddir_args,
814 sizeof (autofs_rddirargs))) {
815 syslog(LOG_ERR,
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);
821 break;
824 autofs_readdir_1_r(rddir_args, &rddir_res);
826 free(rddir_args->rda_map);
827 free(rddir_args);
829 if (!encode_res(xdr_autofs_rddirres, &door_res,
830 (caddr_t)&rddir_res, &res_size)) {
831 syslog(LOG_ERR,
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);
837 } else {
838 door_res->res_status = 0;
839 res = (caddr_t)door_res;
841 autofs_readdir_1_free_r(&rddir_res);
842 break;
843 #ifdef MALLOC_DEBUG
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",
851 error);
852 return;
853 #endif
854 case NULLPROC:
855 res = NULL;
856 res_size = 0;
857 break;
858 default:
859 failed_res.res_status = EINVAL;
860 res = (char *)&failed_res;
861 res_size = sizeof (autofs_door_res_t);
862 break;
865 srsz = res_size;
866 errno = 0;
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);
879 } else {
880 syslog(LOG_ERR, "door_return failed %d, buffer %p, "
881 "buffer size %d", error, (void *)res, res_size);
882 res = NULL;
883 res_size = 0;
885 (void) door_return(res, res_size, NULL, 0);
886 /* NOTREACHED */
889 static int
890 start_autofs_svcs(void)
892 int doorfd;
893 #ifdef DEBUG
894 int dfd;
895 #endif
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"));
900 return (1);
903 #ifdef DEBUG
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);
911 return (1);
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);
924 (void) close(dfd);
925 (void) close(doorfd);
926 return (1);
928 #endif /* DEBUG */
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
940 /*CONSTCOND*/
941 while (1)
942 (void) pause();
944 /* NOTREACHED */
945 syslog(LOG_ERR, gettext("Door server exited"));
946 return (10);
949 static int
950 decode_args(
951 xdrproc_t xdrfunc,
952 autofs_door_args_t *argp,
953 caddr_t *xdrargs,
954 int size)
956 XDR xdrs;
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");
966 return (ENOMEM);
969 bzero(*xdrargs, size);
971 if (!(*xdrfunc)(&xdrs, *xdrargs)) {
972 free(*xdrargs);
973 *xdrargs = NULL;
974 syslog(LOG_ERR, "error decoding arguments");
975 return (EINVAL);
978 return (0);
982 static bool_t
983 encode_res(
984 xdrproc_t xdrfunc,
985 autofs_door_res_t **results,
986 caddr_t resp,
987 int *size)
989 XDR xdrs;
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;
996 return (FALSE);
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");
1005 return (FALSE);
1007 (*results)->res_status = 0;
1008 return (TRUE);
1011 static void
1012 automountd_wait_for_cleanup(pid_t pid)
1014 int status;
1015 int child_exitval;
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
1026 * filesystems
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);