sm_svc.c revision 1160694128cd3980cc06abe31af529a887efd310
/*
* 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 */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <ftw.h>
#include <signal.h>
#include <string.h>
#include <syslog.h>
#include <netconfig.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/resource.h>
#include <dirent.h>
#include <errno.h>
#include <rpcsvc/sm_inter.h>
#include <rpcsvc/nsm_addr.h>
#include <thread.h>
#include <synch.h>
#include <limits.h>
#include <rpcsvc/daemon_utils.h>
#include <priv_utils.h>
#include "sm_statd.h"
#define home1 "statmon"
/*
* User and group IDs to run as. These are hardwired, rather than looked
* up at runtime, because they are very unlikely to change and because they
* provide some protection against bogus changes to the passwd and group
* files.
*/
static char statd_home[MAXPATHLEN];
int debug;
int regfiles_only = 0; /* 1 => use symlinks in statmon, 0 => don't */
char hostname[MAXHOSTNAMELEN];
/*
* These variables will be used to store all the
* alias names for the host, as well as the -a
* command line hostnames.
*/
int host_name_count;
char **host_name; /* store -a opts */
int addrix; /* # of -a entries */
/*
* The following 2 variables are meaningful
* only under a HA configuration.
* The path_name array is dynamically allocated in main() during
* command line argument processing for the -p options.
*/
int pathix = 0; /* # of -p entries */
/* Global variables. Refer to sm_statd.h for description */
int die;
int in_crash;
/* forward references */
static void set_statmon_owner(void);
static void copy_client_names(void);
static void one_statmon_owner(const char *);
/*
* statd protocol
* commands:
* SM_STAT
* returns stat_fail to caller
* SM_MON
* adds an entry to the monitor_q and the record_q
* This message is sent by the server lockd to the server
* statd, to indicate that a new client is to be monitored.
* It is also sent by the server lockd to the client statd
* to indicate that a new server is to be monitored.
* SM_UNMON
* removes an entry from the monitor_q and the record_q
* SM_UNMON_ALL
* removes all entries from a particular host from the
* monitor_q and the record_q. Our statd has this
* disabled.
* SM_SIMU_CRASH
* simulate a crash. removes everything from the
* record_q and the recovery_q, then calls statd_init()
* to restart things. This message is sent by the server
* lockd to the server statd to have all clients notified
* that they should reclaim locks.
* SM_NOTIFY
* Sent by statd on server to statd on client during
* crash recovery. The client statd passes the info
* to its lockd so it can attempt to reclaim the locks
* held on the server.
*
* There are three main hash tables used to keep track of things.
* mon_table
* table that keeps track hosts statd must watch. If one of
* these hosts crashes, then any locks held by that host must
* be released.
* record_table
* used to keep track of all the hostname files stored in
* are holding or have held a lock at some point. Needed
* to determine if a file needs to be created for host in
* recov_q
* used to keep track hostnames during a recovery
*
* The entries are hashed based upon the name.
*
* for each host that is holding (or has held) a lock. This is
* used during initialization on startup, or after a simulated
* crash.
*/
static void
{
union {
struct sm_name sm_stat_1_arg;
struct mon sm_mon_1_arg;
struct mon_id sm_unmon_1_arg;
struct my_id sm_unmon_all_1_arg;
} argument;
union {
} result;
char *(*local)();
/*
* Dispatch according to which protocol is being used:
* NSM_ADDR_PROGRAM is the private lockd address
* registration protocol.
* SM_PROG is the normal statd (NSM) protocol.
*/
case NULLPROC:
return;
case NSMADDRPROC1_REG:
local = (char *(*)()) nsmaddrproc1_reg;
break;
default:
return;
}
} else {
case NULLPROC:
return;
case SM_STAT:
break;
case SM_MON:
break;
case SM_UNMON:
break;
case SM_UNMON_ALL:
local = (char *(*)()) sm_unmon_all;
break;
case SM_SIMU_CRASH:
local = (char *(*)()) sm_simu_crash;
break;
case SM_NOTIFY:
break;
default:
return;
}
}
return;
}
}
}
}
/*
* Remove all files under directory path_dir.
*/
static int
char *path_dir;
{
char tmp_path[MAXPATHLEN];
if (debug)
"warning: open directory %s failed: %m\n", path_dir);
return (1);
}
return (1);
}
MAXPATHLEN) {
"statd: remove dir %s/%s failed. Pathname too long.\n",
continue;
}
}
}
return (0);
}
/*
* Copy all files from directory `from_dir' to directory `to_dir'.
* Symlinks, if any, are preserved.
*/
void
char *from_dir;
char *to_dir;
{
int n;
if (debug)
"warning: open directory %s failed: %m\n", from_dir);
return;
}
return;
}
continue;
}
if (is_symlink(path)) {
/*
* Follow the link to get the referenced file name
* and make a new link for that file in to_dir.
*/
if (n <= 0) {
if (debug >= 2) {
(void) printf(
"copydir_from_to: can't read link %s\n",
path);
}
continue;
}
rname[n] = '\0';
} else {
/*
* Simply copy regular files to to_dir.
*/
(void) create_file(path);
}
}
}
static int
init_hostname(void)
{
int sock;
return (-1);
}
lifn.lifn_flags = 0;
"statd:init_hostname, get number of interfaces, error: %m");
return (-1);
}
perror("statd -a can't get ip configuration\n");
return (-1);
}
return (0);
}
int
{
int c;
int ppid;
extern char *optarg;
int choice = 0;
int mode;
int sz;
int connmaxrec = RPC_MAXDATASIZE;
addrix = 0;
pathix = 0;
if (init_hostname() < 0)
exit(1);
switch (c) {
case 'd':
break;
case 'D':
choice = 1;
break;
case 'a':
if (addrix < host_name_count) {
if (sz < MAXHOSTNAMELEN) {
NULL) {
addrix++;
}
} else
"statd: -a name of host is too long.\n");
}
} else
"statd: -a exceeding maximum hostnames\n");
break;
case 'p':
/* If the path_name array has not yet */
/* been malloc'ed, do that. The array */
/* should be big enough to hold all of the */
/* -p options we might have. An upper */
/* bound on the number of -p options is */
/* argc/2, because each -p option consumes */
/* two arguments. Here the upper bound */
/* is supposing that all the command line */
/* arguments are -p options, which would */
/* actually never be the case. */
"statd: malloc failed\n");
exit(1);
}
}
pathix++;
} else {
"statd: -p pathname is too long.\n");
}
break;
case 'r':
regfiles_only = 1;
break;
default:
"statd [-d level] [-D]\n");
return (1);
}
if (choice == 0) {
} else {
}
if (debug)
(void) printf("debug is on, create entry: %s, %s, %s\n",
(void) printf("statd: getrlimit failed. \n");
/* Set maxfdlimit current soft limit */
MAX_FDS);
if (!debug) {
if (ppid == -1) {
abort();
}
if (ppid != 0) {
exit(0);
}
closefrom(0);
(void) dup(1);
(void) setsid();
}
/*
* 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 (ppid) {
case 0:
break;
case -1:
exit(2);
default:
/* daemon was already running */
exit(0);
}
/* Get other aliases from each interface. */
merge_hosts();
/*
* Set to automatic mode such that threads are automatically
* created
*/
"statd:unable to set automatic MT mode.");
exit(1);
}
/*
* Set non-blocking mode and maximum record size for
* connection oriented RPC transports.
*/
}
"statd: unable to create (SM_PROG, SM_VERS) for netpath.");
exit(1);
}
"statd: unable to create (NSM_ADDR_PROGRAM, NSM_ADDR_V1) for netpath.");
}
/*
* directories exist and are owned by daemon. Then change our uid
* to daemon. The uid change is to prevent attacks against local
* daemons that trust any call from a local root process.
*/
/*
*
* statd now runs as a daemon rather than root and can not
* dump core under / because of the permission. It is
* important that current working directory of statd be
* can dump the core upon the receipt of the signal.
* One still need to set allow_setid_core to non-zero in
*
*/
if (chdir(statd_home) < 0) {
exit(1);
}
sm_inithash();
die = 0;
/*
* This variable is set to ensure that an sm_crash
* request will not be done at the same time
* when a statd_init is being done, since sm_crash
* can reset some variables that statd_init will be using.
*/
in_crash = 1;
statd_init();
if (debug)
(void) printf("Starting svc_run\n");
svc_run();
/* NOTREACHED */
thr_exit((void *) 1);
return (0);
}
/*
* Make sure the ownership of the statmon directories is correct, then
* arguments) don't exist, they are created first. The sm and sm.bak
* directories are not created here, but if they already exist, they are
* chowned to the correct uid, along with anything else in the
* directories.
*/
static void
{
int i;
/*
* creating them if necessary.
*/
for (i = 0; i < pathix; i++) {
char alt_path[MAXPATHLEN];
}
exit(1);
}
}
/*
* Copy client names from the alternate statmon directories into
* exist, though the sm and sm.bak directories might not.
*/
static void
{
int i;
/*
* Remove the files in alternate directory when copying is done.
*/
for (i = 0; i < pathix; i++) {
/*
* If the alternate directories do not exist, create it.
* If they do exist, just do the copy.
*/
"can't mkdir %s: %m\n", buf);
continue;
}
(void) remove_dir(buf);
}
path_name[i]);
"can't mkdir %s: %m\n", buf);
continue;
}
(void) remove_dir(buf);
}
}
}
/*
* Create the given directory if it doesn't already exist. Set the user
* and group to daemon for the directory and anything under it.
*/
static void
one_statmon_owner(const char *dir)
{
dir);
return;
}
}
if (debug)
dir);
}
}
/*
* Set the user and group to daemon for the given file or directory. If
* it's a directory, also makes sure that it is mode 755.
* Generates a syslog message but does not return an error if there were
* problems.
*/
/*ARGSUSED3*/
static int
{
return (0);
/*
* Some older systems might have mode 777 directories. Fix that.
*/
if (debug)
if (debug)
}
}
/* If already owned by daemon, don't bother changing. */
return (0);
if (debug)
path);
if (debug)
}
return (0);
}