xref: /onnv-gate/usr/src/cmd/fs.d/nfs/statd/sm_svc.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*0Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate /*
31*0Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
32*0Sstevel@tonic-gate  * The Regents of the University of California
33*0Sstevel@tonic-gate  * All Rights Reserved
34*0Sstevel@tonic-gate  *
35*0Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
36*0Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
37*0Sstevel@tonic-gate  * contributors.
38*0Sstevel@tonic-gate  */
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate #include <stdio.h>
43*0Sstevel@tonic-gate #include <stdlib.h>
44*0Sstevel@tonic-gate #include <ftw.h>
45*0Sstevel@tonic-gate #include <signal.h>
46*0Sstevel@tonic-gate #include <string.h>
47*0Sstevel@tonic-gate #include <syslog.h>
48*0Sstevel@tonic-gate #include <netconfig.h>
49*0Sstevel@tonic-gate #include <unistd.h>
50*0Sstevel@tonic-gate #include <netdb.h>
51*0Sstevel@tonic-gate #include <rpc/rpc.h>
52*0Sstevel@tonic-gate #include <netinet/in.h>
53*0Sstevel@tonic-gate #include <sys/param.h>
54*0Sstevel@tonic-gate #include <sys/resource.h>
55*0Sstevel@tonic-gate #include <sys/file.h>
56*0Sstevel@tonic-gate #include <sys/types.h>
57*0Sstevel@tonic-gate #include <sys/stat.h>
58*0Sstevel@tonic-gate #include <sys/sockio.h>
59*0Sstevel@tonic-gate #include <dirent.h>
60*0Sstevel@tonic-gate #include <errno.h>
61*0Sstevel@tonic-gate #include <rpcsvc/sm_inter.h>
62*0Sstevel@tonic-gate #include <rpcsvc/nsm_addr.h>
63*0Sstevel@tonic-gate #include <thread.h>
64*0Sstevel@tonic-gate #include <synch.h>
65*0Sstevel@tonic-gate #include <net/if.h>
66*0Sstevel@tonic-gate #include <limits.h>
67*0Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h>
68*0Sstevel@tonic-gate #include <priv_utils.h>
69*0Sstevel@tonic-gate #include "sm_statd.h"
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate #define	home0		"/var/statmon"
73*0Sstevel@tonic-gate #define	current0	"/var/statmon/sm"
74*0Sstevel@tonic-gate #define	backup0		"/var/statmon/sm.bak"
75*0Sstevel@tonic-gate #define	state0		"/var/statmon/state"
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate #define	home1		"statmon"
78*0Sstevel@tonic-gate #define	current1	"statmon/sm/"
79*0Sstevel@tonic-gate #define	backup1		"statmon/sm.bak/"
80*0Sstevel@tonic-gate #define	state1		"statmon/state"
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate /*
83*0Sstevel@tonic-gate  * User and group IDs to run as.  These are hardwired, rather than looked
84*0Sstevel@tonic-gate  * up at runtime, because they are very unlikely to change and because they
85*0Sstevel@tonic-gate  * provide some protection against bogus changes to the passwd and group
86*0Sstevel@tonic-gate  * files.
87*0Sstevel@tonic-gate  */
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate char STATE[MAXPATHLEN], CURRENT[MAXPATHLEN], BACKUP[MAXPATHLEN];
90*0Sstevel@tonic-gate static char statd_home[MAXPATHLEN];
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate int debug;
93*0Sstevel@tonic-gate int regfiles_only = 0;		/* 1 => use symlinks in statmon, 0 => don't */
94*0Sstevel@tonic-gate char hostname[MAXHOSTNAMELEN];
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate /*
97*0Sstevel@tonic-gate  * These variables will be used to store all the
98*0Sstevel@tonic-gate  * alias names for the host, as well as the -a
99*0Sstevel@tonic-gate  * command line hostnames.
100*0Sstevel@tonic-gate  */
101*0Sstevel@tonic-gate int host_name_count;
102*0Sstevel@tonic-gate char **host_name; /* store -a opts */
103*0Sstevel@tonic-gate int  addrix; /* # of -a entries */
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate /*
107*0Sstevel@tonic-gate  * The following 2 variables are meaningful
108*0Sstevel@tonic-gate  * only under a HA configuration.
109*0Sstevel@tonic-gate  * The path_name array is dynamically allocated in main() during
110*0Sstevel@tonic-gate  * command line argument processing for the -p options.
111*0Sstevel@tonic-gate  */
112*0Sstevel@tonic-gate char **path_name = NULL;  /* store -p opts */
113*0Sstevel@tonic-gate int  pathix = 0;  /* # of -p entries */
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate /* Global variables.  Refer to sm_statd.h for description */
116*0Sstevel@tonic-gate mutex_t crash_lock;
117*0Sstevel@tonic-gate int die;
118*0Sstevel@tonic-gate int in_crash;
119*0Sstevel@tonic-gate cond_t crash_finish;
120*0Sstevel@tonic-gate mutex_t sm_trylock;
121*0Sstevel@tonic-gate rwlock_t thr_rwlock;
122*0Sstevel@tonic-gate cond_t retrywait;
123*0Sstevel@tonic-gate mutex_t name_addrlock;
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate /* forward references */
126*0Sstevel@tonic-gate static void set_statmon_owner(void);
127*0Sstevel@tonic-gate static void copy_client_names(void);
128*0Sstevel@tonic-gate static void one_statmon_owner(const char *);
129*0Sstevel@tonic-gate static int nftw_owner(const char *, const struct stat *, int, struct FTW *);
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate /*
132*0Sstevel@tonic-gate  * statd protocol
133*0Sstevel@tonic-gate  * 	commands:
134*0Sstevel@tonic-gate  * 		SM_STAT
135*0Sstevel@tonic-gate  * 			returns stat_fail to caller
136*0Sstevel@tonic-gate  * 		SM_MON
137*0Sstevel@tonic-gate  * 			adds an entry to the monitor_q and the record_q
138*0Sstevel@tonic-gate  *			This message is sent by the server lockd to the server
139*0Sstevel@tonic-gate  *			statd, to indicate that a new client is to be monitored.
140*0Sstevel@tonic-gate  *			It is also sent by the server lockd to the client statd
141*0Sstevel@tonic-gate  *			to indicate that a new server is to be monitored.
142*0Sstevel@tonic-gate  * 		SM_UNMON
143*0Sstevel@tonic-gate  * 			removes an entry from the monitor_q and the record_q
144*0Sstevel@tonic-gate  * 		SM_UNMON_ALL
145*0Sstevel@tonic-gate  * 			removes all entries from a particular host from the
146*0Sstevel@tonic-gate  * 			monitor_q and the record_q.  Our statd has this
147*0Sstevel@tonic-gate  * 			disabled.
148*0Sstevel@tonic-gate  * 		SM_SIMU_CRASH
149*0Sstevel@tonic-gate  * 			simulate a crash.  removes everything from the
150*0Sstevel@tonic-gate  * 			record_q and the recovery_q, then calls statd_init()
151*0Sstevel@tonic-gate  * 			to restart things.  This message is sent by the server
152*0Sstevel@tonic-gate  *			lockd to the server statd to have all clients notified
153*0Sstevel@tonic-gate  *			that they should reclaim locks.
154*0Sstevel@tonic-gate  * 		SM_NOTIFY
155*0Sstevel@tonic-gate  *			Sent by statd on server to statd on client during
156*0Sstevel@tonic-gate  *			crash recovery.  The client statd passes the info
157*0Sstevel@tonic-gate  *			to its lockd so it can attempt to reclaim the locks
158*0Sstevel@tonic-gate  *			held on the server.
159*0Sstevel@tonic-gate  *
160*0Sstevel@tonic-gate  * There are three main hash tables used to keep track of things.
161*0Sstevel@tonic-gate  * 	mon_table
162*0Sstevel@tonic-gate  * 		table that keeps track hosts statd must watch.  If one of
163*0Sstevel@tonic-gate  * 		these hosts crashes, then any locks held by that host must
164*0Sstevel@tonic-gate  * 		be released.
165*0Sstevel@tonic-gate  * 	record_table
166*0Sstevel@tonic-gate  * 		used to keep track of all the hostname files stored in
167*0Sstevel@tonic-gate  * 		the directory /var/statmon/sm.  These are client hosts who
168*0Sstevel@tonic-gate  *		are holding or have held a lock at some point.  Needed
169*0Sstevel@tonic-gate  *		to determine if a file needs to be created for host in
170*0Sstevel@tonic-gate  *		/var/statmon/sm.
171*0Sstevel@tonic-gate  *	recov_q
172*0Sstevel@tonic-gate  *		used to keep track hostnames during a recovery
173*0Sstevel@tonic-gate  *
174*0Sstevel@tonic-gate  * The entries are hashed based upon the name.
175*0Sstevel@tonic-gate  *
176*0Sstevel@tonic-gate  * There is a directory /var/statmon/sm which holds a file named
177*0Sstevel@tonic-gate  * for each host that is holding (or has held) a lock.  This is
178*0Sstevel@tonic-gate  * used during initialization on startup, or after a simulated
179*0Sstevel@tonic-gate  * crash.
180*0Sstevel@tonic-gate  */
181*0Sstevel@tonic-gate 
182*0Sstevel@tonic-gate static void
183*0Sstevel@tonic-gate sm_prog_1(rqstp, transp)
184*0Sstevel@tonic-gate 	struct svc_req *rqstp;
185*0Sstevel@tonic-gate 	SVCXPRT *transp;
186*0Sstevel@tonic-gate {
187*0Sstevel@tonic-gate 	union {
188*0Sstevel@tonic-gate 		struct sm_name sm_stat_1_arg;
189*0Sstevel@tonic-gate 		struct mon sm_mon_1_arg;
190*0Sstevel@tonic-gate 		struct mon_id sm_unmon_1_arg;
191*0Sstevel@tonic-gate 		struct my_id sm_unmon_all_1_arg;
192*0Sstevel@tonic-gate 		struct stat_chge ntf_arg;
193*0Sstevel@tonic-gate 		struct reg1args reg1_arg;
194*0Sstevel@tonic-gate 	} argument;
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate 	union {
197*0Sstevel@tonic-gate 		sm_stat_res stat_resp;
198*0Sstevel@tonic-gate 		sm_stat	mon_resp;
199*0Sstevel@tonic-gate 		struct reg1res reg1_resp;
200*0Sstevel@tonic-gate 	} result;
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	bool_t (*xdr_argument)(), (*xdr_result)();
203*0Sstevel@tonic-gate 	char *(*local)();
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 	/*
206*0Sstevel@tonic-gate 	 * Dispatch according to which protocol is being used:
207*0Sstevel@tonic-gate 	 *	NSM_ADDR_PROGRAM is the private lockd address
208*0Sstevel@tonic-gate 	 *		registration protocol.
209*0Sstevel@tonic-gate 	 *	SM_PROG is the normal statd (NSM) protocol.
210*0Sstevel@tonic-gate 	 */
211*0Sstevel@tonic-gate 	if (rqstp->rq_prog == NSM_ADDR_PROGRAM) {
212*0Sstevel@tonic-gate 		switch (rqstp->rq_proc) {
213*0Sstevel@tonic-gate 		case NULLPROC:
214*0Sstevel@tonic-gate 			svc_sendreply(transp, xdr_void, (caddr_t)NULL);
215*0Sstevel@tonic-gate 			return;
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 		case NSMADDRPROC1_REG:
218*0Sstevel@tonic-gate 			xdr_argument = xdr_reg1args;
219*0Sstevel@tonic-gate 			xdr_result = xdr_reg1res;
220*0Sstevel@tonic-gate 			local = (char *(*)()) nsmaddrproc1_reg;
221*0Sstevel@tonic-gate 			break;
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 		default:
224*0Sstevel@tonic-gate 			svcerr_noproc(transp);
225*0Sstevel@tonic-gate 			return;
226*0Sstevel@tonic-gate 		}
227*0Sstevel@tonic-gate 	} else {
228*0Sstevel@tonic-gate 		switch (rqstp->rq_proc) {
229*0Sstevel@tonic-gate 		case NULLPROC:
230*0Sstevel@tonic-gate 			svc_sendreply(transp, xdr_void, (caddr_t)NULL);
231*0Sstevel@tonic-gate 			return;
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate 		case SM_STAT:
234*0Sstevel@tonic-gate 			xdr_argument = xdr_sm_name;
235*0Sstevel@tonic-gate 			xdr_result = xdr_sm_stat_res;
236*0Sstevel@tonic-gate 			local = (char *(*)()) sm_status;
237*0Sstevel@tonic-gate 			break;
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 		case SM_MON:
240*0Sstevel@tonic-gate 			xdr_argument = xdr_mon;
241*0Sstevel@tonic-gate 			xdr_result = xdr_sm_stat_res;
242*0Sstevel@tonic-gate 			local = (char *(*)()) sm_mon;
243*0Sstevel@tonic-gate 			break;
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 		case SM_UNMON:
246*0Sstevel@tonic-gate 			xdr_argument = xdr_mon_id;
247*0Sstevel@tonic-gate 			xdr_result = xdr_sm_stat;
248*0Sstevel@tonic-gate 			local = (char *(*)()) sm_unmon;
249*0Sstevel@tonic-gate 			break;
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 		case SM_UNMON_ALL:
252*0Sstevel@tonic-gate 			xdr_argument = xdr_my_id;
253*0Sstevel@tonic-gate 			xdr_result = xdr_sm_stat;
254*0Sstevel@tonic-gate 			local = (char *(*)()) sm_unmon_all;
255*0Sstevel@tonic-gate 			break;
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 		case SM_SIMU_CRASH:
258*0Sstevel@tonic-gate 			xdr_argument = xdr_void;
259*0Sstevel@tonic-gate 			xdr_result = xdr_void;
260*0Sstevel@tonic-gate 			local = (char *(*)()) sm_simu_crash;
261*0Sstevel@tonic-gate 			break;
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 		case SM_NOTIFY:
264*0Sstevel@tonic-gate 			xdr_argument = xdr_stat_chge;
265*0Sstevel@tonic-gate 			xdr_result = xdr_void;
266*0Sstevel@tonic-gate 			local = (char *(*)()) sm_notify;
267*0Sstevel@tonic-gate 			break;
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate 		default:
270*0Sstevel@tonic-gate 			svcerr_noproc(transp);
271*0Sstevel@tonic-gate 			return;
272*0Sstevel@tonic-gate 		}
273*0Sstevel@tonic-gate 	}
274*0Sstevel@tonic-gate 
275*0Sstevel@tonic-gate 	(void) memset(&argument, 0, sizeof (argument));
276*0Sstevel@tonic-gate 	if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
277*0Sstevel@tonic-gate 		svcerr_decode(transp);
278*0Sstevel@tonic-gate 		return;
279*0Sstevel@tonic-gate 	}
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 	(void) memset(&result, 0, sizeof (result));
282*0Sstevel@tonic-gate 	(*local)(&argument, &result);
283*0Sstevel@tonic-gate 	if (!svc_sendreply(transp, xdr_result, (caddr_t)&result)) {
284*0Sstevel@tonic-gate 		svcerr_systemerr(transp);
285*0Sstevel@tonic-gate 	}
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 	if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
288*0Sstevel@tonic-gate 			syslog(LOG_ERR, "statd: unable to free arguments\n");
289*0Sstevel@tonic-gate 		}
290*0Sstevel@tonic-gate }
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate /*
293*0Sstevel@tonic-gate  * Remove all files under directory path_dir.
294*0Sstevel@tonic-gate  */
295*0Sstevel@tonic-gate static int
296*0Sstevel@tonic-gate remove_dir(path_dir)
297*0Sstevel@tonic-gate char *path_dir;
298*0Sstevel@tonic-gate {
299*0Sstevel@tonic-gate 	DIR	*dp;
300*0Sstevel@tonic-gate 	struct dirent   *dirp, *entp;
301*0Sstevel@tonic-gate 	char tmp_path[MAXPATHLEN];
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate 	if ((dp = opendir(path_dir)) == (DIR *)NULL) {
304*0Sstevel@tonic-gate 		if (debug)
305*0Sstevel@tonic-gate 		    syslog(LOG_ERR,
306*0Sstevel@tonic-gate 			"warning: open directory %s failed: %m\n", path_dir);
307*0Sstevel@tonic-gate 		return (1);
308*0Sstevel@tonic-gate 	}
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate 	entp = (struct dirent *)xmalloc(MAXDIRENT);
311*0Sstevel@tonic-gate 	if (entp == NULL) {
312*0Sstevel@tonic-gate 		(void) closedir(dp);
313*0Sstevel@tonic-gate 		return (1);
314*0Sstevel@tonic-gate 	}
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	while ((dirp = readdir_r(dp, entp)) != (struct dirent *)NULL) {
317*0Sstevel@tonic-gate 		if (strcmp(dirp->d_name, ".") != 0 &&
318*0Sstevel@tonic-gate 			strcmp(dirp->d_name, "..") != 0) {
319*0Sstevel@tonic-gate 			if (strlen(path_dir) + strlen(dirp->d_name) +2 >
320*0Sstevel@tonic-gate 				MAXPATHLEN) {
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 				syslog(LOG_ERR,
323*0Sstevel@tonic-gate 		"statd: remove dir %s/%s failed.  Pathname too long.\n",
324*0Sstevel@tonic-gate 				path_dir, dirp->d_name);
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 				continue;
327*0Sstevel@tonic-gate 			}
328*0Sstevel@tonic-gate 			(void) strcpy(tmp_path, path_dir);
329*0Sstevel@tonic-gate 			(void) strcat(tmp_path, "/");
330*0Sstevel@tonic-gate 			(void) strcat(tmp_path, dirp->d_name);
331*0Sstevel@tonic-gate 			delete_file(tmp_path);
332*0Sstevel@tonic-gate 		}
333*0Sstevel@tonic-gate 	}
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 	free(entp);
336*0Sstevel@tonic-gate 	(void) closedir(dp);
337*0Sstevel@tonic-gate 	return (0);
338*0Sstevel@tonic-gate }
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate /*
341*0Sstevel@tonic-gate  * Copy all files from directory `from_dir' to directory `to_dir'.
342*0Sstevel@tonic-gate  * Symlinks, if any, are preserved.
343*0Sstevel@tonic-gate  */
344*0Sstevel@tonic-gate void
345*0Sstevel@tonic-gate copydir_from_to(from_dir, to_dir)
346*0Sstevel@tonic-gate char *from_dir;
347*0Sstevel@tonic-gate char *to_dir;
348*0Sstevel@tonic-gate {
349*0Sstevel@tonic-gate 	int	n;
350*0Sstevel@tonic-gate 	DIR	*dp;
351*0Sstevel@tonic-gate 	struct dirent   *dirp, *entp;
352*0Sstevel@tonic-gate 	char rname[MAXNAMELEN + 1];
353*0Sstevel@tonic-gate 	char path[MAXPATHLEN+MAXNAMELEN+2];
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 	if ((dp = opendir(from_dir)) == (DIR *)NULL) {
356*0Sstevel@tonic-gate 		if (debug)
357*0Sstevel@tonic-gate 		    syslog(LOG_ERR,
358*0Sstevel@tonic-gate 			"warning: open directory %s failed: %m\n", from_dir);
359*0Sstevel@tonic-gate 		return;
360*0Sstevel@tonic-gate 	}
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 	entp = (struct dirent *)xmalloc(MAXDIRENT);
363*0Sstevel@tonic-gate 	if (entp == NULL) {
364*0Sstevel@tonic-gate 		(void) closedir(dp);
365*0Sstevel@tonic-gate 		return;
366*0Sstevel@tonic-gate 	}
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 	while ((dirp = readdir_r(dp, entp)) != (struct dirent *)NULL) {
369*0Sstevel@tonic-gate 		if (strcmp(dirp->d_name, ".") == 0 ||
370*0Sstevel@tonic-gate 			strcmp(dirp->d_name, "..") == 0) {
371*0Sstevel@tonic-gate 			continue;
372*0Sstevel@tonic-gate 		}
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate 		(void) strcpy(path, from_dir);
375*0Sstevel@tonic-gate 		(void) strcat(path, "/");
376*0Sstevel@tonic-gate 		(void) strcat(path, dirp->d_name);
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 		if (is_symlink(path)) {
379*0Sstevel@tonic-gate 			/*
380*0Sstevel@tonic-gate 			 * Follow the link to get the referenced file name
381*0Sstevel@tonic-gate 			 * and make a new link for that file in to_dir.
382*0Sstevel@tonic-gate 			 */
383*0Sstevel@tonic-gate 			n = readlink(path, rname, MAXNAMELEN);
384*0Sstevel@tonic-gate 			if (n <= 0) {
385*0Sstevel@tonic-gate 				if (debug >= 2) {
386*0Sstevel@tonic-gate 				    (void) printf(
387*0Sstevel@tonic-gate 					"copydir_from_to: can't read link %s\n",
388*0Sstevel@tonic-gate 					path);
389*0Sstevel@tonic-gate 				}
390*0Sstevel@tonic-gate 				continue;
391*0Sstevel@tonic-gate 			}
392*0Sstevel@tonic-gate 			rname[n] = '\0';
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 			(void) create_symlink(to_dir, rname, dirp->d_name);
395*0Sstevel@tonic-gate 		} else {
396*0Sstevel@tonic-gate 			/*
397*0Sstevel@tonic-gate 			 * Simply copy regular files to to_dir.
398*0Sstevel@tonic-gate 			 */
399*0Sstevel@tonic-gate 			(void) strcpy(path, to_dir);
400*0Sstevel@tonic-gate 			(void) strcat(path, "/");
401*0Sstevel@tonic-gate 			(void) strcat(path, dirp->d_name);
402*0Sstevel@tonic-gate 			(void) create_file(path);
403*0Sstevel@tonic-gate 		}
404*0Sstevel@tonic-gate 	}
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate 	free(entp);
407*0Sstevel@tonic-gate 	(void) closedir(dp);
408*0Sstevel@tonic-gate }
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate static int
411*0Sstevel@tonic-gate init_hostname(void)
412*0Sstevel@tonic-gate {
413*0Sstevel@tonic-gate 	struct lifnum lifn;
414*0Sstevel@tonic-gate 	int sock;
415*0Sstevel@tonic-gate 
416*0Sstevel@tonic-gate 	if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
417*0Sstevel@tonic-gate 		syslog(LOG_ERR, "statd:init_hostname, socket: %m");
418*0Sstevel@tonic-gate 		return (-1);
419*0Sstevel@tonic-gate 	}
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate 	lifn.lifn_family = AF_UNSPEC;
422*0Sstevel@tonic-gate 	lifn.lifn_flags = 0;
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 	if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
425*0Sstevel@tonic-gate 		syslog(LOG_ERR,
426*0Sstevel@tonic-gate 		"statd:init_hostname, get number of interfaces, error: %m");
427*0Sstevel@tonic-gate 		close(sock);
428*0Sstevel@tonic-gate 		return (-1);
429*0Sstevel@tonic-gate 	}
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 	host_name_count = lifn.lifn_count;
432*0Sstevel@tonic-gate 
433*0Sstevel@tonic-gate 	host_name = (char **)malloc(host_name_count * sizeof (char *));
434*0Sstevel@tonic-gate 	if (host_name == NULL) {
435*0Sstevel@tonic-gate 		perror("statd -a can't get ip configuration\n");
436*0Sstevel@tonic-gate 		close(sock);
437*0Sstevel@tonic-gate 		return (-1);
438*0Sstevel@tonic-gate 	}
439*0Sstevel@tonic-gate 	close(sock);
440*0Sstevel@tonic-gate 	return (0);
441*0Sstevel@tonic-gate }
442*0Sstevel@tonic-gate 
443*0Sstevel@tonic-gate main(argc, argv)
444*0Sstevel@tonic-gate 	int argc;
445*0Sstevel@tonic-gate 	char **argv;
446*0Sstevel@tonic-gate {
447*0Sstevel@tonic-gate 	int c;
448*0Sstevel@tonic-gate 	int ppid;
449*0Sstevel@tonic-gate 	extern char *optarg;
450*0Sstevel@tonic-gate 	int choice = 0;
451*0Sstevel@tonic-gate 	struct rlimit rl;
452*0Sstevel@tonic-gate 	int mode;
453*0Sstevel@tonic-gate 	int sz;
454*0Sstevel@tonic-gate 	int connmaxrec = RPC_MAXDATASIZE;
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 	addrix = 0;
457*0Sstevel@tonic-gate 	pathix = 0;
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate 	(void) gethostname(hostname, MAXHOSTNAMELEN);
460*0Sstevel@tonic-gate 	if (init_hostname() < 0)
461*0Sstevel@tonic-gate 		exit(1);
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "Dd:a:p:r")) != EOF)
464*0Sstevel@tonic-gate 		switch (c) {
465*0Sstevel@tonic-gate 		case 'd':
466*0Sstevel@tonic-gate 			(void) sscanf(optarg, "%d", &debug);
467*0Sstevel@tonic-gate 			break;
468*0Sstevel@tonic-gate 		case 'D':
469*0Sstevel@tonic-gate 			choice = 1;
470*0Sstevel@tonic-gate 			break;
471*0Sstevel@tonic-gate 		case 'a':
472*0Sstevel@tonic-gate 			if (addrix < host_name_count) {
473*0Sstevel@tonic-gate 				if (strcmp(hostname, optarg) != 0) {
474*0Sstevel@tonic-gate 					sz = strlen(optarg);
475*0Sstevel@tonic-gate 					if (sz < MAXHOSTNAMELEN) {
476*0Sstevel@tonic-gate 						host_name[addrix] =
477*0Sstevel@tonic-gate 							(char *)xmalloc(sz+1);
478*0Sstevel@tonic-gate 						if (host_name[addrix] !=
479*0Sstevel@tonic-gate 						    NULL) {
480*0Sstevel@tonic-gate 						(void) sscanf(optarg, "%s",
481*0Sstevel@tonic-gate 							host_name[addrix]);
482*0Sstevel@tonic-gate 							addrix++;
483*0Sstevel@tonic-gate 						}
484*0Sstevel@tonic-gate 					} else
485*0Sstevel@tonic-gate 					(void) fprintf(stderr,
486*0Sstevel@tonic-gate 				    "statd: -a name of host is too long.\n");
487*0Sstevel@tonic-gate 				}
488*0Sstevel@tonic-gate 			} else
489*0Sstevel@tonic-gate 				(void) fprintf(stderr,
490*0Sstevel@tonic-gate 				    "statd: -a exceeding maximum hostnames\n");
491*0Sstevel@tonic-gate 			break;
492*0Sstevel@tonic-gate 		case 'p':
493*0Sstevel@tonic-gate 			if (strlen(optarg) < MAXPATHLEN) {
494*0Sstevel@tonic-gate 				/* If the path_name array has not yet	   */
495*0Sstevel@tonic-gate 				/* been malloc'ed, do that.  The array	   */
496*0Sstevel@tonic-gate 				/* should be big enough to hold all of the */
497*0Sstevel@tonic-gate 				/* -p options we might have.  An upper	   */
498*0Sstevel@tonic-gate 				/* bound on the number of -p options is	   */
499*0Sstevel@tonic-gate 				/* argc/2, because each -p option consumes */
500*0Sstevel@tonic-gate 				/* two arguments.  Here the upper bound	   */
501*0Sstevel@tonic-gate 				/* is supposing that all the command line  */
502*0Sstevel@tonic-gate 				/* arguments are -p options, which would   */
503*0Sstevel@tonic-gate 				/* actually never be the case.		   */
504*0Sstevel@tonic-gate 				if (path_name == NULL) {
505*0Sstevel@tonic-gate 					size_t sz = (argc/2) * sizeof (char *);
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 					path_name = (char **)malloc(sz);
508*0Sstevel@tonic-gate 					if (path_name == NULL) {
509*0Sstevel@tonic-gate 						(void) fprintf(stderr,
510*0Sstevel@tonic-gate 						"statd: malloc failed\n");
511*0Sstevel@tonic-gate 						exit(1);
512*0Sstevel@tonic-gate 					}
513*0Sstevel@tonic-gate 					(void) memset(path_name, 0, sz);
514*0Sstevel@tonic-gate 				}
515*0Sstevel@tonic-gate 				path_name[pathix] = optarg;
516*0Sstevel@tonic-gate 				pathix++;
517*0Sstevel@tonic-gate 			} else {
518*0Sstevel@tonic-gate 				(void) fprintf(stderr,
519*0Sstevel@tonic-gate 				"statd: -p pathname is too long.\n");
520*0Sstevel@tonic-gate 			}
521*0Sstevel@tonic-gate 			break;
522*0Sstevel@tonic-gate 		case 'r':
523*0Sstevel@tonic-gate 			regfiles_only = 1;
524*0Sstevel@tonic-gate 			break;
525*0Sstevel@tonic-gate 		default:
526*0Sstevel@tonic-gate 			(void) fprintf(stderr,
527*0Sstevel@tonic-gate 			"statd [-d level] [-D]\n");
528*0Sstevel@tonic-gate 			return (1);
529*0Sstevel@tonic-gate 		}
530*0Sstevel@tonic-gate 
531*0Sstevel@tonic-gate 	if (choice == 0) {
532*0Sstevel@tonic-gate 		(void) strcpy(statd_home, home0);
533*0Sstevel@tonic-gate 		(void) strcpy(CURRENT, current0);
534*0Sstevel@tonic-gate 		(void) strcpy(BACKUP, backup0);
535*0Sstevel@tonic-gate 		(void) strcpy(STATE, state0);
536*0Sstevel@tonic-gate 	} else {
537*0Sstevel@tonic-gate 		(void) strcpy(statd_home, home1);
538*0Sstevel@tonic-gate 		(void) strcpy(CURRENT, current1);
539*0Sstevel@tonic-gate 		(void) strcpy(BACKUP, backup1);
540*0Sstevel@tonic-gate 		(void) strcpy(STATE, state1);
541*0Sstevel@tonic-gate 	}
542*0Sstevel@tonic-gate 	if (debug)
543*0Sstevel@tonic-gate 		(void) printf("debug is on, create entry: %s, %s, %s\n",
544*0Sstevel@tonic-gate 			CURRENT, BACKUP, STATE);
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 	if (getrlimit(RLIMIT_NOFILE, &rl))
547*0Sstevel@tonic-gate 		(void) printf("statd: getrlimit failed. \n");
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate 	/* Set maxfdlimit current soft limit */
550*0Sstevel@tonic-gate 	rl.rlim_cur = MAX_FDS;
551*0Sstevel@tonic-gate 	if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
552*0Sstevel@tonic-gate 		syslog(LOG_ERR, "statd: unable to set RLIMIT_NOFILE to %d\n",
553*0Sstevel@tonic-gate 			MAX_FDS);
554*0Sstevel@tonic-gate 
555*0Sstevel@tonic-gate 	if (!debug) {
556*0Sstevel@tonic-gate 		ppid = fork();
557*0Sstevel@tonic-gate 		if (ppid == -1) {
558*0Sstevel@tonic-gate 			(void) fprintf(stderr, "statd: fork failure\n");
559*0Sstevel@tonic-gate 			(void) fflush(stderr);
560*0Sstevel@tonic-gate 			abort();
561*0Sstevel@tonic-gate 		}
562*0Sstevel@tonic-gate 		if (ppid != 0) {
563*0Sstevel@tonic-gate 			exit(0);
564*0Sstevel@tonic-gate 		}
565*0Sstevel@tonic-gate 		closefrom(0);
566*0Sstevel@tonic-gate 		(void) open("/dev/null", O_RDONLY);
567*0Sstevel@tonic-gate 		(void) open("/dev/null", O_WRONLY);
568*0Sstevel@tonic-gate 		(void) dup(1);
569*0Sstevel@tonic-gate 		(void) setsid();
570*0Sstevel@tonic-gate 		openlog("statd", LOG_PID, LOG_DAEMON);
571*0Sstevel@tonic-gate 	}
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate 	(void) _create_daemon_lock(STATD, DAEMON_UID, DAEMON_GID);
574*0Sstevel@tonic-gate 	/*
575*0Sstevel@tonic-gate 	 * establish our lock on the lock file and write our pid to it.
576*0Sstevel@tonic-gate 	 * exit if some other process holds the lock, or if there's any
577*0Sstevel@tonic-gate 	 * error in writing/locking the file.
578*0Sstevel@tonic-gate 	 */
579*0Sstevel@tonic-gate 	ppid = _enter_daemon_lock(STATD);
580*0Sstevel@tonic-gate 	switch (ppid) {
581*0Sstevel@tonic-gate 	case 0:
582*0Sstevel@tonic-gate 		break;
583*0Sstevel@tonic-gate 	case -1:
584*0Sstevel@tonic-gate 		syslog(LOG_ERR, "error locking for %s: %s", STATD,
585*0Sstevel@tonic-gate 		    strerror(errno));
586*0Sstevel@tonic-gate 		exit(2);
587*0Sstevel@tonic-gate 	default:
588*0Sstevel@tonic-gate 		/* daemon was already running */
589*0Sstevel@tonic-gate 		exit(0);
590*0Sstevel@tonic-gate 	}
591*0Sstevel@tonic-gate 
592*0Sstevel@tonic-gate 	/* Get other aliases from each interface. */
593*0Sstevel@tonic-gate 	merge_hosts();
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate 	/*
596*0Sstevel@tonic-gate 	 * Set to automatic mode such that threads are automatically
597*0Sstevel@tonic-gate 	 * created
598*0Sstevel@tonic-gate 	 */
599*0Sstevel@tonic-gate 	mode = RPC_SVC_MT_AUTO;
600*0Sstevel@tonic-gate 	if (!rpc_control(RPC_SVC_MTMODE_SET, &mode)) {
601*0Sstevel@tonic-gate 		syslog(LOG_ERR,
602*0Sstevel@tonic-gate 			"statd:unable to set automatic MT mode.");
603*0Sstevel@tonic-gate 		exit(1);
604*0Sstevel@tonic-gate 	}
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate 	/*
607*0Sstevel@tonic-gate 	 * Set non-blocking mode and maximum record size for
608*0Sstevel@tonic-gate 	 * connection oriented RPC transports.
609*0Sstevel@tonic-gate 	 */
610*0Sstevel@tonic-gate 	if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
611*0Sstevel@tonic-gate 		syslog(LOG_INFO, "unable to set maximum RPC record size");
612*0Sstevel@tonic-gate 	}
613*0Sstevel@tonic-gate 
614*0Sstevel@tonic-gate 	if (!svc_create(sm_prog_1, SM_PROG, SM_VERS, "netpath")) {
615*0Sstevel@tonic-gate 	    syslog(LOG_ERR,
616*0Sstevel@tonic-gate 		"statd: unable to create (SM_PROG, SM_VERS) for netpath.");
617*0Sstevel@tonic-gate 	    exit(1);
618*0Sstevel@tonic-gate 	}
619*0Sstevel@tonic-gate 
620*0Sstevel@tonic-gate 	if (!svc_create(sm_prog_1, NSM_ADDR_PROGRAM, NSM_ADDR_V1, "netpath")) {
621*0Sstevel@tonic-gate 	    syslog(LOG_ERR,
622*0Sstevel@tonic-gate 	"statd: unable to create (NSM_ADDR_PROGRAM, NSM_ADDR_V1) for netpath.");
623*0Sstevel@tonic-gate 	}
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 	/*
626*0Sstevel@tonic-gate 	 * Make sure /var/statmon and any alternate (-p) statmon
627*0Sstevel@tonic-gate 	 * directories exist and are owned by daemon.  Then change our uid
628*0Sstevel@tonic-gate 	 * to daemon.  The uid change is to prevent attacks against local
629*0Sstevel@tonic-gate 	 * daemons that trust any call from a local root process.
630*0Sstevel@tonic-gate 	 */
631*0Sstevel@tonic-gate 
632*0Sstevel@tonic-gate 	set_statmon_owner();
633*0Sstevel@tonic-gate 
634*0Sstevel@tonic-gate 	/*
635*0Sstevel@tonic-gate 	 *
636*0Sstevel@tonic-gate 	 * statd now runs as a daemon rather than root and can not
637*0Sstevel@tonic-gate 	 * dump core under / because of the permission. It is
638*0Sstevel@tonic-gate 	 * important that current working directory of statd be
639*0Sstevel@tonic-gate 	 * changed to writable directory /var/statmon so that it
640*0Sstevel@tonic-gate 	 * can dump the core upon the receipt of the signal.
641*0Sstevel@tonic-gate 	 * One still need to set allow_setid_core to non-zero in
642*0Sstevel@tonic-gate 	 * /etc/system to get the core dump.
643*0Sstevel@tonic-gate 	 *
644*0Sstevel@tonic-gate 	 */
645*0Sstevel@tonic-gate 
646*0Sstevel@tonic-gate 	if (chdir(statd_home) < 0) {
647*0Sstevel@tonic-gate 		syslog(LOG_ERR, "can't chdir %s: %m", statd_home);
648*0Sstevel@tonic-gate 		exit(1);
649*0Sstevel@tonic-gate 	}
650*0Sstevel@tonic-gate 
651*0Sstevel@tonic-gate 	copy_client_names();
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 	rwlock_init(&thr_rwlock, USYNC_THREAD, NULL);
654*0Sstevel@tonic-gate 	mutex_init(&crash_lock, USYNC_THREAD, NULL);
655*0Sstevel@tonic-gate 	mutex_init(&name_addrlock, USYNC_THREAD, NULL);
656*0Sstevel@tonic-gate 	cond_init(&crash_finish, USYNC_THREAD, NULL);
657*0Sstevel@tonic-gate 	cond_init(&retrywait, USYNC_THREAD, NULL);
658*0Sstevel@tonic-gate 	sm_inithash();
659*0Sstevel@tonic-gate 	die = 0;
660*0Sstevel@tonic-gate 	/*
661*0Sstevel@tonic-gate 	 * This variable is set to ensure that an sm_crash
662*0Sstevel@tonic-gate 	 * request will not be done at the same time
663*0Sstevel@tonic-gate 	 * when a statd_init is being done, since sm_crash
664*0Sstevel@tonic-gate 	 * can reset some variables that statd_init will be using.
665*0Sstevel@tonic-gate 	 */
666*0Sstevel@tonic-gate 	in_crash = 1;
667*0Sstevel@tonic-gate 	statd_init();
668*0Sstevel@tonic-gate 
669*0Sstevel@tonic-gate 	if (debug)
670*0Sstevel@tonic-gate 		(void) printf("Starting svc_run\n");
671*0Sstevel@tonic-gate 	svc_run();
672*0Sstevel@tonic-gate 	syslog(LOG_ERR, "statd: svc_run returned\n");
673*0Sstevel@tonic-gate 	/* NOTREACHED */
674*0Sstevel@tonic-gate 	thr_exit((void *) 1);
675*0Sstevel@tonic-gate 
676*0Sstevel@tonic-gate }
677*0Sstevel@tonic-gate 
678*0Sstevel@tonic-gate /*
679*0Sstevel@tonic-gate  * Make sure the ownership of the statmon directories is correct, then
680*0Sstevel@tonic-gate  * change our uid to match.  If the top-level directories (/var/statmon, -p
681*0Sstevel@tonic-gate  * arguments) don't exist, they are created first.  The sm and sm.bak
682*0Sstevel@tonic-gate  * directories are not created here, but if they already exist, they are
683*0Sstevel@tonic-gate  * chowned to the correct uid, along with anything else in the
684*0Sstevel@tonic-gate  * directories.
685*0Sstevel@tonic-gate  */
686*0Sstevel@tonic-gate 
687*0Sstevel@tonic-gate static void
688*0Sstevel@tonic-gate set_statmon_owner()
689*0Sstevel@tonic-gate {
690*0Sstevel@tonic-gate 	int i;
691*0Sstevel@tonic-gate 
692*0Sstevel@tonic-gate 	/*
693*0Sstevel@tonic-gate 	 * Recursively chown/chgrp /var/statmon and the alternate paths,
694*0Sstevel@tonic-gate 	 * creating them if necessary.
695*0Sstevel@tonic-gate 	 */
696*0Sstevel@tonic-gate 	one_statmon_owner(statd_home);
697*0Sstevel@tonic-gate 	for (i = 0; i < pathix; i++) {
698*0Sstevel@tonic-gate 		char alt_path[MAXPATHLEN];
699*0Sstevel@tonic-gate 
700*0Sstevel@tonic-gate 		snprintf(alt_path, MAXPATHLEN, "%s/statmon", path_name[i]);
701*0Sstevel@tonic-gate 		one_statmon_owner(alt_path);
702*0Sstevel@tonic-gate 	}
703*0Sstevel@tonic-gate 
704*0Sstevel@tonic-gate 	if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET,
705*0Sstevel@tonic-gate 	    DAEMON_UID, DAEMON_GID, (char *)NULL) == -1) {
706*0Sstevel@tonic-gate 		syslog(LOG_ERR, "can't run unprivileged: %m");
707*0Sstevel@tonic-gate 		exit(1);
708*0Sstevel@tonic-gate 	}
709*0Sstevel@tonic-gate 
710*0Sstevel@tonic-gate 	__fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_SESSION,
711*0Sstevel@tonic-gate 	    PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
712*0Sstevel@tonic-gate }
713*0Sstevel@tonic-gate 
714*0Sstevel@tonic-gate /*
715*0Sstevel@tonic-gate  * Copy client names from the alternate statmon directories into
716*0Sstevel@tonic-gate  * /var/statmon.  The top-level (statmon) directories should already
717*0Sstevel@tonic-gate  * exist, though the sm and sm.bak directories might not.
718*0Sstevel@tonic-gate  */
719*0Sstevel@tonic-gate 
720*0Sstevel@tonic-gate static void
721*0Sstevel@tonic-gate copy_client_names()
722*0Sstevel@tonic-gate {
723*0Sstevel@tonic-gate 	int i;
724*0Sstevel@tonic-gate 	char buf[MAXPATHLEN+SM_MAXPATHLEN];
725*0Sstevel@tonic-gate 
726*0Sstevel@tonic-gate 	/*
727*0Sstevel@tonic-gate 	 * Copy all clients from alternate paths to /var/statmon/sm
728*0Sstevel@tonic-gate 	 * Remove the files in alternate directory when copying is done.
729*0Sstevel@tonic-gate 	 */
730*0Sstevel@tonic-gate 	for (i = 0; i < pathix; i++) {
731*0Sstevel@tonic-gate 		/*
732*0Sstevel@tonic-gate 		 * If the alternate directories do not exist, create it.
733*0Sstevel@tonic-gate 		 * If they do exist, just do the copy.
734*0Sstevel@tonic-gate 		 */
735*0Sstevel@tonic-gate 		snprintf(buf, sizeof (buf), "%s/statmon/sm", path_name[i]);
736*0Sstevel@tonic-gate 		if ((mkdir(buf, SM_DIRECTORY_MODE)) == -1) {
737*0Sstevel@tonic-gate 			if (errno != EEXIST) {
738*0Sstevel@tonic-gate 				syslog(LOG_ERR,
739*0Sstevel@tonic-gate 					"can't mkdir %s: %m\n", buf);
740*0Sstevel@tonic-gate 				continue;
741*0Sstevel@tonic-gate 			}
742*0Sstevel@tonic-gate 			copydir_from_to(buf, CURRENT);
743*0Sstevel@tonic-gate 			(void) remove_dir(buf);
744*0Sstevel@tonic-gate 		}
745*0Sstevel@tonic-gate 
746*0Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "%s/statmon/sm.bak",
747*0Sstevel@tonic-gate 				path_name[i]);
748*0Sstevel@tonic-gate 		if ((mkdir(buf, SM_DIRECTORY_MODE)) == -1) {
749*0Sstevel@tonic-gate 			if (errno != EEXIST) {
750*0Sstevel@tonic-gate 				syslog(LOG_ERR,
751*0Sstevel@tonic-gate 					"can't mkdir %s: %m\n", buf);
752*0Sstevel@tonic-gate 				continue;
753*0Sstevel@tonic-gate 			}
754*0Sstevel@tonic-gate 			copydir_from_to(buf, BACKUP);
755*0Sstevel@tonic-gate 			(void) remove_dir(buf);
756*0Sstevel@tonic-gate 		}
757*0Sstevel@tonic-gate 	}
758*0Sstevel@tonic-gate }
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate /*
761*0Sstevel@tonic-gate  * Create the given directory if it doesn't already exist.  Set the user
762*0Sstevel@tonic-gate  * and group to daemon for the directory and anything under it.
763*0Sstevel@tonic-gate  */
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate static void
766*0Sstevel@tonic-gate one_statmon_owner(const char *dir)
767*0Sstevel@tonic-gate {
768*0Sstevel@tonic-gate 	if ((mkdir(dir, SM_DIRECTORY_MODE)) == -1) {
769*0Sstevel@tonic-gate 		if (errno != EEXIST) {
770*0Sstevel@tonic-gate 			syslog(LOG_ERR, "can't mkdir %s: %m",
771*0Sstevel@tonic-gate 			    dir);
772*0Sstevel@tonic-gate 			return;
773*0Sstevel@tonic-gate 		}
774*0Sstevel@tonic-gate 	}
775*0Sstevel@tonic-gate 
776*0Sstevel@tonic-gate 	if (debug)
777*0Sstevel@tonic-gate 		printf("Setting owner for %s\n", dir);
778*0Sstevel@tonic-gate 
779*0Sstevel@tonic-gate 	if (nftw(dir, nftw_owner, MAX_FDS, FTW_PHYS) != 0) {
780*0Sstevel@tonic-gate 		syslog(LOG_WARNING, "error setting owner for %s: %m",
781*0Sstevel@tonic-gate 		    dir);
782*0Sstevel@tonic-gate 	}
783*0Sstevel@tonic-gate }
784*0Sstevel@tonic-gate 
785*0Sstevel@tonic-gate /*
786*0Sstevel@tonic-gate  * Set the user and group to daemon for the given file or directory.  If
787*0Sstevel@tonic-gate  * it's a directory, also makes sure that it is mode 755.
788*0Sstevel@tonic-gate  * Generates a syslog message but does not return an error if there were
789*0Sstevel@tonic-gate  * problems.
790*0Sstevel@tonic-gate  */
791*0Sstevel@tonic-gate 
792*0Sstevel@tonic-gate /*ARGSUSED3*/
793*0Sstevel@tonic-gate static int
794*0Sstevel@tonic-gate nftw_owner(const char *path, const struct stat *statp, int info,
795*0Sstevel@tonic-gate 	struct FTW *ftw)
796*0Sstevel@tonic-gate {
797*0Sstevel@tonic-gate 	if (!(info == FTW_F || info == FTW_D))
798*0Sstevel@tonic-gate 		return (0);
799*0Sstevel@tonic-gate 
800*0Sstevel@tonic-gate 	/*
801*0Sstevel@tonic-gate 	 * Some older systems might have mode 777 directories.  Fix that.
802*0Sstevel@tonic-gate 	 */
803*0Sstevel@tonic-gate 
804*0Sstevel@tonic-gate 	if (info == FTW_D && (statp->st_mode & (S_IWGRP | S_IWOTH)) != 0) {
805*0Sstevel@tonic-gate 		mode_t newmode = (statp->st_mode & ~(S_IWGRP | S_IWOTH)) &
806*0Sstevel@tonic-gate 			S_IAMB;
807*0Sstevel@tonic-gate 
808*0Sstevel@tonic-gate 		if (debug)
809*0Sstevel@tonic-gate 			printf("chmod %03o %s\n", newmode, path);
810*0Sstevel@tonic-gate 		if (chmod(path, newmode) < 0) {
811*0Sstevel@tonic-gate 			int error = errno;
812*0Sstevel@tonic-gate 
813*0Sstevel@tonic-gate 			syslog(LOG_WARNING, "can't chmod %s to %03o: %m",
814*0Sstevel@tonic-gate 			    path, newmode);
815*0Sstevel@tonic-gate 			if (debug)
816*0Sstevel@tonic-gate 				printf("  FAILED: %s\n", strerror(error));
817*0Sstevel@tonic-gate 		}
818*0Sstevel@tonic-gate 	}
819*0Sstevel@tonic-gate 
820*0Sstevel@tonic-gate 	/* If already owned by daemon, don't bother changing. */
821*0Sstevel@tonic-gate 	if (statp->st_uid == DAEMON_UID &&
822*0Sstevel@tonic-gate 	    statp->st_gid == DAEMON_GID)
823*0Sstevel@tonic-gate 		return (0);
824*0Sstevel@tonic-gate 
825*0Sstevel@tonic-gate 	if (debug)
826*0Sstevel@tonic-gate 		printf("lchown %s daemon:daemon\n", path);
827*0Sstevel@tonic-gate 	if (lchown(path, DAEMON_UID, DAEMON_GID) < 0) {
828*0Sstevel@tonic-gate 		int error = errno;
829*0Sstevel@tonic-gate 
830*0Sstevel@tonic-gate 		syslog(LOG_WARNING, "can't chown %s to daemon: %m",
831*0Sstevel@tonic-gate 		    path);
832*0Sstevel@tonic-gate 		if (debug)
833*0Sstevel@tonic-gate 			printf("  FAILED: %s\n", strerror(error));
834*0Sstevel@tonic-gate 	}
835*0Sstevel@tonic-gate 
836*0Sstevel@tonic-gate 	return (0);
837*0Sstevel@tonic-gate }
838