xref: /onnv-gate/usr/src/cmd/fs.d/nfs/statd/sm_svc.c (revision 12648:61bf50c7467b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51676Sjpk  * Common Development and Distribution License (the "License").
61676Sjpk  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*12648SSurya.Prakki@Sun.COM  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
260Sstevel@tonic-gate /*	  All Rights Reserved  	*/
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
300Sstevel@tonic-gate  * The Regents of the University of California
310Sstevel@tonic-gate  * All Rights Reserved
320Sstevel@tonic-gate  *
330Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
340Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
350Sstevel@tonic-gate  * contributors.
360Sstevel@tonic-gate  */
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include <stdio.h>
391914Scasper #include <stdio_ext.h>
400Sstevel@tonic-gate #include <stdlib.h>
410Sstevel@tonic-gate #include <ftw.h>
420Sstevel@tonic-gate #include <signal.h>
430Sstevel@tonic-gate #include <string.h>
440Sstevel@tonic-gate #include <syslog.h>
450Sstevel@tonic-gate #include <netconfig.h>
460Sstevel@tonic-gate #include <unistd.h>
470Sstevel@tonic-gate #include <netdb.h>
480Sstevel@tonic-gate #include <rpc/rpc.h>
490Sstevel@tonic-gate #include <netinet/in.h>
500Sstevel@tonic-gate #include <sys/param.h>
510Sstevel@tonic-gate #include <sys/resource.h>
520Sstevel@tonic-gate #include <sys/file.h>
530Sstevel@tonic-gate #include <sys/types.h>
540Sstevel@tonic-gate #include <sys/stat.h>
550Sstevel@tonic-gate #include <sys/sockio.h>
560Sstevel@tonic-gate #include <dirent.h>
570Sstevel@tonic-gate #include <errno.h>
580Sstevel@tonic-gate #include <rpcsvc/sm_inter.h>
590Sstevel@tonic-gate #include <rpcsvc/nsm_addr.h>
600Sstevel@tonic-gate #include <thread.h>
610Sstevel@tonic-gate #include <synch.h>
620Sstevel@tonic-gate #include <net/if.h>
630Sstevel@tonic-gate #include <limits.h>
640Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h>
650Sstevel@tonic-gate #include <priv_utils.h>
660Sstevel@tonic-gate #include "sm_statd.h"
670Sstevel@tonic-gate 
680Sstevel@tonic-gate 
690Sstevel@tonic-gate #define	home0		"/var/statmon"
700Sstevel@tonic-gate #define	current0	"/var/statmon/sm"
710Sstevel@tonic-gate #define	backup0		"/var/statmon/sm.bak"
720Sstevel@tonic-gate #define	state0		"/var/statmon/state"
730Sstevel@tonic-gate 
740Sstevel@tonic-gate #define	home1		"statmon"
750Sstevel@tonic-gate #define	current1	"statmon/sm/"
760Sstevel@tonic-gate #define	backup1		"statmon/sm.bak/"
770Sstevel@tonic-gate #define	state1		"statmon/state"
780Sstevel@tonic-gate 
790Sstevel@tonic-gate /*
800Sstevel@tonic-gate  * User and group IDs to run as.  These are hardwired, rather than looked
810Sstevel@tonic-gate  * up at runtime, because they are very unlikely to change and because they
820Sstevel@tonic-gate  * provide some protection against bogus changes to the passwd and group
830Sstevel@tonic-gate  * files.
840Sstevel@tonic-gate  */
852712Snn35248 uid_t	daemon_uid = DAEMON_UID;
862712Snn35248 gid_t	daemon_gid = DAEMON_GID;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate char STATE[MAXPATHLEN], CURRENT[MAXPATHLEN], BACKUP[MAXPATHLEN];
890Sstevel@tonic-gate static char statd_home[MAXPATHLEN];
900Sstevel@tonic-gate 
910Sstevel@tonic-gate int debug;
920Sstevel@tonic-gate int regfiles_only = 0;		/* 1 => use symlinks in statmon, 0 => don't */
930Sstevel@tonic-gate char hostname[MAXHOSTNAMELEN];
940Sstevel@tonic-gate 
950Sstevel@tonic-gate /*
960Sstevel@tonic-gate  * These variables will be used to store all the
970Sstevel@tonic-gate  * alias names for the host, as well as the -a
980Sstevel@tonic-gate  * command line hostnames.
990Sstevel@tonic-gate  */
1000Sstevel@tonic-gate int host_name_count;
1010Sstevel@tonic-gate char **host_name; /* store -a opts */
1020Sstevel@tonic-gate int  addrix; /* # of -a entries */
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate /*
1060Sstevel@tonic-gate  * The following 2 variables are meaningful
1070Sstevel@tonic-gate  * only under a HA configuration.
1080Sstevel@tonic-gate  * The path_name array is dynamically allocated in main() during
1090Sstevel@tonic-gate  * command line argument processing for the -p options.
1100Sstevel@tonic-gate  */
1110Sstevel@tonic-gate char **path_name = NULL;  /* store -p opts */
1120Sstevel@tonic-gate int  pathix = 0;  /* # of -p entries */
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate /* Global variables.  Refer to sm_statd.h for description */
1150Sstevel@tonic-gate mutex_t crash_lock;
1160Sstevel@tonic-gate int die;
1170Sstevel@tonic-gate int in_crash;
1180Sstevel@tonic-gate cond_t crash_finish;
1190Sstevel@tonic-gate mutex_t sm_trylock;
1200Sstevel@tonic-gate rwlock_t thr_rwlock;
1210Sstevel@tonic-gate cond_t retrywait;
1220Sstevel@tonic-gate mutex_t name_addrlock;
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate /* forward references */
1250Sstevel@tonic-gate static void set_statmon_owner(void);
1260Sstevel@tonic-gate static void copy_client_names(void);
1270Sstevel@tonic-gate static void one_statmon_owner(const char *);
1280Sstevel@tonic-gate static int nftw_owner(const char *, const struct stat *, int, struct FTW *);
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate /*
1310Sstevel@tonic-gate  * statd protocol
1320Sstevel@tonic-gate  * 	commands:
1330Sstevel@tonic-gate  * 		SM_STAT
1340Sstevel@tonic-gate  * 			returns stat_fail to caller
1350Sstevel@tonic-gate  * 		SM_MON
1360Sstevel@tonic-gate  * 			adds an entry to the monitor_q and the record_q
1370Sstevel@tonic-gate  *			This message is sent by the server lockd to the server
1380Sstevel@tonic-gate  *			statd, to indicate that a new client is to be monitored.
1390Sstevel@tonic-gate  *			It is also sent by the server lockd to the client statd
1400Sstevel@tonic-gate  *			to indicate that a new server is to be monitored.
1410Sstevel@tonic-gate  * 		SM_UNMON
1420Sstevel@tonic-gate  * 			removes an entry from the monitor_q and the record_q
1430Sstevel@tonic-gate  * 		SM_UNMON_ALL
1440Sstevel@tonic-gate  * 			removes all entries from a particular host from the
1450Sstevel@tonic-gate  * 			monitor_q and the record_q.  Our statd has this
1460Sstevel@tonic-gate  * 			disabled.
1470Sstevel@tonic-gate  * 		SM_SIMU_CRASH
1480Sstevel@tonic-gate  * 			simulate a crash.  removes everything from the
1490Sstevel@tonic-gate  * 			record_q and the recovery_q, then calls statd_init()
1500Sstevel@tonic-gate  * 			to restart things.  This message is sent by the server
1510Sstevel@tonic-gate  *			lockd to the server statd to have all clients notified
1520Sstevel@tonic-gate  *			that they should reclaim locks.
1530Sstevel@tonic-gate  * 		SM_NOTIFY
1540Sstevel@tonic-gate  *			Sent by statd on server to statd on client during
1550Sstevel@tonic-gate  *			crash recovery.  The client statd passes the info
1560Sstevel@tonic-gate  *			to its lockd so it can attempt to reclaim the locks
1570Sstevel@tonic-gate  *			held on the server.
1580Sstevel@tonic-gate  *
1590Sstevel@tonic-gate  * There are three main hash tables used to keep track of things.
1600Sstevel@tonic-gate  * 	mon_table
1610Sstevel@tonic-gate  * 		table that keeps track hosts statd must watch.  If one of
1620Sstevel@tonic-gate  * 		these hosts crashes, then any locks held by that host must
1630Sstevel@tonic-gate  * 		be released.
1640Sstevel@tonic-gate  * 	record_table
1650Sstevel@tonic-gate  * 		used to keep track of all the hostname files stored in
1660Sstevel@tonic-gate  * 		the directory /var/statmon/sm.  These are client hosts who
1670Sstevel@tonic-gate  *		are holding or have held a lock at some point.  Needed
1680Sstevel@tonic-gate  *		to determine if a file needs to be created for host in
1690Sstevel@tonic-gate  *		/var/statmon/sm.
1700Sstevel@tonic-gate  *	recov_q
1710Sstevel@tonic-gate  *		used to keep track hostnames during a recovery
1720Sstevel@tonic-gate  *
1730Sstevel@tonic-gate  * The entries are hashed based upon the name.
1740Sstevel@tonic-gate  *
1750Sstevel@tonic-gate  * There is a directory /var/statmon/sm which holds a file named
1760Sstevel@tonic-gate  * for each host that is holding (or has held) a lock.  This is
1770Sstevel@tonic-gate  * used during initialization on startup, or after a simulated
1780Sstevel@tonic-gate  * crash.
1790Sstevel@tonic-gate  */
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate static void
sm_prog_1(rqstp,transp)1820Sstevel@tonic-gate sm_prog_1(rqstp, transp)
1830Sstevel@tonic-gate 	struct svc_req *rqstp;
1840Sstevel@tonic-gate 	SVCXPRT *transp;
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate 	union {
1870Sstevel@tonic-gate 		struct sm_name sm_stat_1_arg;
1880Sstevel@tonic-gate 		struct mon sm_mon_1_arg;
1890Sstevel@tonic-gate 		struct mon_id sm_unmon_1_arg;
1900Sstevel@tonic-gate 		struct my_id sm_unmon_all_1_arg;
1910Sstevel@tonic-gate 		struct stat_chge ntf_arg;
1920Sstevel@tonic-gate 		struct reg1args reg1_arg;
1930Sstevel@tonic-gate 	} argument;
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	union {
1960Sstevel@tonic-gate 		sm_stat_res stat_resp;
1970Sstevel@tonic-gate 		sm_stat	mon_resp;
1980Sstevel@tonic-gate 		struct reg1res reg1_resp;
1990Sstevel@tonic-gate 	} result;
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	bool_t (*xdr_argument)(), (*xdr_result)();
2020Sstevel@tonic-gate 	char *(*local)();
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	/*
2050Sstevel@tonic-gate 	 * Dispatch according to which protocol is being used:
2060Sstevel@tonic-gate 	 *	NSM_ADDR_PROGRAM is the private lockd address
2070Sstevel@tonic-gate 	 *		registration protocol.
2080Sstevel@tonic-gate 	 *	SM_PROG is the normal statd (NSM) protocol.
2090Sstevel@tonic-gate 	 */
2100Sstevel@tonic-gate 	if (rqstp->rq_prog == NSM_ADDR_PROGRAM) {
2110Sstevel@tonic-gate 		switch (rqstp->rq_proc) {
2120Sstevel@tonic-gate 		case NULLPROC:
2130Sstevel@tonic-gate 			svc_sendreply(transp, xdr_void, (caddr_t)NULL);
2140Sstevel@tonic-gate 			return;
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 		case NSMADDRPROC1_REG:
2170Sstevel@tonic-gate 			xdr_argument = xdr_reg1args;
2180Sstevel@tonic-gate 			xdr_result = xdr_reg1res;
2190Sstevel@tonic-gate 			local = (char *(*)()) nsmaddrproc1_reg;
2200Sstevel@tonic-gate 			break;
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 		default:
2230Sstevel@tonic-gate 			svcerr_noproc(transp);
2240Sstevel@tonic-gate 			return;
2250Sstevel@tonic-gate 		}
2260Sstevel@tonic-gate 	} else {
2270Sstevel@tonic-gate 		switch (rqstp->rq_proc) {
2280Sstevel@tonic-gate 		case NULLPROC:
2290Sstevel@tonic-gate 			svc_sendreply(transp, xdr_void, (caddr_t)NULL);
2300Sstevel@tonic-gate 			return;
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 		case SM_STAT:
2330Sstevel@tonic-gate 			xdr_argument = xdr_sm_name;
2340Sstevel@tonic-gate 			xdr_result = xdr_sm_stat_res;
2350Sstevel@tonic-gate 			local = (char *(*)()) sm_status;
2360Sstevel@tonic-gate 			break;
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 		case SM_MON:
2390Sstevel@tonic-gate 			xdr_argument = xdr_mon;
2400Sstevel@tonic-gate 			xdr_result = xdr_sm_stat_res;
2410Sstevel@tonic-gate 			local = (char *(*)()) sm_mon;
2420Sstevel@tonic-gate 			break;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 		case SM_UNMON:
2450Sstevel@tonic-gate 			xdr_argument = xdr_mon_id;
2460Sstevel@tonic-gate 			xdr_result = xdr_sm_stat;
2470Sstevel@tonic-gate 			local = (char *(*)()) sm_unmon;
2480Sstevel@tonic-gate 			break;
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 		case SM_UNMON_ALL:
2510Sstevel@tonic-gate 			xdr_argument = xdr_my_id;
2520Sstevel@tonic-gate 			xdr_result = xdr_sm_stat;
2530Sstevel@tonic-gate 			local = (char *(*)()) sm_unmon_all;
2540Sstevel@tonic-gate 			break;
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 		case SM_SIMU_CRASH:
2570Sstevel@tonic-gate 			xdr_argument = xdr_void;
2580Sstevel@tonic-gate 			xdr_result = xdr_void;
2590Sstevel@tonic-gate 			local = (char *(*)()) sm_simu_crash;
2600Sstevel@tonic-gate 			break;
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 		case SM_NOTIFY:
2630Sstevel@tonic-gate 			xdr_argument = xdr_stat_chge;
2640Sstevel@tonic-gate 			xdr_result = xdr_void;
2650Sstevel@tonic-gate 			local = (char *(*)()) sm_notify;
2660Sstevel@tonic-gate 			break;
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 		default:
2690Sstevel@tonic-gate 			svcerr_noproc(transp);
2700Sstevel@tonic-gate 			return;
2710Sstevel@tonic-gate 		}
2720Sstevel@tonic-gate 	}
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	(void) memset(&argument, 0, sizeof (argument));
2750Sstevel@tonic-gate 	if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
2760Sstevel@tonic-gate 		svcerr_decode(transp);
2770Sstevel@tonic-gate 		return;
2780Sstevel@tonic-gate 	}
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	(void) memset(&result, 0, sizeof (result));
2810Sstevel@tonic-gate 	(*local)(&argument, &result);
2820Sstevel@tonic-gate 	if (!svc_sendreply(transp, xdr_result, (caddr_t)&result)) {
2830Sstevel@tonic-gate 		svcerr_systemerr(transp);
2840Sstevel@tonic-gate 	}
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
2870Sstevel@tonic-gate 			syslog(LOG_ERR, "statd: unable to free arguments\n");
2880Sstevel@tonic-gate 		}
2890Sstevel@tonic-gate }
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate /*
2920Sstevel@tonic-gate  * Remove all files under directory path_dir.
2930Sstevel@tonic-gate  */
2940Sstevel@tonic-gate static int
remove_dir(path_dir)2950Sstevel@tonic-gate remove_dir(path_dir)
2960Sstevel@tonic-gate char *path_dir;
2970Sstevel@tonic-gate {
2980Sstevel@tonic-gate 	DIR	*dp;
299871Scasper 	struct dirent   *dirp;
3000Sstevel@tonic-gate 	char tmp_path[MAXPATHLEN];
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	if ((dp = opendir(path_dir)) == (DIR *)NULL) {
3030Sstevel@tonic-gate 		if (debug)
3040Sstevel@tonic-gate 		    syslog(LOG_ERR,
3050Sstevel@tonic-gate 			"warning: open directory %s failed: %m\n", path_dir);
3060Sstevel@tonic-gate 		return (1);
3070Sstevel@tonic-gate 	}
3080Sstevel@tonic-gate 
309871Scasper 	while ((dirp = readdir(dp)) != NULL) {
3100Sstevel@tonic-gate 		if (strcmp(dirp->d_name, ".") != 0 &&
3110Sstevel@tonic-gate 			strcmp(dirp->d_name, "..") != 0) {
3120Sstevel@tonic-gate 			if (strlen(path_dir) + strlen(dirp->d_name) +2 >
3130Sstevel@tonic-gate 				MAXPATHLEN) {
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 				syslog(LOG_ERR,
3160Sstevel@tonic-gate 		"statd: remove dir %s/%s failed.  Pathname too long.\n",
3170Sstevel@tonic-gate 				path_dir, dirp->d_name);
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 				continue;
3200Sstevel@tonic-gate 			}
3210Sstevel@tonic-gate 			(void) strcpy(tmp_path, path_dir);
3220Sstevel@tonic-gate 			(void) strcat(tmp_path, "/");
3230Sstevel@tonic-gate 			(void) strcat(tmp_path, dirp->d_name);
3240Sstevel@tonic-gate 			delete_file(tmp_path);
3250Sstevel@tonic-gate 		}
3260Sstevel@tonic-gate 	}
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	(void) closedir(dp);
3290Sstevel@tonic-gate 	return (0);
3300Sstevel@tonic-gate }
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate /*
3330Sstevel@tonic-gate  * Copy all files from directory `from_dir' to directory `to_dir'.
3340Sstevel@tonic-gate  * Symlinks, if any, are preserved.
3350Sstevel@tonic-gate  */
3360Sstevel@tonic-gate void
copydir_from_to(from_dir,to_dir)3370Sstevel@tonic-gate copydir_from_to(from_dir, to_dir)
3380Sstevel@tonic-gate char *from_dir;
3390Sstevel@tonic-gate char *to_dir;
3400Sstevel@tonic-gate {
3410Sstevel@tonic-gate 	int	n;
3420Sstevel@tonic-gate 	DIR	*dp;
343871Scasper 	struct dirent   *dirp;
3440Sstevel@tonic-gate 	char rname[MAXNAMELEN + 1];
3450Sstevel@tonic-gate 	char path[MAXPATHLEN+MAXNAMELEN+2];
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	if ((dp = opendir(from_dir)) == (DIR *)NULL) {
3480Sstevel@tonic-gate 		if (debug)
3490Sstevel@tonic-gate 		    syslog(LOG_ERR,
3500Sstevel@tonic-gate 			"warning: open directory %s failed: %m\n", from_dir);
3510Sstevel@tonic-gate 		return;
3520Sstevel@tonic-gate 	}
3530Sstevel@tonic-gate 
354871Scasper 	while ((dirp = readdir(dp)) != NULL) {
3550Sstevel@tonic-gate 		if (strcmp(dirp->d_name, ".") == 0 ||
3560Sstevel@tonic-gate 			strcmp(dirp->d_name, "..") == 0) {
3570Sstevel@tonic-gate 			continue;
3580Sstevel@tonic-gate 		}
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 		(void) strcpy(path, from_dir);
3610Sstevel@tonic-gate 		(void) strcat(path, "/");
3620Sstevel@tonic-gate 		(void) strcat(path, dirp->d_name);
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 		if (is_symlink(path)) {
3650Sstevel@tonic-gate 			/*
3660Sstevel@tonic-gate 			 * Follow the link to get the referenced file name
3670Sstevel@tonic-gate 			 * and make a new link for that file in to_dir.
3680Sstevel@tonic-gate 			 */
3690Sstevel@tonic-gate 			n = readlink(path, rname, MAXNAMELEN);
3700Sstevel@tonic-gate 			if (n <= 0) {
3710Sstevel@tonic-gate 				if (debug >= 2) {
3720Sstevel@tonic-gate 				    (void) printf(
3730Sstevel@tonic-gate 					"copydir_from_to: can't read link %s\n",
3740Sstevel@tonic-gate 					path);
3750Sstevel@tonic-gate 				}
3760Sstevel@tonic-gate 				continue;
3770Sstevel@tonic-gate 			}
3780Sstevel@tonic-gate 			rname[n] = '\0';
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 			(void) create_symlink(to_dir, rname, dirp->d_name);
3810Sstevel@tonic-gate 		} else {
3820Sstevel@tonic-gate 			/*
3830Sstevel@tonic-gate 			 * Simply copy regular files to to_dir.
3840Sstevel@tonic-gate 			 */
3850Sstevel@tonic-gate 			(void) strcpy(path, to_dir);
3860Sstevel@tonic-gate 			(void) strcat(path, "/");
3870Sstevel@tonic-gate 			(void) strcat(path, dirp->d_name);
3880Sstevel@tonic-gate 			(void) create_file(path);
3890Sstevel@tonic-gate 		}
3900Sstevel@tonic-gate 	}
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	(void) closedir(dp);
3930Sstevel@tonic-gate }
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate static int
init_hostname(void)3960Sstevel@tonic-gate init_hostname(void)
3970Sstevel@tonic-gate {
3980Sstevel@tonic-gate 	struct lifnum lifn;
3990Sstevel@tonic-gate 	int sock;
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
4020Sstevel@tonic-gate 		syslog(LOG_ERR, "statd:init_hostname, socket: %m");
4030Sstevel@tonic-gate 		return (-1);
4040Sstevel@tonic-gate 	}
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	lifn.lifn_family = AF_UNSPEC;
4070Sstevel@tonic-gate 	lifn.lifn_flags = 0;
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
4100Sstevel@tonic-gate 		syslog(LOG_ERR,
4110Sstevel@tonic-gate 		"statd:init_hostname, get number of interfaces, error: %m");
4120Sstevel@tonic-gate 		close(sock);
4130Sstevel@tonic-gate 		return (-1);
4140Sstevel@tonic-gate 	}
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	host_name_count = lifn.lifn_count;
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	host_name = (char **)malloc(host_name_count * sizeof (char *));
4190Sstevel@tonic-gate 	if (host_name == NULL) {
4200Sstevel@tonic-gate 		perror("statd -a can't get ip configuration\n");
4210Sstevel@tonic-gate 		close(sock);
4220Sstevel@tonic-gate 		return (-1);
4230Sstevel@tonic-gate 	}
4240Sstevel@tonic-gate 	close(sock);
4250Sstevel@tonic-gate 	return (0);
4260Sstevel@tonic-gate }
4270Sstevel@tonic-gate 
428249Sjwahlig int
main(int argc,char * argv[])429249Sjwahlig main(int argc, char *argv[])
4300Sstevel@tonic-gate {
4310Sstevel@tonic-gate 	int c;
4320Sstevel@tonic-gate 	int ppid;
4330Sstevel@tonic-gate 	extern char *optarg;
4340Sstevel@tonic-gate 	int choice = 0;
4350Sstevel@tonic-gate 	struct rlimit rl;
4360Sstevel@tonic-gate 	int mode;
4370Sstevel@tonic-gate 	int sz;
4380Sstevel@tonic-gate 	int connmaxrec = RPC_MAXDATASIZE;
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	addrix = 0;
4410Sstevel@tonic-gate 	pathix = 0;
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	(void) gethostname(hostname, MAXHOSTNAMELEN);
4440Sstevel@tonic-gate 	if (init_hostname() < 0)
4450Sstevel@tonic-gate 		exit(1);
4460Sstevel@tonic-gate 
447*12648SSurya.Prakki@Sun.COM 	while ((c = getopt(argc, argv, "Dd:a:G:p:rU:")) != EOF)
4480Sstevel@tonic-gate 		switch (c) {
4490Sstevel@tonic-gate 		case 'd':
4500Sstevel@tonic-gate 			(void) sscanf(optarg, "%d", &debug);
4510Sstevel@tonic-gate 			break;
4520Sstevel@tonic-gate 		case 'D':
4530Sstevel@tonic-gate 			choice = 1;
4540Sstevel@tonic-gate 			break;
4550Sstevel@tonic-gate 		case 'a':
4560Sstevel@tonic-gate 			if (addrix < host_name_count) {
4570Sstevel@tonic-gate 				if (strcmp(hostname, optarg) != 0) {
4580Sstevel@tonic-gate 					sz = strlen(optarg);
4590Sstevel@tonic-gate 					if (sz < MAXHOSTNAMELEN) {
4600Sstevel@tonic-gate 						host_name[addrix] =
4617832SPavel.Filipensky@Sun.COM 						    (char *)xmalloc(sz+1);
4620Sstevel@tonic-gate 						if (host_name[addrix] !=
4630Sstevel@tonic-gate 						    NULL) {
4640Sstevel@tonic-gate 						(void) sscanf(optarg, "%s",
4657832SPavel.Filipensky@Sun.COM 						    host_name[addrix]);
4660Sstevel@tonic-gate 							addrix++;
4670Sstevel@tonic-gate 						}
4680Sstevel@tonic-gate 					} else
4690Sstevel@tonic-gate 					(void) fprintf(stderr,
4700Sstevel@tonic-gate 				    "statd: -a name of host is too long.\n");
4710Sstevel@tonic-gate 				}
4720Sstevel@tonic-gate 			} else
4730Sstevel@tonic-gate 				(void) fprintf(stderr,
4740Sstevel@tonic-gate 				    "statd: -a exceeding maximum hostnames\n");
4750Sstevel@tonic-gate 			break;
4762712Snn35248 		case 'U':
4772712Snn35248 			(void) sscanf(optarg, "%d", &daemon_uid);
4782712Snn35248 			break;
4792712Snn35248 		case 'G':
4802712Snn35248 			(void) sscanf(optarg, "%d", &daemon_gid);
4812712Snn35248 			break;
4820Sstevel@tonic-gate 		case 'p':
4830Sstevel@tonic-gate 			if (strlen(optarg) < MAXPATHLEN) {
4840Sstevel@tonic-gate 				/* If the path_name array has not yet	   */
4850Sstevel@tonic-gate 				/* been malloc'ed, do that.  The array	   */
4860Sstevel@tonic-gate 				/* should be big enough to hold all of the */
4870Sstevel@tonic-gate 				/* -p options we might have.  An upper	   */
4880Sstevel@tonic-gate 				/* bound on the number of -p options is	   */
4890Sstevel@tonic-gate 				/* argc/2, because each -p option consumes */
4900Sstevel@tonic-gate 				/* two arguments.  Here the upper bound	   */
4910Sstevel@tonic-gate 				/* is supposing that all the command line  */
4920Sstevel@tonic-gate 				/* arguments are -p options, which would   */
4930Sstevel@tonic-gate 				/* actually never be the case.		   */
4940Sstevel@tonic-gate 				if (path_name == NULL) {
4950Sstevel@tonic-gate 					size_t sz = (argc/2) * sizeof (char *);
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 					path_name = (char **)malloc(sz);
4980Sstevel@tonic-gate 					if (path_name == NULL) {
4990Sstevel@tonic-gate 						(void) fprintf(stderr,
5000Sstevel@tonic-gate 						"statd: malloc failed\n");
5010Sstevel@tonic-gate 						exit(1);
5020Sstevel@tonic-gate 					}
5030Sstevel@tonic-gate 					(void) memset(path_name, 0, sz);
5040Sstevel@tonic-gate 				}
5050Sstevel@tonic-gate 				path_name[pathix] = optarg;
5060Sstevel@tonic-gate 				pathix++;
5070Sstevel@tonic-gate 			} else {
5080Sstevel@tonic-gate 				(void) fprintf(stderr,
5090Sstevel@tonic-gate 				"statd: -p pathname is too long.\n");
5100Sstevel@tonic-gate 			}
5110Sstevel@tonic-gate 			break;
5120Sstevel@tonic-gate 		case 'r':
5130Sstevel@tonic-gate 			regfiles_only = 1;
5140Sstevel@tonic-gate 			break;
5150Sstevel@tonic-gate 		default:
5160Sstevel@tonic-gate 			(void) fprintf(stderr,
5170Sstevel@tonic-gate 			"statd [-d level] [-D]\n");
5180Sstevel@tonic-gate 			return (1);
5190Sstevel@tonic-gate 		}
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	if (choice == 0) {
5220Sstevel@tonic-gate 		(void) strcpy(statd_home, home0);
5230Sstevel@tonic-gate 		(void) strcpy(CURRENT, current0);
5240Sstevel@tonic-gate 		(void) strcpy(BACKUP, backup0);
5250Sstevel@tonic-gate 		(void) strcpy(STATE, state0);
5260Sstevel@tonic-gate 	} else {
5270Sstevel@tonic-gate 		(void) strcpy(statd_home, home1);
5280Sstevel@tonic-gate 		(void) strcpy(CURRENT, current1);
5290Sstevel@tonic-gate 		(void) strcpy(BACKUP, backup1);
5300Sstevel@tonic-gate 		(void) strcpy(STATE, state1);
5310Sstevel@tonic-gate 	}
5320Sstevel@tonic-gate 	if (debug)
5330Sstevel@tonic-gate 		(void) printf("debug is on, create entry: %s, %s, %s\n",
5347832SPavel.Filipensky@Sun.COM 		    CURRENT, BACKUP, STATE);
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	if (getrlimit(RLIMIT_NOFILE, &rl))
5370Sstevel@tonic-gate 		(void) printf("statd: getrlimit failed. \n");
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	/* Set maxfdlimit current soft limit */
5407832SPavel.Filipensky@Sun.COM 	rl.rlim_cur = rl.rlim_max;
5410Sstevel@tonic-gate 	if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
5420Sstevel@tonic-gate 		syslog(LOG_ERR, "statd: unable to set RLIMIT_NOFILE to %d\n",
5437832SPavel.Filipensky@Sun.COM 		    rl.rlim_cur);
5440Sstevel@tonic-gate 
5451914Scasper 	(void) enable_extended_FILE_stdio(-1, -1);
5461914Scasper 
5470Sstevel@tonic-gate 	if (!debug) {
5480Sstevel@tonic-gate 		ppid = fork();
5490Sstevel@tonic-gate 		if (ppid == -1) {
5500Sstevel@tonic-gate 			(void) fprintf(stderr, "statd: fork failure\n");
5510Sstevel@tonic-gate 			(void) fflush(stderr);
5520Sstevel@tonic-gate 			abort();
5530Sstevel@tonic-gate 		}
5540Sstevel@tonic-gate 		if (ppid != 0) {
5550Sstevel@tonic-gate 			exit(0);
5560Sstevel@tonic-gate 		}
5570Sstevel@tonic-gate 		closefrom(0);
5580Sstevel@tonic-gate 		(void) open("/dev/null", O_RDONLY);
5590Sstevel@tonic-gate 		(void) open("/dev/null", O_WRONLY);
5600Sstevel@tonic-gate 		(void) dup(1);
5610Sstevel@tonic-gate 		(void) setsid();
5620Sstevel@tonic-gate 		openlog("statd", LOG_PID, LOG_DAEMON);
5630Sstevel@tonic-gate 	}
5640Sstevel@tonic-gate 
5652712Snn35248 	(void) _create_daemon_lock(STATD, daemon_uid, daemon_gid);
5660Sstevel@tonic-gate 	/*
5670Sstevel@tonic-gate 	 * establish our lock on the lock file and write our pid to it.
5680Sstevel@tonic-gate 	 * exit if some other process holds the lock, or if there's any
5690Sstevel@tonic-gate 	 * error in writing/locking the file.
5700Sstevel@tonic-gate 	 */
5710Sstevel@tonic-gate 	ppid = _enter_daemon_lock(STATD);
5720Sstevel@tonic-gate 	switch (ppid) {
5730Sstevel@tonic-gate 	case 0:
5740Sstevel@tonic-gate 		break;
5750Sstevel@tonic-gate 	case -1:
5760Sstevel@tonic-gate 		syslog(LOG_ERR, "error locking for %s: %s", STATD,
5770Sstevel@tonic-gate 		    strerror(errno));
5780Sstevel@tonic-gate 		exit(2);
5790Sstevel@tonic-gate 	default:
5800Sstevel@tonic-gate 		/* daemon was already running */
5810Sstevel@tonic-gate 		exit(0);
5820Sstevel@tonic-gate 	}
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	/* Get other aliases from each interface. */
5850Sstevel@tonic-gate 	merge_hosts();
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	/*
5880Sstevel@tonic-gate 	 * Set to automatic mode such that threads are automatically
5890Sstevel@tonic-gate 	 * created
5900Sstevel@tonic-gate 	 */
5910Sstevel@tonic-gate 	mode = RPC_SVC_MT_AUTO;
5920Sstevel@tonic-gate 	if (!rpc_control(RPC_SVC_MTMODE_SET, &mode)) {
5930Sstevel@tonic-gate 		syslog(LOG_ERR,
5947832SPavel.Filipensky@Sun.COM 		    "statd:unable to set automatic MT mode.");
5950Sstevel@tonic-gate 		exit(1);
5960Sstevel@tonic-gate 	}
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 	/*
5990Sstevel@tonic-gate 	 * Set non-blocking mode and maximum record size for
6000Sstevel@tonic-gate 	 * connection oriented RPC transports.
6010Sstevel@tonic-gate 	 */
6020Sstevel@tonic-gate 	if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
6030Sstevel@tonic-gate 		syslog(LOG_INFO, "unable to set maximum RPC record size");
6040Sstevel@tonic-gate 	}
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 	if (!svc_create(sm_prog_1, SM_PROG, SM_VERS, "netpath")) {
6077832SPavel.Filipensky@Sun.COM 		syslog(LOG_ERR,
6087832SPavel.Filipensky@Sun.COM 	    "statd: unable to create (SM_PROG, SM_VERS) for netpath.");
6097832SPavel.Filipensky@Sun.COM 		exit(1);
6100Sstevel@tonic-gate 	}
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 	if (!svc_create(sm_prog_1, NSM_ADDR_PROGRAM, NSM_ADDR_V1, "netpath")) {
6137832SPavel.Filipensky@Sun.COM 		syslog(LOG_ERR,
6140Sstevel@tonic-gate 	"statd: unable to create (NSM_ADDR_PROGRAM, NSM_ADDR_V1) for netpath.");
6150Sstevel@tonic-gate 	}
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	/*
6180Sstevel@tonic-gate 	 * Make sure /var/statmon and any alternate (-p) statmon
6190Sstevel@tonic-gate 	 * directories exist and are owned by daemon.  Then change our uid
6200Sstevel@tonic-gate 	 * to daemon.  The uid change is to prevent attacks against local
6210Sstevel@tonic-gate 	 * daemons that trust any call from a local root process.
6220Sstevel@tonic-gate 	 */
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	set_statmon_owner();
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	/*
6270Sstevel@tonic-gate 	 *
6280Sstevel@tonic-gate 	 * statd now runs as a daemon rather than root and can not
6290Sstevel@tonic-gate 	 * dump core under / because of the permission. It is
6300Sstevel@tonic-gate 	 * important that current working directory of statd be
6310Sstevel@tonic-gate 	 * changed to writable directory /var/statmon so that it
6320Sstevel@tonic-gate 	 * can dump the core upon the receipt of the signal.
6330Sstevel@tonic-gate 	 * One still need to set allow_setid_core to non-zero in
6340Sstevel@tonic-gate 	 * /etc/system to get the core dump.
6350Sstevel@tonic-gate 	 *
6360Sstevel@tonic-gate 	 */
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	if (chdir(statd_home) < 0) {
6390Sstevel@tonic-gate 		syslog(LOG_ERR, "can't chdir %s: %m", statd_home);
6400Sstevel@tonic-gate 		exit(1);
6410Sstevel@tonic-gate 	}
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	copy_client_names();
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 	rwlock_init(&thr_rwlock, USYNC_THREAD, NULL);
6460Sstevel@tonic-gate 	mutex_init(&crash_lock, USYNC_THREAD, NULL);
6470Sstevel@tonic-gate 	mutex_init(&name_addrlock, USYNC_THREAD, NULL);
6480Sstevel@tonic-gate 	cond_init(&crash_finish, USYNC_THREAD, NULL);
6490Sstevel@tonic-gate 	cond_init(&retrywait, USYNC_THREAD, NULL);
6500Sstevel@tonic-gate 	sm_inithash();
6510Sstevel@tonic-gate 	die = 0;
6520Sstevel@tonic-gate 	/*
6530Sstevel@tonic-gate 	 * This variable is set to ensure that an sm_crash
6540Sstevel@tonic-gate 	 * request will not be done at the same time
6550Sstevel@tonic-gate 	 * when a statd_init is being done, since sm_crash
6560Sstevel@tonic-gate 	 * can reset some variables that statd_init will be using.
6570Sstevel@tonic-gate 	 */
6580Sstevel@tonic-gate 	in_crash = 1;
6590Sstevel@tonic-gate 	statd_init();
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 	if (debug)
6620Sstevel@tonic-gate 		(void) printf("Starting svc_run\n");
6630Sstevel@tonic-gate 	svc_run();
6640Sstevel@tonic-gate 	syslog(LOG_ERR, "statd: svc_run returned\n");
6650Sstevel@tonic-gate 	/* NOTREACHED */
6660Sstevel@tonic-gate 	thr_exit((void *) 1);
667249Sjwahlig 	return (0);
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate }
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate /*
6720Sstevel@tonic-gate  * Make sure the ownership of the statmon directories is correct, then
6730Sstevel@tonic-gate  * change our uid to match.  If the top-level directories (/var/statmon, -p
6740Sstevel@tonic-gate  * arguments) don't exist, they are created first.  The sm and sm.bak
6750Sstevel@tonic-gate  * directories are not created here, but if they already exist, they are
6760Sstevel@tonic-gate  * chowned to the correct uid, along with anything else in the
6770Sstevel@tonic-gate  * directories.
6780Sstevel@tonic-gate  */
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate static void
set_statmon_owner(void)6811676Sjpk set_statmon_owner(void)
6820Sstevel@tonic-gate {
6830Sstevel@tonic-gate 	int i;
6841676Sjpk 	boolean_t can_do_mlp;
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	/*
6870Sstevel@tonic-gate 	 * Recursively chown/chgrp /var/statmon and the alternate paths,
6880Sstevel@tonic-gate 	 * creating them if necessary.
6890Sstevel@tonic-gate 	 */
6900Sstevel@tonic-gate 	one_statmon_owner(statd_home);
6910Sstevel@tonic-gate 	for (i = 0; i < pathix; i++) {
6920Sstevel@tonic-gate 		char alt_path[MAXPATHLEN];
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 		snprintf(alt_path, MAXPATHLEN, "%s/statmon", path_name[i]);
6950Sstevel@tonic-gate 		one_statmon_owner(alt_path);
6960Sstevel@tonic-gate 	}
6970Sstevel@tonic-gate 
6981676Sjpk 	can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
6990Sstevel@tonic-gate 	if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET,
7002712Snn35248 	    daemon_uid, daemon_gid, can_do_mlp ? PRIV_NET_BINDMLP : NULL,
7011676Sjpk 	    NULL) == -1) {
7020Sstevel@tonic-gate 		syslog(LOG_ERR, "can't run unprivileged: %m");
7030Sstevel@tonic-gate 		exit(1);
7040Sstevel@tonic-gate 	}
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	__fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_SESSION,
7070Sstevel@tonic-gate 	    PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
7080Sstevel@tonic-gate }
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate /*
7110Sstevel@tonic-gate  * Copy client names from the alternate statmon directories into
7120Sstevel@tonic-gate  * /var/statmon.  The top-level (statmon) directories should already
7130Sstevel@tonic-gate  * exist, though the sm and sm.bak directories might not.
7140Sstevel@tonic-gate  */
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate static void
copy_client_names()7170Sstevel@tonic-gate copy_client_names()
7180Sstevel@tonic-gate {
7190Sstevel@tonic-gate 	int i;
7200Sstevel@tonic-gate 	char buf[MAXPATHLEN+SM_MAXPATHLEN];
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 	/*
7230Sstevel@tonic-gate 	 * Copy all clients from alternate paths to /var/statmon/sm
7240Sstevel@tonic-gate 	 * Remove the files in alternate directory when copying is done.
7250Sstevel@tonic-gate 	 */
7260Sstevel@tonic-gate 	for (i = 0; i < pathix; i++) {
7270Sstevel@tonic-gate 		/*
7280Sstevel@tonic-gate 		 * If the alternate directories do not exist, create it.
7290Sstevel@tonic-gate 		 * If they do exist, just do the copy.
7300Sstevel@tonic-gate 		 */
7310Sstevel@tonic-gate 		snprintf(buf, sizeof (buf), "%s/statmon/sm", path_name[i]);
7320Sstevel@tonic-gate 		if ((mkdir(buf, SM_DIRECTORY_MODE)) == -1) {
7330Sstevel@tonic-gate 			if (errno != EEXIST) {
7340Sstevel@tonic-gate 				syslog(LOG_ERR,
7357832SPavel.Filipensky@Sun.COM 				    "can't mkdir %s: %m\n", buf);
7360Sstevel@tonic-gate 				continue;
7370Sstevel@tonic-gate 			}
7380Sstevel@tonic-gate 			copydir_from_to(buf, CURRENT);
7390Sstevel@tonic-gate 			(void) remove_dir(buf);
7400Sstevel@tonic-gate 		}
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "%s/statmon/sm.bak",
7437832SPavel.Filipensky@Sun.COM 		    path_name[i]);
7440Sstevel@tonic-gate 		if ((mkdir(buf, SM_DIRECTORY_MODE)) == -1) {
7450Sstevel@tonic-gate 			if (errno != EEXIST) {
7460Sstevel@tonic-gate 				syslog(LOG_ERR,
7477832SPavel.Filipensky@Sun.COM 				    "can't mkdir %s: %m\n", buf);
7480Sstevel@tonic-gate 				continue;
7490Sstevel@tonic-gate 			}
7500Sstevel@tonic-gate 			copydir_from_to(buf, BACKUP);
7510Sstevel@tonic-gate 			(void) remove_dir(buf);
7520Sstevel@tonic-gate 		}
7530Sstevel@tonic-gate 	}
7540Sstevel@tonic-gate }
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate /*
7570Sstevel@tonic-gate  * Create the given directory if it doesn't already exist.  Set the user
7580Sstevel@tonic-gate  * and group to daemon for the directory and anything under it.
7590Sstevel@tonic-gate  */
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate static void
one_statmon_owner(const char * dir)7620Sstevel@tonic-gate one_statmon_owner(const char *dir)
7630Sstevel@tonic-gate {
7640Sstevel@tonic-gate 	if ((mkdir(dir, SM_DIRECTORY_MODE)) == -1) {
7650Sstevel@tonic-gate 		if (errno != EEXIST) {
7660Sstevel@tonic-gate 			syslog(LOG_ERR, "can't mkdir %s: %m",
7670Sstevel@tonic-gate 			    dir);
7680Sstevel@tonic-gate 			return;
7690Sstevel@tonic-gate 		}
7700Sstevel@tonic-gate 	}
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	if (debug)
7730Sstevel@tonic-gate 		printf("Setting owner for %s\n", dir);
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	if (nftw(dir, nftw_owner, MAX_FDS, FTW_PHYS) != 0) {
7760Sstevel@tonic-gate 		syslog(LOG_WARNING, "error setting owner for %s: %m",
7770Sstevel@tonic-gate 		    dir);
7780Sstevel@tonic-gate 	}
7790Sstevel@tonic-gate }
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate /*
7820Sstevel@tonic-gate  * Set the user and group to daemon for the given file or directory.  If
7830Sstevel@tonic-gate  * it's a directory, also makes sure that it is mode 755.
7840Sstevel@tonic-gate  * Generates a syslog message but does not return an error if there were
7850Sstevel@tonic-gate  * problems.
7860Sstevel@tonic-gate  */
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate /*ARGSUSED3*/
7890Sstevel@tonic-gate static int
nftw_owner(const char * path,const struct stat * statp,int info,struct FTW * ftw)7900Sstevel@tonic-gate nftw_owner(const char *path, const struct stat *statp, int info,
7910Sstevel@tonic-gate 	struct FTW *ftw)
7920Sstevel@tonic-gate {
7930Sstevel@tonic-gate 	if (!(info == FTW_F || info == FTW_D))
7940Sstevel@tonic-gate 		return (0);
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 	/*
7970Sstevel@tonic-gate 	 * Some older systems might have mode 777 directories.  Fix that.
7980Sstevel@tonic-gate 	 */
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	if (info == FTW_D && (statp->st_mode & (S_IWGRP | S_IWOTH)) != 0) {
8010Sstevel@tonic-gate 		mode_t newmode = (statp->st_mode & ~(S_IWGRP | S_IWOTH)) &
8027832SPavel.Filipensky@Sun.COM 		    S_IAMB;
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 		if (debug)
8050Sstevel@tonic-gate 			printf("chmod %03o %s\n", newmode, path);
8060Sstevel@tonic-gate 		if (chmod(path, newmode) < 0) {
8070Sstevel@tonic-gate 			int error = errno;
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 			syslog(LOG_WARNING, "can't chmod %s to %03o: %m",
8100Sstevel@tonic-gate 			    path, newmode);
8110Sstevel@tonic-gate 			if (debug)
8120Sstevel@tonic-gate 				printf("  FAILED: %s\n", strerror(error));
8130Sstevel@tonic-gate 		}
8140Sstevel@tonic-gate 	}
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 	/* If already owned by daemon, don't bother changing. */
8172712Snn35248 	if (statp->st_uid == daemon_uid &&
8182712Snn35248 	    statp->st_gid == daemon_gid)
8190Sstevel@tonic-gate 		return (0);
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 	if (debug)
8220Sstevel@tonic-gate 		printf("lchown %s daemon:daemon\n", path);
8232712Snn35248 	if (lchown(path, daemon_uid, daemon_gid) < 0) {
8240Sstevel@tonic-gate 		int error = errno;
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 		syslog(LOG_WARNING, "can't chown %s to daemon: %m",
8270Sstevel@tonic-gate 		    path);
8280Sstevel@tonic-gate 		if (debug)
8290Sstevel@tonic-gate 			printf("  FAILED: %s\n", strerror(error));
8300Sstevel@tonic-gate 	}
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 	return (0);
8330Sstevel@tonic-gate }
834