autod_main.c revision ace1a5f11236a072fca1b5e0ea1416a083a9f2aa
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
* 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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.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 <rpcsvc/nfs_prot.h>
#include <netdir.h>
#include <string.h>
#include <thread.h>
#include <locale.h>
#include "automount.h"
#include <rpcsvc/daemon_utils.h>
#include <deflt.h>
#include <strings.h>
static void autofs_mount_1_r(struct autofs_lookupargs *,
struct autofs_mountres *, struct authunix_parms *);
static void autofs_mount_1_free_r(struct autofs_mountres *);
static void autofs_lookup_1_r(struct autofs_lookupargs *,
struct autofs_lookupres *, struct authunix_parms *);
static void autofs_lookup_1_free_r(struct autofs_lookupres *);
struct authunix_parms *);
static void autofs_unmount_1_free_r(struct umntres *);
static void autofs_readdir_1_r(struct autofs_rddirargs *,
struct autofs_rddirres *, struct authunix_parms *);
static void autofs_readdir_1_free_r(struct autofs_rddirres *);
static void usage();
static void warn_hup(int);
static void free_action_list();
void (*)());
void (*)());
#define CTIME_BUF_LEN 26
/*
* XXX - this limit was imposed due to resource problems - even though
* we can and do try and set the rlimit to be able to handle more threads,
* fopen() doesn't allow more than 256 fp's.
*/
#define MAXTHREADS 64
#define RESOURCE_FACTOR 8
static char str_arch[32];
static char str_cpu[32];
char self[64];
int verbose = 0;
int trace = 0;
int automountd_nobrowse = 0;
int
int argc;
char *argv[];
{
int c, i, error;
int rpc_svc_mode = RPC_SVC_MT_AUTO;
int maxthreads = MAXTHREADS;
int prevthreads = 0;
char *defval;
int defflags;
if (geteuid() != 0) {
exit(1);
}
/*
* Read in the values from config file first before we check
* commandline options so the options override the file.
*/
if ((defopen(AUTOFSADMIN)) == 0) {
else
}
else
}
errno = 0;
if (errno != 0)
trace = 0;
}
}
/* close defaults file */
}
switch (c) {
case 'v':
verbose++;
break;
case 'n':
break;
case 'T':
trace++;
break;
case 'D':
break;
default:
usage();
}
}
"automountd: can't determine hostname, error: %d\n",
error);
exit(1);
}
#ifndef DEBUG
if (pid < 0) {
perror("cannot fork");
exit(1);
}
if (pid)
exit(0);
#endif
(void) setsid();
/*
* Since the "arch" command no longer exists we
* have to rely on sysinfo(SI_MACHINE) to return the closest
* approximation. For backward compatibility we
* need to substitute "sun4" for "sun4m", "sun4c", ...
*/
char buf[16];
} else {
"can't determine machine type, error: %m");
}
}
char buf[16];
} else {
"can't determine processor type, error: %m");
}
}
/*
* initialize the name services, use NULL arguments to ensure
* we don't initialize the stack of files used in file service
*/
/*
* set the maximum number of threads to be used. If it succeeds
* increase the number of resources the threads need. If the
* the resource allocation fails, return the threads value back
* to the default value
*/
"unable to increase system resource limit");
/* back off changes to threads */
== FALSE) {
/*
* Exit if we have more threads than resources.
*/
"unable to match threads to system resources");
exit(1);
}
"decreased threads to match low resources");
} else {
/*
* Both are successful. Note that setrlimit
* allows a max setting of 1024
*/
if (trace > 3) {
trace_prt(1,
" maxthreads: %d rlim_max: %d rlim_cur: %d\n",
}
closefrom(3);
}
} else {
"unable to increase threads - continue with default");
}
/*
* 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
*/
switch (pid) {
case 0:
break;
case -1:
exit(2);
default:
/* daemon was already running */
exit(0);
}
/*
* If we coredump it'll be /core.
*/
if (chdir("/") < 0)
/*
* Create cache_cleanup thread
*/
exit(1);
}
/* other initializations */
exit(1);
}
exit(1);
}
svc_run();
return (1);
}
/*
* The old automounter supported a SIGHUP
* to allow it to resynchronize internal
* This is no longer relevant, but we
* need to catch the signal and warn
* the user.
*/
/* ARGSUSED */
static void
warn_hup(i)
int i;
{
}
static void
usage()
{
"\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 */
}
/*
* dupreq_nonidemp(struct svc_req *rqstp, SVCXPRT *transp, int res_sz,
* bool_t (*xdr_result)(), void (*local_free)())
* check the status of nonidempotent requests in the duplicate request cache.
* Get result of done requests and send a reply to the kernel. Return status.
*/
static int
{
int dupstat;
switch (dupstat) {
case DUP_NEW:
break;
case DUP_DONE:
if (!resp_buf) {
if (verbose) {
"dupreq_nonidemp: done, no cached result");
}
break;
}
/* buffer contains xdr encoded results - decode and sendreply */
if (verbose) {
"dupreq_nonidemp: done, send reply to kernel");
}
xdr_destroy(&xdrs);
break;
}
if (verbose)
"dupreq_nonidemp: cannot xdr decode result");
xdr_destroy(&xdrs);
break;
}
xdr_destroy(&xdrs);
(void) (*local_free)(res);
return (DUP_ERROR);
}
xdr_destroy(&xdrs);
(void) (*local_free)(res);
break;
/* all other cases log the case and drop the request */
case DUP_INPROGRESS:
if (verbose) {
"dupreq_nonidemp: duplicate request in progress\n");
}
break;
case DUP_DROP: /* should never be called in automountd */
if (verbose)
"dupreq_nonidemp: dropped duplicate request error");
break;
case DUP_ERROR: /* fall through */
default:
if (verbose)
"dupreq_nonidemp: duplicate request cache error");
break;
}
return (dupstat);
}
/*
* dupdonereq_nonidemp(struct svc_req *rqstp, caddr_t res,
* bool_t (*xdr_result)())
* call the cache to indicate we are done with the nonidempotent request.
* xdr_result will write the encoded xdr form of results into the buffer
* provided in xdrmem_create. Makes a best effort to update the cache
* first with a buffer containing the results, and then with a NULL buffer.
* Return status.
*/
static int
{
int dupstat;
/*
* create a results buffer and write into the cache
* continue with a NULL buffer on errors.
*/
if (verbose)
resp_bufsz = 0;
} else {
resp_bufsz = 0;
} else {
if (verbose)
"cannot xdr encode results");
xdr_destroy(&xdrs);
resp_bufsz = 0;
} else
xdr_destroy(&xdrs);
}
}
DUP_DONE);
if (verbose)
if (verbose)
"dupdonereq_nonidemp: retry failed");
}
}
if (resp_buf)
return (dupstat);
}
/*
* dupreq_idemp(struct svc_req *rqstp, SVCXPRT *transp, int res_sz;
* bool_t (*xdr_result)(), void (*local_free)())
* check the status of idempotent requests in the duplicate request cache.
* treat a idempotent request like a new one if its done, but do workavoids
* if its a request in progress. Return status.
*/
static int
{
int dupstat;
#ifdef lint
#endif /* lint */
/*
* call the cache to check the status of the request. don't care
* about results in the cache.
*/
switch (dupstat) {
case DUP_NEW:
break;
case DUP_DONE:
if (verbose)
break;
/* all other cases log the case and drop the request */
case DUP_INPROGRESS:
if (verbose)
"dupreq_idemp: duplicate request in progress\n");
break;
case DUP_DROP: /* should never be called in automountd */
if (verbose)
"dupreq_idemp: dropped duplicate request error");
break;
case DUP_ERROR: /* fall through */
default:
if (verbose)
"dupreq_idemp: duplicate request cache error");
break;
}
return (dupstat);
}
/*
* dupdonereq_idemp(struct svc_req *rqstp, caddr_t res, bool_t (*xdr_result)())
* call the cache to indicate we are done with the idempotent request - we do
* this to allow work avoids for in progress requests. don't bother to store
* any results in the cache. Return status.
*/
static int
{
int dupstat;
#ifdef lint
#endif /* lint */
return (dupstat);
}
/*
* Returns the UID of the caller
*/
static uid_t
{
char *err_msg = "Could not get local uid - request ignored\n";
if (trace > 1)
if (verbose)
return (-1);
}
if (uid != 0) {
char *err_msg =
"Illegal access attempt by uid=%ld - request ignored\n";
if (trace > 1)
}
return (uid);
}
/*
* Each RPC request will automatically spawn a new thread with this
* as its entry point.
* XXX - the switch statement should be changed to a table of procedures
* similar to that used by rfs_dispatch() in uts/common/fs/nfs/nfs_server.c.
* duplicate request handling should also be synced with rfs_dispatch().
*/
static void
{
union {
} argument;
union {
} res;
bool_t (*xdr_argument)();
bool_t (*xdr_result)();
void (*local)();
void (*local_free)();
int (*dup_request)();
int (*dupdone_request)();
/*
* Drop request
*/
return;
}
case NULLPROC:
return;
#ifdef MALLOC_DEBUG
case AUTOFS_DUMP_DEBUG:
check_leaks("/var/tmp/automountd.leak");
return;
#endif
case AUTOFS_LOOKUP:
break;
case AUTOFS_MOUNT:
break;
case AUTOFS_UNMOUNT:
break;
case AUTOFS_READDIR:
break;
default:
return;
}
local_free) != DUP_NEW)
return;
return;
}
/* update cache with done request results */
}
}
(*local_free)(&res);
}
static void
struct autofs_rddirargs *req;
struct autofs_rddirres *res;
struct authunix_parms *cred;
{
if (trace > 0)
if (trace > 0)
}
static void
struct autofs_rddirres *res;
{
}
}
/* ARGSUSED */
static void
struct umntrequest *m;
struct authunix_parms *cred;
{
struct umntrequest *ul;
if (trace > 0) {
char ctime_buf[CTIME_BUF_LEN];
ctime_buf[0] = '\0';
" mntopts=%s %s\n",
}
if (trace > 0)
}
static void
{
#ifdef lint
#endif /* lint */
}
static void
struct autofs_lookupargs *m;
struct autofs_lookupres *res;
struct authunix_parms *cred;
{
enum autofs_action action;
int status;
if (trace > 0) {
char ctime_buf[CTIME_BUF_LEN];
ctime_buf[0] = '\0';
}
if (status == 0) {
/*
* Return action list to kernel.
*/
} else {
/*
* Entry not found
*/
}
if (trace > 0)
}
static void
struct autofs_lookupres *res;
{
/*
* Free link information
*/
}
}
static void
struct autofs_lookupargs *m;
struct autofs_mountres *res;
struct authunix_parms *cred;
{
int status;
if (trace > 0) {
char ctime_buf[CTIME_BUF_LEN];
ctime_buf[0] = '\0';
}
if (status != 0) {
/*
* An error occurred, free action list if allocated.
*/
}
}
/*
* Return action list to kernel.
*/
} else {
/*
* No work to do left for the kernel
*/
}
if (trace > 0) {
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:
status);
}
}
if (m->isdirect) {
/* direct mount */
} else {
/* indirect mount */
}
}
}
static void
struct autofs_mountres *res;
{
if (trace > 2)
}
}
/*
* 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
{
const char *p1;
char *p2;
p1++;
} else {
}
}
*p2++ = '\n';
*p2 = '\0';
}
static void
{
case AUTOFS_MOUNT_RQ:
/* LINTED pointer alignment */
break;
case AUTOFS_LINK_RQ:
"non AUTOFS_MOUNT_RQ requests not implemented\n");
break;
default:
"non AUTOFS_MOUNT_RQ requests not implemented\n");
break;
}
free(p);
}
}