vold_main.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Portions of this source code were derived from Berkeley 4.3 BSD
* under license from the Regents of the University of California.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <rpcsvc/nfs_prot.h>
#include <sys/resource.h>
#include <netdb.h>
#include <netdir.h>
#include <locale.h>
#include <ulimit.h>
#include <ucontext.h>
#include <pwd.h>
#include <grp.h>
#include <sys/systeminfo.h>
#include <thread.h>
#include <synch.h>
#include <stropts.h>
#include <zone.h>
#include <libscf.h>
#include "vold.h"
/* extern vars */
extern int trace; /* nfs server trace enable */
extern int vol_fd;
/* extern prototypes */
extern int __rpc_negotiate_uid(int fd);
/* local prototypes */
static struct netconfig *trans_loopback(void);
static void catch(void);
static void catch_n_exit(int);
static void catch_n_return(int);
void reread_config(int);
static void usage(void);
static void vold_run(void);
/* global vars */
int verbose = DEFAULT_VERBOSE;
int debug_level = DEFAULT_DEBUG;
char *vold_root = DEFAULT_VOLD_ROOT;
char *vold_config = DEFAULT_VOLD_CONFIG;
char *vold_devdir = DEFAULT_VOLD_DEVDIR;
char *volume_group = DEFAULT_VOLUME_GROUP;
char *nisplus_group = DEFAULT_NISPLUS_GROUP;
int never_writeback = 0;
char self[MAXHOSTNAMELEN];
struct timeval current_time;
int vold_running = 0;
/* local vars */
static int vold_polltime = DEFAULT_POLLTIME;
static char *prog_name;
static int mount_timeout = 30;
static int reread_config_file = 0;
static int event_notify_pipe[2];
#define MAXPOLLFD 5
void
{
extern bool_t config_read(void);
extern int sysevent_init(void);
struct knetconfig knconf;
int c;
int set_my_log = 0;
int rpc_fd;
char *buf;
char mntopts[MAX_MNTOPT_STR];
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
if (getzoneid() != GLOBAL_ZONEID) {
}
/* argument processing */
switch (c) {
case 'v':
verbose++;
break;
case 't':
trace++;
break;
case 'f':
vold_config = (char *)optarg;
break;
case 'd':
break;
case 'o':
vold_devdir = (char *)optarg;
break;
case 'g':
volume_group = (char *)optarg;
break;
case 'G':
nisplus_group = (char *)optarg;
break;
case 'l':
set_my_log = 1;
break;
case 'L':
break;
case 'n':
never_writeback = 1;
break;
case 'P':
break;
default:
usage();
/*NOTREACHED*/
}
}
if (set_my_log == 0)
(void) umask(0);
/*
* XXLP: This really should be removed and work done to work out
* what privileges vold actually needs. This could be problematic
* with vold because of the pluggable action system. However this
* is done via rmmount in a child process so at least the main vold
* process can probably run with fewer privileges even if it needs
* a full inheritable set to pass on to rmmount.
*/
if (geteuid() != 0) {
}
/*
* Increase file descriptor limit to the most it can possibly
* be.
*/
fatal("getrlimit for fd's failed; %m\n");
}
fatal("setrlimit for fd's failed; %m\n");
}
}
}
"vol_init failed (can't communicate with kernel)\n"));
/*NOTREACHED*/
}
/* read in the config file */
if (!config_read()) {
}
nconf = trans_loopback();
/*NOTREACHED*/
}
/*NOTREACHED*/
}
/*
* Negotiate for returning the uid of the caller.
* This should be done before enabling the endpoint for
* service via t_bind() (called in svc_tli_create())
* so that requests to vold contain the uid.
*/
if (__rpc_negotiate_uid(rpc_fd) != 0) {
"Couldn't negotiate for uid with loopback transport %s\n"),
/* NOT REACHED */
}
/*LINTED alignment ok*/
/*NOTREACHED*/
}
gettext("svc_tli_create: Cannot create server handle\n"));
/*NOTREACHED*/
}
(struct netconfig *)0)) {
/*NOTREACHED*/
}
}
/*
* create signal notify pipe.
*/
if (pipe(event_notify_pipe) < 0) {
/*NOTREACHED*/
}
/*
* ensure the root node is set up before using it
*
* XXX: the only case that this seems to apply to is the one where
* no floppy or CD-ROM (or otherwise normal device) is present,
* but the pcmem forcload=TRUE option has loaded the dev_pcmem
* DSO (see bug id# 1244293)
*/
db_root(); /* funky but true */
}
/*
* Fork vold
* For debugging, the sense of this is backwards -- here we fork
* the mount half rather than the work half (so we can use dbx
* easily).
*/
if (mount_pid == -1) {
/*NOTREACHED*/
} else if (mount_pid == 0) {
/* child */
/*
* NFSMNT_NOAC flag needs to be turned off when NFS client
* side bugid 1110389 is fixed.
*
* NOTE: as of s494-ea, the NFSMNT_NOAC flag can NOT
* be used, as it doesn't seem to be fully implemented.
*
* 10/14/94: symlinks seem to be hosed in 2.4 (NFS seems to
* be caching READLINKs, so on goes NFSMNT_NOAC again
* (see bug id# 1179769) -- also, 1110389 has long-since
* been fixed.
*/
/*NOTREACHED*/
}
/*
* Check to see mount point is there...
*/
"can't make directory \"%s\"; %m\n"),
}
} else {
/*NOTREACHED*/
}
/* ...and that it's a directory. */
/*NOTREACHED*/
}
/*
*/
buf = vold_malloc(c);
/*
* mount "/vol" -- this will block until our parent
* actually services this request
*/
} else {
}
exit(1);
/*NOTREACHED*/
}
exit(0);
/*NOTREACHED*/
}
/* parent */
(void) setsid();
/* set up our signal handlers */
/*
* The SIGHUP handler provides a mechanism
* for changing vold's map of the system's
* removable media devices when either vold's
* configuration file changes or the system's
* removable media device configuration changes.
*
* We also register with sysventd to receive notification
* of new devices being added.
*/
/*
* tell vol driver about where our root is
*/
/*NOTREACHED*/
}
(void) sysevent_init();
/* do the real work */
vold_run();
/*NOTREACHED*/
}
/*
* Get a netconfig entry for loopback transport
*/
static struct netconfig *
trans_loopback(void)
{
nc = setnetconfig();
return (NULL);
break;
}
}
return (nconf);
}
static void
{
struct nd_hostserv nd_hostserv;
struct nd_addrlist *nas;
} else {
/*NOTREACHED*/
}
}
static int
wait_mount(void)
{
int stat;
/*
* the child we forked to do the mount() may not be
* done yet, so wait until it is
*/
} else {
/*NOTREACHED*/
}
}
return (comp);
}
/*
* main loop for the volume daemon.
*/
/*
* egad... what a clever... well...
* The problem is that it's impossible to write a fully MT program
* at this time because several of the libraries that I depend on
* (e.g. the rpc library) are not MT safe. So, we suffer from a
* very partial MT job. The main significance here is that poll(2)
* relies on SIGCHLD to kick us out of a system call. It's much more
* efficient (in terms of wall clock time) to do this than just
* poll for some number of seconds.
*/
static void
vold_run(void)
{
extern void svc_getreq_common(const int);
extern void vol_readevents(void);
extern int vol_async(void);
extern bool_t config_read(void);
int n, i, fd;
int action_in_progress = 0;
int rpc_fd;
for (i = 0; i < svc_max_pollfd; i++) {
if (svc_pollfd[i].fd >= 0) {
rpc_fd = i;
break;
}
}
/* let the threads GO */
if (vold_running == 0) {
(void) mutex_lock(&running_mutex);
vold_running = 1;
(void) cond_broadcast(&running_cv);
(void) mutex_unlock(&running_mutex);
}
npollfd++;
npollfd++;
npollfd++;
/* handle events forever */
for (;;) {
/* wait until something happens */
n, errno);
/* update idea of the "now" */
/*
* We need to serialize:
* 1) svc_getreq_common - it will touch devmap.
* 2) vol_readevents - touch a lot of shared data.
* 3) vol_async - dev_eject changes node data.
* 4) config_read - anything should not be working.
*/
(void) mutex_lock(&vold_main_mutex);
/*
* Is there work to do?
*/
if (n > 0) {
/* there is work to do -- look at each possible fd */
for (i = 0; n != 0 && i < npollfd; i++) {
continue;
/* this is an NFS event */
/* this is a volctl event */
/* this is a signal event */
}
n--;
}
} else if (n < 0) {
/* poll() had an error */
} else {
debug(10,
"vold_run: poll failed (errno %d)\n",
errno);
}
/* cleaup the signal notify pipe. */
}
if (mount_complete) {
/*
* don't want to process async tasks (such as
* media insertion) until the NFS server is ready
* to handle request
*/
} else {
/*
* mount completed. we need to check pending
* event which was delivered while waiting
* for the child. Otherwise, events won't be
* processed until poll returns.
*/
}
}
/*
* should reconfig after vol_async() was called. Otherwise,
* new action may be invoked by vol_readevents, and may be
* running while reconfiguring.
*/
if (!action_in_progress && reread_config_file) {
/*
* Either vold's configuration file
* has changed or the actual removable
* media device configuration has changed.
*/
reread_config_file = 0;
(void) config_read();
}
(void) mutex_unlock(&vold_main_mutex);
}
/*NOTREACHED*/
}
static void
usage(void)
{
gettext("\t[-v]\t\tverbose status information\n"));
gettext("\t[-t]\t\tunfs server trace information\n"));
gettext("\t[-d directory]\talternate /vol directory\n"));
gettext("\t[-l logfile]\tplace to put log messages\n"));
gettext("\t[-L loglevel]\tlevel of debug information\n"));
exit(1);
}
void
catch(void)
{
extern int umount_all(char *);
int err;
if (childpid < 0) {
} else if (childpid == 0) {
/* in child */
} else {
}
} else {
/* in parent */
childpid);
childpid);
} else {
childpid);
}
}
}
/*
* Exit from the thread.
*/
/*ARGSUSED*/
static void
catch_n_exit(int sig)
{
extern void flushlog(void);
extern void sysevent_fini(void);
flushlog();
if (thr_self() > 1) {
}
(void) sysevent_fini();
exit(0);
}
/*
* don't do anything but write one byte to pipe, so that poll()
* never get stuck.
*/
/*ARGSUSED*/
void
catch_n_return(int sig)
{
vold_run_run();
}
/*
* Signal to reread the configuration file
*/
/*ARGSUSED*/
void
reread_config(int sig)
{
reread_config_file = 1;
vold_run_run();
}
void
vold_run_run(void)
{
char c = 0;
}