autod_main.c revision dd51520e127b452179a2ce4ea3bd8dee949f9afe
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <stdio.h>
#include <stdio_ext.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <memory.h>
#include <stropts.h>
#include <netconfig.h>
#include <stdarg.h>
#include <sys/resource.h>
#include <sys/systeminfo.h>
#include <syslog.h>
#include <errno.h>
#include <sys/sockio.h>
#include <rpc/xdr.h>
#include <net/if.h>
#include <netdir.h>
#include <string.h>
#include <thread.h>
#include <locale.h>
#include <door.h>
#include <limits.h>
#include "automount.h"
#include <sys/vfs.h>
#include <sys/mnttab.h>
#include <arpa/inet.h>
#include <rpcsvc/daemon_utils.h>
#include <deflt.h>
#include <strings.h>
#include <priv.h>
#include <tsol/label.h>
#include <sys/utsname.h>
#include <sys/thread.h>
#include <nfs/rnode.h>
#include <nfs/nfs.h>
#include <wait.h>
#include <libshare.h>
#include <libscf.h>
#include "smfcfg.h"
static void autofs_doorfunc(void *, char *, size_t, door_desc_t *, uint_t);
static void autofs_setdoor(int);
static void autofs_mntinfo_1_r(autofs_lookupargs *, autofs_mountres *);
static void autofs_mount_1_free_r(struct autofs_mountres *);
static void autofs_lookup_1_r(autofs_lookupargs *, autofs_lookupres *);
static void autofs_lookup_1_free_args(autofs_lookupargs *);
static void autofs_unmount_1_r(umntrequest *, umntres *);
static void autofs_unmount_1_free_args(umntrequest *);
static void autofs_readdir_1_r(autofs_rddirargs *, autofs_rddirres *);
static void autofs_readdir_1_free_r(struct autofs_rddirres *);
static int decode_args(xdrproc_t, autofs_door_args_t *, caddr_t *, int);
static bool_t encode_res(xdrproc_t, autofs_door_res_t **, caddr_t, int *);
static void usage();
static void warn_hup(int);
static void free_action_list();
static int start_autofs_svcs();
static void automountd_wait_for_cleanup(pid_t);
/*
* Private autofs system call
*/
extern int _autofssys(int, void *);
#define CTIME_BUF_LEN 26
#define RESOURCE_FACTOR 8
#ifdef DEBUG
#define AUTOFS_DOOR "/var/run/autofs_door"
#endif /* DEBUG */
static thread_key_t s_thr_key;
struct autodir *dir_head;
struct autodir *dir_tail;
char self[64];
time_t timenow;
int verbose = 0;
int trace = 0;
int automountd_nobrowse = 0;
int
main(argc, argv)
int argc;
char *argv[];
{
pid_t pid;
int c, error;
struct rlimit rlset;
char defval[6];
int ret = 0, bufsz;
if (geteuid() != 0) {
(void) fprintf(stderr, "%s must be run as root\n", argv[0]);
exit(1);
}
/*
* Read in the values from SMF first before we check
* commandline options so the options override the file.
*/
bufsz = 6;
ret = autofs_smf_get_prop("automountd_verbose", defval,
DEFAULT_INSTANCE, SCF_TYPE_BOOLEAN, AUTOMOUNTD, &bufsz);
if (ret == SA_OK) {
if (strncasecmp("true", defval, 4) == 0)
verbose = TRUE;
else
verbose = FALSE;
}
bufsz = 6;
ret = autofs_smf_get_prop("nobrowse", defval, DEFAULT_INSTANCE,
SCF_TYPE_BOOLEAN, AUTOMOUNTD, &bufsz);
if (ret == SA_OK) {
if (strncasecmp("true", defval, 4) == 0)
automountd_nobrowse = TRUE;
else
automountd_nobrowse = FALSE;
}
bufsz = 6;
ret = autofs_smf_get_prop("trace", defval, DEFAULT_INSTANCE,
SCF_TYPE_INTEGER, AUTOMOUNTD, &bufsz);
if (ret == SA_OK) {
errno = 0;
trace = strtol(defval, (char **)NULL, 10);
if (errno != 0)
trace = 0;
}
put_automountd_env();
while ((c = getopt(argc, argv, "vnTD:")) != EOF) {
switch (c) {
case 'v':
verbose++;
break;
case 'n':
automountd_nobrowse++;
break;
case 'T':
trace++;
break;
case 'D':
(void) putenv(optarg);
break;
default:
usage();
}
}
if (sysinfo(SI_HOSTNAME, self, sizeof (self)) == -1) {
error = errno;
(void) fprintf(stderr,
"automountd: can't determine hostname, error: %d\n",
error);
exit(1);
}
#ifndef DEBUG
pid = fork();
if (pid < 0) {
perror("cannot fork");
exit(1);
}
if (pid)
exit(0);
#endif
(void) setsid();
openlog("automountd", LOG_PID, LOG_DAEMON);
(void) setlocale(LC_ALL, "");
/*
* Create the door_servers to manage fork/exec requests for
* mounts and executable automount maps
*/
if ((did_fork_exec = door_create(automountd_do_fork_exec,
NULL, NULL)) == -1) {
syslog(LOG_ERR, "door_create failed: %m, Exiting.");
exit(errno);
}
if ((did_exec_map = door_create(automountd_do_exec_map,
NULL, NULL)) == -1) {
syslog(LOG_ERR, "door_create failed: %m, Exiting.");
if (door_revoke(did_fork_exec) == -1) {
syslog(LOG_ERR, "failed to door_revoke(%d) %m",
did_fork_exec);
}
exit(errno);
}
/*
* Before we become multithreaded we fork allowing the parent
* to become a door server to handle all mount and unmount
* requests. This works around a potential hang in using
* fork1() within a multithreaded environment
*/
pid = fork1();
if (pid < 0) {
syslog(LOG_ERR,
"can't fork the automountd mount process %m");
if (door_revoke(did_fork_exec) == -1) {
syslog(LOG_ERR, "failed to door_revoke(%d) %m",
did_fork_exec);
}
if (door_revoke(did_exec_map) == -1) {
syslog(LOG_ERR, "failed to door_revoke(%d) %m",
did_exec_map);
}
exit(1);
} else if (pid > 0) {
/* this is the door server process */
automountd_wait_for_cleanup(pid);
}
(void) rwlock_init(&cache_lock, USYNC_THREAD, NULL);
(void) rwlock_init(&autofs_rddir_cache_lock, USYNC_THREAD, NULL);
/*
* initialize the name services, use NULL arguments to ensure
* we don't initialize the stack of files used in file service
*/
(void) ns_setup(NULL, NULL);
/*
* we're using doors and its thread management now so we need to
* make sure we have more than the default of 256 file descriptors
* available.
*/
rlset.rlim_cur = RLIM_INFINITY;
rlset.rlim_max = RLIM_INFINITY;
if (setrlimit(RLIMIT_NOFILE, &rlset) == -1)
syslog(LOG_ERR, "setrlimit failed for %s: %s", AUTOMOUNTD,
strerror(errno));
(void) enable_extended_FILE_stdio(-1, -1);
/*
* establish our lock on the lock file and write our pid to it.
* exit if some other process holds the lock, or if there's any
* error in writing/locking the file.
*/
pid = _enter_daemon_lock(AUTOMOUNTD);
switch (pid) {
case 0:
break;
case -1:
syslog(LOG_ERR, "error locking for %s: %m", AUTOMOUNTD);
exit(2);
default:
/* daemon was already running */
exit(0);
}
/*
* If we coredump it'll be /core.
*/
if (chdir("/") < 0)
syslog(LOG_ERR, "chdir /: %m");
/*
* Create cache_cleanup thread
*/
if (thr_create(NULL, 0, (void *(*)(void *))cache_cleanup, NULL,
THR_DETACHED | THR_DAEMON | THR_NEW_LWP, NULL)) {
syslog(LOG_ERR, "unable to create cache_cleanup thread");
exit(1);
}
/* other initializations */
(void) rwlock_init(&portmap_cache_lock, USYNC_THREAD, NULL);
/*
* On a labeled system, allow read-down nfs mounts if privileged
* (PRIV_NET_MAC_AWARE) to do so. Otherwise, ignore the error
* and "mount equal label only" behavior will result.
*/
if (is_system_labeled()) {
(void) setpflags(NET_MAC_AWARE, 1);
(void) setpflags(NET_MAC_AWARE_INHERIT, 1);
}
(void) signal(SIGHUP, warn_hup);
/* start services */
return (start_autofs_svcs());
}
/*
* The old automounter supported a SIGHUP
* to allow it to resynchronize internal
* state with the /etc/mnttab.
* This is no longer relevant, but we
* need to catch the signal and warn
* the user.
*/
/* ARGSUSED */
static void
warn_hup(i)
int i;
{
syslog(LOG_ERR, "SIGHUP received: ignored");
(void) signal(SIGHUP, warn_hup);
}
static void
usage()
{
(void) fprintf(stderr, "Usage: automountd\n"
"\t[-T]\t\t(trace requests)\n"
"\t[-v]\t\t(verbose error msgs)\n"
"\t[-D n=s]\t(define env variable)\n");
exit(1);
/* NOTREACHED */
}
static void
autofs_readdir_1_r(
autofs_rddirargs *req,
autofs_rddirres *res)
{
if (trace > 0)
trace_prt(1, "READDIR REQUEST : %s @ %ld\n",
req->rda_map, req->rda_offset);
do_readdir(req, res);
if (trace > 0)
trace_prt(1, "READDIR REPLY : status=%d\n", res->rd_status);
}
static void
autofs_readdir_1_free_r(struct autofs_rddirres *res)
{
if (res->rd_status == AUTOFS_OK) {
if (res->rd_rddir.rddir_entries)
free(res->rd_rddir.rddir_entries);
}
}
/* ARGSUSED */
static void
autofs_unmount_1_r(
umntrequest *m,
umntres *res)
{
struct umntrequest *ul;
if (trace > 0) {
char ctime_buf[CTIME_BUF_LEN];
if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL)
ctime_buf[0] = '\0';
trace_prt(1, "UNMOUNT REQUEST: %s", ctime_buf);
for (ul = m; ul; ul = ul->next)
trace_prt(1, " resource=%s fstype=%s mntpnt=%s"
" mntopts=%s %s\n",
ul->mntresource,
ul->fstype,
ul->mntpnt,
ul->mntopts,
ul->isdirect ? "direct" : "indirect");
}
res->status = do_unmount1(m);
if (trace > 0)
trace_prt(1, "UNMOUNT REPLY: status=%d\n", res->status);
}
static void
autofs_lookup_1_r(
autofs_lookupargs *m,
autofs_lookupres *res)
{
autofs_action_t action;
struct linka link;
int status;
if (trace > 0) {
char ctime_buf[CTIME_BUF_LEN];
if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL)
ctime_buf[0] = '\0';
trace_prt(1, "LOOKUP REQUEST: %s", ctime_buf);
trace_prt(1, " name=%s[%s] map=%s opts=%s path=%s direct=%d\n",
m->name, m->subdir, m->map, m->opts, m->path, m->isdirect);
}
bzero(&link, sizeof (struct linka));
status = do_lookup1(m->map, m->name, m->subdir, m->opts, m->path,
(uint_t)m->isdirect, m->uid, &action, &link);
if (status == 0) {
/*
* Return action list to kernel.
*/
res->lu_res = AUTOFS_OK;
if ((res->lu_type.action = action) == AUTOFS_LINK_RQ) {
res->lu_type.lookup_result_type_u.lt_linka = link;
}
} else {
/*
* Entry not found
*/
res->lu_res = AUTOFS_NOENT;
}
res->lu_verbose = verbose;
if (trace > 0)
trace_prt(1, "LOOKUP REPLY : status=%d\n", res->lu_res);
}
static void
autofs_mntinfo_1_r(
autofs_lookupargs *m,
autofs_mountres *res)
{
int status;
action_list *alp = NULL;
if (trace > 0) {
char ctime_buf[CTIME_BUF_LEN];
if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL)
ctime_buf[0] = '\0';
trace_prt(1, "MOUNT REQUEST: %s", ctime_buf);
trace_prt(1, " name=%s[%s] map=%s opts=%s path=%s direct=%d\n",
m->name, m->subdir, m->map, m->opts, m->path, m->isdirect);
}
status = do_mount1(m->map, m->name, m->subdir, m->opts, m->path,
(uint_t)m->isdirect, m->uid, &alp, DOMOUNT_USER);
if (status != 0) {
/*
* An error occurred, free action list if allocated.
*/
if (alp != NULL) {
free_action_list(alp);
alp = NULL;
}
}
if (alp != NULL) {
/*
* Return action list to kernel.
*/
res->mr_type.status = AUTOFS_ACTION;
res->mr_type.mount_result_type_u.list = alp;
} else {
/*
* No work to do left for the kernel
*/
res->mr_type.status = AUTOFS_DONE;
res->mr_type.mount_result_type_u.error = status;
}
if (trace > 0) {
switch (res->mr_type.status) {
case AUTOFS_ACTION:
trace_prt(1,
"MOUNT REPLY : status=%d, AUTOFS_ACTION\n",
status);
break;
case AUTOFS_DONE:
trace_prt(1,
"MOUNT REPLY : status=%d, AUTOFS_DONE\n",
status);
break;
default:
trace_prt(1, "MOUNT REPLY : status=%d, UNKNOWN\n",
status);
}
}
if (status && verbose) {
if (m->isdirect) {
/* direct mount */
syslog(LOG_ERR, "mount of %s failed", m->path);
} else {
/* indirect mount */
syslog(LOG_ERR,
"mount of %s/%s failed", m->path, m->name);
}
}
}
static void
autofs_mount_1_free_r(struct autofs_mountres *res)
{
if (res->mr_type.status == AUTOFS_ACTION) {
if (trace > 2)
trace_prt(1, "freeing action list\n");
free_action_list(res->mr_type.mount_result_type_u.list);
}
}
/*
* Used for reporting messages from code shared with automount command.
* Formats message into a buffer and calls syslog.
*
* Print an error. Works like printf (fmt string and variable args)
* except that it will subsititute an error message for a "%m" string
* (like syslog).
*/
void
pr_msg(const char *fmt, ...)
{
va_list ap;
char fmtbuff[BUFSIZ], buff[BUFSIZ];
const char *p1;
char *p2;
p2 = fmtbuff;
fmt = gettext(fmt);
for (p1 = fmt; *p1; p1++) {
if (*p1 == '%' && *(p1 + 1) == 'm') {
(void) strcpy(p2, strerror(errno));
p2 += strlen(p2);
p1++;
} else {
*p2++ = *p1;
}
}
if (p2 > fmtbuff && *(p2-1) != '\n')
*p2++ = '\n';
*p2 = '\0';
va_start(ap, fmt);
(void) vsprintf(buff, fmtbuff, ap);
va_end(ap);
syslog(LOG_ERR, buff);
}
static void
free_action_list(action_list *alp)
{
action_list *p, *next = NULL;
struct mounta *mp;
for (p = alp; p != NULL; p = next) {
switch (p->action.action) {
case AUTOFS_MOUNT_RQ:
mp = &(p->action.action_list_entry_u.mounta);
/* LINTED pointer alignment */
if (mp->fstype) {
if (strcmp(mp->fstype, "autofs") == 0) {
free_autofs_args((autofs_args *)
mp->dataptr);
} else if (strncmp(mp->fstype, "nfs", 3) == 0) {
free_nfs_args((struct nfs_args *)
mp->dataptr);
}
}
mp->dataptr = NULL;
mp->datalen = 0;
free_mounta(mp);
break;
case AUTOFS_LINK_RQ:
syslog(LOG_ERR,
"non AUTOFS_MOUNT_RQ requests not implemented\n");
break;
default:
syslog(LOG_ERR,
"non AUTOFS_MOUNT_RQ requests not implemented\n");
break;
}
next = p->next;
free(p);
}
}
static void
autofs_lookup_1_free_args(autofs_lookupargs *args)
{
if (args->map)
free(args->map);
if (args->path)
free(args->path);
if (args->name)
free(args->name);
if (args->subdir)
free(args->subdir);
if (args->opts)
free(args->opts);
}
static void
autofs_unmount_1_free_args(umntrequest *args)
{
if (args->mntresource)
free(args->mntresource);
if (args->mntpnt)
free(args->mntpnt);
if (args->fstype)
free(args->fstype);
if (args->mntopts)
free(args->mntopts);
if (args->next)
autofs_unmount_1_free_args(args->next);
}
static void
autofs_setdoor(int did)
{
if (did < 0) {
did = 0;
}
(void) _autofssys(AUTOFS_SETDOOR, &did);
}
void *
autofs_get_buffer(size_t size)
{
autofs_tsd_t *tsd = NULL;
/*
* Make sure the buffer size is aligned
*/
(void) thr_getspecific(s_thr_key, (void **)&tsd);
if (tsd == NULL) {
tsd = (autofs_tsd_t *)malloc(sizeof (autofs_tsd_t));
if (tsd == NULL) {
return (NULL);
}
tsd->atsd_buf = malloc(size);
if (tsd->atsd_buf != NULL)
tsd->atsd_len = size;
else
tsd->atsd_len = 0;
(void) thr_setspecific(s_thr_key, tsd);
} else {
if (tsd->atsd_buf && (tsd->atsd_len < size)) {
free(tsd->atsd_buf);
tsd->atsd_buf = malloc(size);
if (tsd->atsd_buf != NULL)
tsd->atsd_len = size;
else {
tsd->atsd_len = 0;
}
}
}
if (tsd->atsd_buf) {
bzero(tsd->atsd_buf, size);
return (tsd->atsd_buf);
} else {
syslog(LOG_ERR,
gettext("Can't Allocate tsd buffer, size %d"), size);
return (NULL);
}
}
/*
* Each request will automatically spawn a new thread with this
* as its entry point.
*/
/* ARGUSED */
static void
autofs_doorfunc(
void *cookie,
char *argp,
size_t arg_size,
door_desc_t *dp,
uint_t n_desc)
{
char *res;
int res_size;
int which;
int error = 0;
int srsz = 0;
autofs_lookupargs *xdrargs;
autofs_lookupres lookup_res;
autofs_rddirargs *rddir_args;
autofs_rddirres rddir_res;
autofs_mountres mount_res;
umntrequest *umnt_args;
umntres umount_res;
autofs_door_res_t *door_res;
autofs_door_res_t failed_res;
if (arg_size < sizeof (autofs_door_args_t)) {
failed_res.res_status = EINVAL;
error = door_return((char *)&failed_res,
sizeof (autofs_door_res_t), NULL, 0);
/*
* If we got here the door_return() failed.
*/
syslog(LOG_ERR, "Bad argument, door_return failure %d", error);
return;
}
timenow = time((time_t *)NULL);
which = ((autofs_door_args_t *)argp)->cmd;
switch (which) {
case AUTOFS_LOOKUP:
if (error = decode_args(xdr_autofs_lookupargs,
(autofs_door_args_t *)argp, (caddr_t *)&xdrargs,
sizeof (autofs_lookupargs))) {
syslog(LOG_ERR,
"error allocating lookup arguments buffer");
failed_res.res_status = error;
failed_res.xdr_len = 0;
res = (caddr_t)&failed_res;
res_size = 0;
break;
}
bzero(&lookup_res, sizeof (autofs_lookupres));
autofs_lookup_1_r(xdrargs, &lookup_res);
autofs_lookup_1_free_args(xdrargs);
free(xdrargs);
if (!encode_res(xdr_autofs_lookupres, &door_res,
(caddr_t)&lookup_res, &res_size)) {
syslog(LOG_ERR,
"error allocating lookup results buffer");
failed_res.res_status = EINVAL;
failed_res.xdr_len = 0;
res = (caddr_t)&failed_res;
} else {
door_res->res_status = 0;
res = (caddr_t)door_res;
}
break;
case AUTOFS_MNTINFO:
if (error = decode_args(xdr_autofs_lookupargs,
(autofs_door_args_t *)argp, (caddr_t *)&xdrargs,
sizeof (autofs_lookupargs))) {
syslog(LOG_ERR,
"error allocating lookup arguments buffer");
failed_res.res_status = error;
failed_res.xdr_len = 0;
res = (caddr_t)&failed_res;
res_size = 0;
break;
}
autofs_mntinfo_1_r((autofs_lookupargs *)xdrargs, &mount_res);
autofs_lookup_1_free_args(xdrargs);
free(xdrargs);
/*
* Only reason we would get a NULL res is because
* we could not allocate a results buffer. Use
* a local one to return the error EAGAIN as has
* always been done when memory allocations fail.
*/
if (!encode_res(xdr_autofs_mountres, &door_res,
(caddr_t)&mount_res, &res_size)) {
syslog(LOG_ERR,
"error allocating mount results buffer");
failed_res.res_status = EAGAIN;
failed_res.xdr_len = 0;
res = (caddr_t)&failed_res;
} else {
door_res->res_status = 0;
res = (caddr_t)door_res;
}
autofs_mount_1_free_r(&mount_res);
break;
case AUTOFS_UNMOUNT:
if (error = decode_args(xdr_umntrequest,
(autofs_door_args_t *)argp,
(caddr_t *)&umnt_args, sizeof (umntrequest))) {
syslog(LOG_ERR,
"error allocating unmount argument buffer");
failed_res.res_status = error;
failed_res.xdr_len = 0;
res = (caddr_t)&failed_res;
res_size = sizeof (autofs_door_res_t);
break;
}
autofs_unmount_1_r(umnt_args, &umount_res);
error = umount_res.status;
autofs_unmount_1_free_args(umnt_args);
free(umnt_args);
if (!encode_res(xdr_umntres, &door_res, (caddr_t)&umount_res,
&res_size)) {
syslog(LOG_ERR,
"error allocating unmount results buffer");
failed_res.res_status = EINVAL;
failed_res.xdr_len = 0;
res = (caddr_t)&failed_res;
res_size = sizeof (autofs_door_res_t);
} else {
door_res->res_status = 0;
res = (caddr_t)door_res;
}
break;
case AUTOFS_READDIR:
if (error = decode_args(xdr_autofs_rddirargs,
(autofs_door_args_t *)argp,
(caddr_t *)&rddir_args,
sizeof (autofs_rddirargs))) {
syslog(LOG_ERR,
"error allocating readdir argument buffer");
failed_res.res_status = error;
failed_res.xdr_len = 0;
res = (caddr_t)&failed_res;
res_size = sizeof (autofs_door_res_t);
break;
}
autofs_readdir_1_r(rddir_args, &rddir_res);
free(rddir_args->rda_map);
free(rddir_args);
if (!encode_res(xdr_autofs_rddirres, &door_res,
(caddr_t)&rddir_res, &res_size)) {
syslog(LOG_ERR,
"error allocating readdir results buffer");
failed_res.res_status = ENOMEM;
failed_res.xdr_len = 0;
res = (caddr_t)&failed_res;
res_size = sizeof (autofs_door_res_t);
} else {
door_res->res_status = 0;
res = (caddr_t)door_res;
}
autofs_readdir_1_free_r(&rddir_res);
break;
#ifdef MALLOC_DEBUG
case AUTOFS_DUMP_DEBUG:
check_leaks("/var/tmp/automountd.leak");
error = door_return(NULL, 0, NULL, 0);
/*
* If we got here, door_return() failed
*/
syslog(LOG_ERR, "dump debug door_return failure %d",
error);
return;
#endif
case NULLPROC:
res = NULL;
res_size = 0;
break;
default:
failed_res.res_status = EINVAL;
res = (char *)&failed_res;
res_size = sizeof (autofs_door_res_t);
break;
}
srsz = res_size;
errno = 0;
error = door_return(res, res_size, NULL, 0);
if (errno == E2BIG) {
/*
* Failed due to encoded results being bigger than the
* kernel expected bufsize. Passing actual results size
* back down to kernel.
*/
failed_res.res_status = EOVERFLOW;
failed_res.xdr_len = srsz;
res = (caddr_t)&failed_res;
res_size = sizeof (autofs_door_res_t);
} else {
syslog(LOG_ERR, "door_return failed %d, buffer %p, "
"buffer size %d", error, (void *)res, res_size);
res = NULL;
res_size = 0;
}
(void) door_return(res, res_size, NULL, 0);
/* NOTREACHED */
}
static int
start_autofs_svcs(void)
{
int doorfd;
#ifdef DEBUG
int dfd;
#endif
if ((doorfd = door_create(autofs_doorfunc, NULL,
DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
syslog(LOG_ERR, gettext("Unable to create door\n"));
return (1);
}
#ifdef DEBUG
/*
* Create a file system path for the door
*/
if ((dfd = open(AUTOFS_DOOR, O_RDWR|O_CREAT|O_TRUNC,
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
syslog(LOG_ERR, "Unable to open %s: %m\n", AUTOFS_DOOR);
(void) close(doorfd);
return (1);
}
/*
* stale associations clean up
*/
(void) fdetach(AUTOFS_DOOR);
/*
* Register in the namespace to the kernel to door_ki_open.
*/
if (fattach(doorfd, AUTOFS_DOOR) == -1) {
syslog(LOG_ERR, "Unable to fattach door %m\n", AUTOFS_DOOR);
(void) close(dfd);
(void) close(doorfd);
return (1);
}
#endif /* DEBUG */
/*
* Pass door name to kernel for door_ki_open
*/
autofs_setdoor(doorfd);
(void) thr_keycreate(&s_thr_key, NULL);
/*
* Wait for incoming calls
*/
/*CONSTCOND*/
while (1)
(void) pause();
/* NOTREACHED */
syslog(LOG_ERR, gettext("Door server exited"));
return (10);
}
static int
decode_args(
xdrproc_t xdrfunc,
autofs_door_args_t *argp,
caddr_t *xdrargs,
int size)
{
XDR xdrs;
caddr_t tmpargs = (caddr_t)&((autofs_door_args_t *)argp)->xdr_arg;
size_t arg_size = ((autofs_door_args_t *)argp)->xdr_len;
xdrmem_create(&xdrs, tmpargs, arg_size, XDR_DECODE);
*xdrargs = malloc(size);
if (*xdrargs == NULL) {
syslog(LOG_ERR, "error allocating arguments buffer");
return (ENOMEM);
}
bzero(*xdrargs, size);
if (!(*xdrfunc)(&xdrs, *xdrargs)) {
free(*xdrargs);
*xdrargs = NULL;
syslog(LOG_ERR, "error decoding arguments");
return (EINVAL);
}
return (0);
}
static bool_t
encode_res(
xdrproc_t xdrfunc,
autofs_door_res_t **results,
caddr_t resp,
int *size)
{
XDR xdrs;
*size = xdr_sizeof((*xdrfunc), resp);
*results = autofs_get_buffer(
sizeof (autofs_door_res_t) + *size);
if (*results == NULL) {
(*results)->res_status = ENOMEM;
return (FALSE);
}
(*results)->xdr_len = *size;
*size = sizeof (autofs_door_res_t) + (*results)->xdr_len;
xdrmem_create(&xdrs, (caddr_t)((*results)->xdr_res),
(*results)->xdr_len, XDR_ENCODE);
if (!(*xdrfunc)(&xdrs, resp)) {
(*results)->res_status = EINVAL;
syslog(LOG_ERR, "error encoding results");
return (FALSE);
}
(*results)->res_status = 0;
return (TRUE);
}
static void
automountd_wait_for_cleanup(pid_t pid)
{
int status;
int child_exitval;
/*
* Wait for the main automountd process to exit so we cleanup
*/
(void) waitpid(pid, &status, 0);
child_exitval = WEXITSTATUS(status);
/*
* Shutdown the door server for mounting and unmounting
* filesystems
*/
if (door_revoke(did_fork_exec) == -1) {
syslog(LOG_ERR, "failed to door_revoke(%d) %m", did_fork_exec);
}
if (door_revoke(did_exec_map) == -1) {
syslog(LOG_ERR, "failed to door_revoke(%d) %m", did_exec_map);
}
exit(child_exitval);
}