xref: /titanic_44/usr/src/cmd/filesync/main.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 1995-2003 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*
28*7c478bd9Sstevel@tonic-gate  * module:
29*7c478bd9Sstevel@tonic-gate  *	main.c
30*7c478bd9Sstevel@tonic-gate  *
31*7c478bd9Sstevel@tonic-gate  * purpose:
32*7c478bd9Sstevel@tonic-gate  *	argument handling and top level dispatch
33*7c478bd9Sstevel@tonic-gate  *
34*7c478bd9Sstevel@tonic-gate  * contents:
35*7c478bd9Sstevel@tonic-gate  *	main		argument handling and main loop
36*7c478bd9Sstevel@tonic-gate  *	usage		(static) print out usage message
37*7c478bd9Sstevel@tonic-gate  *	confirm		prompt the user for a confirmation and get it
38*7c478bd9Sstevel@tonic-gate  *	nomem		fatal error handler for malloc failures
39*7c478bd9Sstevel@tonic-gate  *	findfiles	(static) locate our baseline and rules files
40*7c478bd9Sstevel@tonic-gate  *	cleanup		(static) unlock baseline and delete temp file
41*7c478bd9Sstevel@tonic-gate  *	check_access	(static) do we have adequate access to a file/directory
42*7c478bd9Sstevel@tonic-gate  *	whoami		(static) get uid/gid/umask
43*7c478bd9Sstevel@tonic-gate  */
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate #include <unistd.h>
48*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
49*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
50*7c478bd9Sstevel@tonic-gate #include <stdio.h>
51*7c478bd9Sstevel@tonic-gate #include <string.h>
52*7c478bd9Sstevel@tonic-gate #include <ctype.h>
53*7c478bd9Sstevel@tonic-gate #include <errno.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate #include "filesync.h"
57*7c478bd9Sstevel@tonic-gate #include "database.h"
58*7c478bd9Sstevel@tonic-gate #include "messages.h"
59*7c478bd9Sstevel@tonic-gate #include "debug.h"
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate /*
62*7c478bd9Sstevel@tonic-gate  * local routines in this module:
63*7c478bd9Sstevel@tonic-gate  */
64*7c478bd9Sstevel@tonic-gate static errmask_t findfiles();		/* find rule and baseline files	*/
65*7c478bd9Sstevel@tonic-gate static void cleanup(int);		/* cleanup locks and temps	*/
66*7c478bd9Sstevel@tonic-gate static errmask_t check_access(char *, int *); /* check access to file	*/
67*7c478bd9Sstevel@tonic-gate static void whoami();			/* gather information about me	*/
68*7c478bd9Sstevel@tonic-gate static void usage(void);		/* general usage		*/
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate /*
72*7c478bd9Sstevel@tonic-gate  * globals exported to the rest of the program
73*7c478bd9Sstevel@tonic-gate  */
74*7c478bd9Sstevel@tonic-gate bool_t	opt_mtime;	/* preserve modification times on propagations	*/
75*7c478bd9Sstevel@tonic-gate bool_t	opt_notouch;	/* don't actually make any changes		*/
76*7c478bd9Sstevel@tonic-gate bool_t	opt_quiet;	/* disable reconciliation command output	*/
77*7c478bd9Sstevel@tonic-gate bool_t	opt_verbose;	/* enable analysis descriptions			*/
78*7c478bd9Sstevel@tonic-gate side_t	opt_force;	/* designated winner for conflicts		*/
79*7c478bd9Sstevel@tonic-gate side_t	opt_oneway;	/* one way only propagation			*/
80*7c478bd9Sstevel@tonic-gate side_t	opt_onesided;	/* permit one-sided evaluation			*/
81*7c478bd9Sstevel@tonic-gate bool_t	opt_everything;	/* everything must agree (modes/uid/gid)	*/
82*7c478bd9Sstevel@tonic-gate bool_t	opt_yes;	/* pre-confirm massive deletions are OK		*/
83*7c478bd9Sstevel@tonic-gate bool_t	opt_acls;	/* always scan for acls on all files		*/
84*7c478bd9Sstevel@tonic-gate bool_t	opt_errors;	/* simulate errors on specified files		*/
85*7c478bd9Sstevel@tonic-gate bool_t	opt_halt;	/* halt on propagation errors			*/
86*7c478bd9Sstevel@tonic-gate dbgmask_t opt_debug;	/* debug mask					*/
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate uid_t	my_uid;		/* default UID for files I create		*/
89*7c478bd9Sstevel@tonic-gate gid_t	my_gid;		/* default GID for files I create		*/
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate static char *file_rules; /* name of rules file				*/
92*7c478bd9Sstevel@tonic-gate static char *file_base;	/* name of baseline file			*/
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate static int new_baseline; /* are we creating a new baseline		*/
95*7c478bd9Sstevel@tonic-gate static int new_rules;	/* are we creating a new rules file		*/
96*7c478bd9Sstevel@tonic-gate static int my_umask;	/* default UMASK for files I create		*/
97*7c478bd9Sstevel@tonic-gate static int lockfd;	/* file descriptor for locking baseline		*/
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate static char *rlist[MAX_RLIST];
100*7c478bd9Sstevel@tonic-gate static int num_restrs = 0;
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate /*
103*7c478bd9Sstevel@tonic-gate  * routine:
104*7c478bd9Sstevel@tonic-gate  *	main
105*7c478bd9Sstevel@tonic-gate  *
106*7c478bd9Sstevel@tonic-gate  * purpose:
107*7c478bd9Sstevel@tonic-gate  *	argument processing and primary dispatch
108*7c478bd9Sstevel@tonic-gate  *
109*7c478bd9Sstevel@tonic-gate  * returns:
110*7c478bd9Sstevel@tonic-gate  *	error codes per filesync.1 (ERR_* in filesync.h)
111*7c478bd9Sstevel@tonic-gate  *
112*7c478bd9Sstevel@tonic-gate  * notes:
113*7c478bd9Sstevel@tonic-gate  *	read filesync.1 in order to understand the argument processing
114*7c478bd9Sstevel@tonic-gate  *
115*7c478bd9Sstevel@tonic-gate  *	most of the command line options just set some opt_ global
116*7c478bd9Sstevel@tonic-gate  *	variable that is later looked at by the code that actually
117*7c478bd9Sstevel@tonic-gate  *	implements the features.  Only file names are really processed
118*7c478bd9Sstevel@tonic-gate  *	in this routine.
119*7c478bd9Sstevel@tonic-gate  */
120*7c478bd9Sstevel@tonic-gate void
121*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
122*7c478bd9Sstevel@tonic-gate {	int i;
123*7c478bd9Sstevel@tonic-gate 	int c;
124*7c478bd9Sstevel@tonic-gate 	errmask_t errs = ERR_OK;
125*7c478bd9Sstevel@tonic-gate 	int do_prune = 0;
126*7c478bd9Sstevel@tonic-gate 	char *srcname = 0;
127*7c478bd9Sstevel@tonic-gate 	char *dstname = 0;
128*7c478bd9Sstevel@tonic-gate 	struct base *bp;
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	/* keep the error messages simple	*/
131*7c478bd9Sstevel@tonic-gate 	argv[0] = "filesync";
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	/* gather together all of the options	*/
134*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "AaehmnqvyD:E:r:s:d:f:o:")) != EOF)
135*7c478bd9Sstevel@tonic-gate 		switch (c) {
136*7c478bd9Sstevel@tonic-gate 			case 'a':	/* always scan for acls	*/
137*7c478bd9Sstevel@tonic-gate 				opt_acls = TRUE;
138*7c478bd9Sstevel@tonic-gate 				break;
139*7c478bd9Sstevel@tonic-gate 			case 'e':	/* everything agrees	*/
140*7c478bd9Sstevel@tonic-gate 				opt_everything = TRUE;
141*7c478bd9Sstevel@tonic-gate 				break;
142*7c478bd9Sstevel@tonic-gate 			case 'h':	/* halt on error	*/
143*7c478bd9Sstevel@tonic-gate 				opt_halt = TRUE;
144*7c478bd9Sstevel@tonic-gate 				break;
145*7c478bd9Sstevel@tonic-gate 			case 'm':	/* preserve modtimes	*/
146*7c478bd9Sstevel@tonic-gate 				opt_mtime = TRUE;
147*7c478bd9Sstevel@tonic-gate 				break;
148*7c478bd9Sstevel@tonic-gate 			case 'n':	/* notouch		*/
149*7c478bd9Sstevel@tonic-gate 				opt_notouch = TRUE;
150*7c478bd9Sstevel@tonic-gate 				break;
151*7c478bd9Sstevel@tonic-gate 			case 'q':	/* quiet		*/
152*7c478bd9Sstevel@tonic-gate 				opt_quiet = TRUE;
153*7c478bd9Sstevel@tonic-gate 				break;
154*7c478bd9Sstevel@tonic-gate 			case 'v':	/* verbose		*/
155*7c478bd9Sstevel@tonic-gate 				opt_verbose = TRUE;
156*7c478bd9Sstevel@tonic-gate 				break;
157*7c478bd9Sstevel@tonic-gate 			case 'y':	/* yes			*/
158*7c478bd9Sstevel@tonic-gate 				opt_yes = TRUE;
159*7c478bd9Sstevel@tonic-gate 				break;
160*7c478bd9Sstevel@tonic-gate 			case 'D':	/* debug options	*/
161*7c478bd9Sstevel@tonic-gate 				if (!isdigit(optarg[0])) {
162*7c478bd9Sstevel@tonic-gate 					dbg_usage();
163*7c478bd9Sstevel@tonic-gate 					exit(ERR_INVAL);
164*7c478bd9Sstevel@tonic-gate 				}
165*7c478bd9Sstevel@tonic-gate 				opt_debug |= strtol(optarg, (char **) NULL, 0);
166*7c478bd9Sstevel@tonic-gate 				break;
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate 			case 'E':	/* error simulation	*/
169*7c478bd9Sstevel@tonic-gate 				if (dbg_set_error(optarg)) {
170*7c478bd9Sstevel@tonic-gate 					err_usage();
171*7c478bd9Sstevel@tonic-gate 					exit(ERR_INVAL);
172*7c478bd9Sstevel@tonic-gate 				}
173*7c478bd9Sstevel@tonic-gate 				opt_errors = TRUE;
174*7c478bd9Sstevel@tonic-gate 				break;
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 			case 'f':	/* force conflict resolution	*/
177*7c478bd9Sstevel@tonic-gate 				switch (optarg[0]) {
178*7c478bd9Sstevel@tonic-gate 					case 's':
179*7c478bd9Sstevel@tonic-gate 						opt_force = OPT_SRC;
180*7c478bd9Sstevel@tonic-gate 						break;
181*7c478bd9Sstevel@tonic-gate 					case 'd':
182*7c478bd9Sstevel@tonic-gate 						opt_force = OPT_DST;
183*7c478bd9Sstevel@tonic-gate 						break;
184*7c478bd9Sstevel@tonic-gate 					case 'o':
185*7c478bd9Sstevel@tonic-gate 						opt_force = OPT_OLD;
186*7c478bd9Sstevel@tonic-gate 						break;
187*7c478bd9Sstevel@tonic-gate 					case 'n':
188*7c478bd9Sstevel@tonic-gate 						opt_force = OPT_NEW;
189*7c478bd9Sstevel@tonic-gate 						break;
190*7c478bd9Sstevel@tonic-gate 					default:
191*7c478bd9Sstevel@tonic-gate 						fprintf(stderr,
192*7c478bd9Sstevel@tonic-gate 							gettext(ERR_badopt),
193*7c478bd9Sstevel@tonic-gate 							c, optarg);
194*7c478bd9Sstevel@tonic-gate 						errs |= ERR_INVAL;
195*7c478bd9Sstevel@tonic-gate 						break;
196*7c478bd9Sstevel@tonic-gate 				}
197*7c478bd9Sstevel@tonic-gate 				break;
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate 			case 'o':	/* one way propagation		*/
200*7c478bd9Sstevel@tonic-gate 				switch (optarg[0]) {
201*7c478bd9Sstevel@tonic-gate 					case 's':
202*7c478bd9Sstevel@tonic-gate 						opt_oneway = OPT_SRC;
203*7c478bd9Sstevel@tonic-gate 						break;
204*7c478bd9Sstevel@tonic-gate 					case 'd':
205*7c478bd9Sstevel@tonic-gate 						opt_oneway = OPT_DST;
206*7c478bd9Sstevel@tonic-gate 						break;
207*7c478bd9Sstevel@tonic-gate 					default:
208*7c478bd9Sstevel@tonic-gate 						fprintf(stderr,
209*7c478bd9Sstevel@tonic-gate 							gettext(ERR_badopt),
210*7c478bd9Sstevel@tonic-gate 							c, optarg);
211*7c478bd9Sstevel@tonic-gate 						errs |= ERR_INVAL;
212*7c478bd9Sstevel@tonic-gate 						break;
213*7c478bd9Sstevel@tonic-gate 				}
214*7c478bd9Sstevel@tonic-gate 				break;
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 			case 'r':	/* restricted reconciliation	*/
217*7c478bd9Sstevel@tonic-gate 				if (num_restrs < MAX_RLIST)
218*7c478bd9Sstevel@tonic-gate 					rlist[ num_restrs++ ] = optarg;
219*7c478bd9Sstevel@tonic-gate 				else {
220*7c478bd9Sstevel@tonic-gate 					fprintf(stderr, gettext(ERR_tomany),
221*7c478bd9Sstevel@tonic-gate 						MAX_RLIST);
222*7c478bd9Sstevel@tonic-gate 					errs |= ERR_INVAL;
223*7c478bd9Sstevel@tonic-gate 				}
224*7c478bd9Sstevel@tonic-gate 				break;
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 			case 's':
227*7c478bd9Sstevel@tonic-gate 				if ((srcname = qualify(optarg)) == 0)
228*7c478bd9Sstevel@tonic-gate 					errs |= ERR_MISSING;
229*7c478bd9Sstevel@tonic-gate 				break;
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 			case 'd':
232*7c478bd9Sstevel@tonic-gate 				if ((dstname = qualify(optarg)) == 0)
233*7c478bd9Sstevel@tonic-gate 					errs |= ERR_MISSING;
234*7c478bd9Sstevel@tonic-gate 				break;
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 			default:
237*7c478bd9Sstevel@tonic-gate 			case '?':
238*7c478bd9Sstevel@tonic-gate 				errs |= ERR_INVAL;
239*7c478bd9Sstevel@tonic-gate 				break;
240*7c478bd9Sstevel@tonic-gate 		}
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	if (opt_debug & DBG_MISC)
243*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "MISC: DBG=%s\n", showflags(dbgmap, opt_debug));
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 	/* if we have file names, we need a source and destination */
246*7c478bd9Sstevel@tonic-gate 	if (optind < argc) {
247*7c478bd9Sstevel@tonic-gate 		if (srcname == 0) {
248*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, gettext(ERR_nosrc));
249*7c478bd9Sstevel@tonic-gate 			errs |= ERR_INVAL;
250*7c478bd9Sstevel@tonic-gate 		}
251*7c478bd9Sstevel@tonic-gate 		if (dstname == 0) {
252*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, gettext(ERR_nodst));
253*7c478bd9Sstevel@tonic-gate 			errs |= ERR_INVAL;
254*7c478bd9Sstevel@tonic-gate 		}
255*7c478bd9Sstevel@tonic-gate 	}
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	/* check for simple usage errors	*/
258*7c478bd9Sstevel@tonic-gate 	if (errs & ERR_INVAL) {
259*7c478bd9Sstevel@tonic-gate 		usage();
260*7c478bd9Sstevel@tonic-gate 		exit(errs);
261*7c478bd9Sstevel@tonic-gate 	}
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	/* locate our baseline and rules files	*/
264*7c478bd9Sstevel@tonic-gate 	if (c = findfiles())
265*7c478bd9Sstevel@tonic-gate 		exit(c);
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 	/* figure out file creation defaults	*/
268*7c478bd9Sstevel@tonic-gate 	whoami();
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 	/* read in our initial baseline		*/
271*7c478bd9Sstevel@tonic-gate 	if (!new_baseline && (c = read_baseline(file_base)))
272*7c478bd9Sstevel@tonic-gate 		errs |= c;
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 	/* read in the rules file if we need or have rules	*/
275*7c478bd9Sstevel@tonic-gate 	if (optind >= argc && new_rules) {
276*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, ERR_nonames);
277*7c478bd9Sstevel@tonic-gate 		errs |= ERR_INVAL;
278*7c478bd9Sstevel@tonic-gate 	} else if (!new_rules)
279*7c478bd9Sstevel@tonic-gate 		errs |= read_rules(file_rules);
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 	/* if anything has failed with our setup, go no further	*/
282*7c478bd9Sstevel@tonic-gate 	if (errs) {
283*7c478bd9Sstevel@tonic-gate 		cleanup(errs);
284*7c478bd9Sstevel@tonic-gate 		exit(errs);
285*7c478bd9Sstevel@tonic-gate 	}
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	/*
288*7c478bd9Sstevel@tonic-gate 	 * figure out whether or not we are willing to do a one-sided
289*7c478bd9Sstevel@tonic-gate 	 * analysis (where we don't even look at the other side.  This
290*7c478bd9Sstevel@tonic-gate 	 * is an "I'm just curious what has changed" query, and we are
291*7c478bd9Sstevel@tonic-gate 	 * only willing to do it if:
292*7c478bd9Sstevel@tonic-gate 	 *	we aren't actually going to do anything
293*7c478bd9Sstevel@tonic-gate 	 *	we have a baseline we can compare against
294*7c478bd9Sstevel@tonic-gate 	 * otherwise, we are going to insist on being able to access
295*7c478bd9Sstevel@tonic-gate 	 * both the source and destination.
296*7c478bd9Sstevel@tonic-gate 	 */
297*7c478bd9Sstevel@tonic-gate 	if (opt_notouch && !new_baseline)
298*7c478bd9Sstevel@tonic-gate 		opt_onesided = opt_oneway;
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 	/*
301*7c478bd9Sstevel@tonic-gate 	 * there are two interested usage scenarios:
302*7c478bd9Sstevel@tonic-gate 	 *	file names specified
303*7c478bd9Sstevel@tonic-gate 	 *		create new rules for the specified files
304*7c478bd9Sstevel@tonic-gate 	 *		evaulate and reconcile only the specified files
305*7c478bd9Sstevel@tonic-gate 	 *	no file names specified
306*7c478bd9Sstevel@tonic-gate 	 *		use already existing rules
307*7c478bd9Sstevel@tonic-gate 	 *		consider restricting them to specified subdirs/files
308*7c478bd9Sstevel@tonic-gate 	 */
309*7c478bd9Sstevel@tonic-gate 	if (optind < argc) {
310*7c478bd9Sstevel@tonic-gate 		/* figure out what base pair we're working on	*/
311*7c478bd9Sstevel@tonic-gate 		bp = add_base(srcname, dstname);
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate 		/* perverse default rules to avoid trouble	*/
314*7c478bd9Sstevel@tonic-gate 		if (new_rules) {
315*7c478bd9Sstevel@tonic-gate 			errs |= add_ignore(0, SUFX_RULES);
316*7c478bd9Sstevel@tonic-gate 			errs |= add_ignore(0, SUFX_BASE);
317*7c478bd9Sstevel@tonic-gate 		}
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 		/* create include rules for each file/dir arg	*/
320*7c478bd9Sstevel@tonic-gate 		while (optind < argc)
321*7c478bd9Sstevel@tonic-gate 			errs |= add_include(bp, argv[ optind++ ]);
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 		/*
324*7c478bd9Sstevel@tonic-gate 		 * evaluate the specified base on each side,
325*7c478bd9Sstevel@tonic-gate 		 * being careful to limit evaulation to new rules
326*7c478bd9Sstevel@tonic-gate 		 */
327*7c478bd9Sstevel@tonic-gate 		errs |= evaluate(bp, OPT_SRC, TRUE);
328*7c478bd9Sstevel@tonic-gate 		errs |= evaluate(bp, OPT_DST, TRUE);
329*7c478bd9Sstevel@tonic-gate 	} else {
330*7c478bd9Sstevel@tonic-gate 		/* note any possible evaluation restrictions	*/
331*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < num_restrs; i++)
332*7c478bd9Sstevel@tonic-gate 			errs |= add_restr(rlist[i]);
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 		/*
335*7c478bd9Sstevel@tonic-gate 		 * we can only prune the baseline file if we have done
336*7c478bd9Sstevel@tonic-gate 		 * a complete (unrestricted) analysis.
337*7c478bd9Sstevel@tonic-gate 		 */
338*7c478bd9Sstevel@tonic-gate 		if (i == 0)
339*7c478bd9Sstevel@tonic-gate 			do_prune = 1;
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 		/* evaulate each base on each side		*/
342*7c478bd9Sstevel@tonic-gate 		for (bp = bases; bp; bp = bp->b_next) {
343*7c478bd9Sstevel@tonic-gate 			errs |= evaluate(bp, OPT_SRC, FALSE);
344*7c478bd9Sstevel@tonic-gate 			errs |= evaluate(bp, OPT_DST, FALSE);
345*7c478bd9Sstevel@tonic-gate 		}
346*7c478bd9Sstevel@tonic-gate 	}
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 	/* if anything serious happened, skip reconciliation	*/
349*7c478bd9Sstevel@tonic-gate 	if (errs & ERR_FATAL) {
350*7c478bd9Sstevel@tonic-gate 		cleanup(errs);
351*7c478bd9Sstevel@tonic-gate 		exit(errs);
352*7c478bd9Sstevel@tonic-gate 	}
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	/* analyze and deal with the differenecs		*/
355*7c478bd9Sstevel@tonic-gate 	errs |= analyze();
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 	/* see if there is any dead-wood in the baseline	*/
358*7c478bd9Sstevel@tonic-gate 	if (do_prune) {
359*7c478bd9Sstevel@tonic-gate 		c = prune();
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 		if (c > 0 && opt_verbose)
362*7c478bd9Sstevel@tonic-gate 			fprintf(stdout, V_prunes, c);
363*7c478bd9Sstevel@tonic-gate 	}
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	/* print out a final summary				*/
366*7c478bd9Sstevel@tonic-gate 	summary();
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 	/* update the rules and baseline files (if needed)	*/
369*7c478bd9Sstevel@tonic-gate 	(void) umask(my_umask);
370*7c478bd9Sstevel@tonic-gate 	errs |= write_baseline(file_base);
371*7c478bd9Sstevel@tonic-gate 	errs |= write_rules(file_rules);
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 	if (opt_debug & DBG_MISC)
374*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "MISC: EXIT=%s\n", showflags(errmap, errs));
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate 	/* just returning ERR_RESOLVABLE upsets some people	*/
377*7c478bd9Sstevel@tonic-gate 	if (errs == ERR_RESOLVABLE && !opt_notouch)
378*7c478bd9Sstevel@tonic-gate 		errs = 0;
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	/* all done	*/
381*7c478bd9Sstevel@tonic-gate 	cleanup(0);
382*7c478bd9Sstevel@tonic-gate 	exit(errs);
383*7c478bd9Sstevel@tonic-gate }
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate /*
387*7c478bd9Sstevel@tonic-gate  * routine:
388*7c478bd9Sstevel@tonic-gate  *	usage
389*7c478bd9Sstevel@tonic-gate  *
390*7c478bd9Sstevel@tonic-gate  * purpose:
391*7c478bd9Sstevel@tonic-gate  *	print out a usage message
392*7c478bd9Sstevel@tonic-gate  *
393*7c478bd9Sstevel@tonic-gate  * parameters:
394*7c478bd9Sstevel@tonic-gate  *	none
395*7c478bd9Sstevel@tonic-gate  *
396*7c478bd9Sstevel@tonic-gate  * returns:
397*7c478bd9Sstevel@tonic-gate  *	none
398*7c478bd9Sstevel@tonic-gate  *
399*7c478bd9Sstevel@tonic-gate  * note:
400*7c478bd9Sstevel@tonic-gate  *	the -D and -E switches are for development/test/support
401*7c478bd9Sstevel@tonic-gate  *	use only and do not show up in the general usage message.
402*7c478bd9Sstevel@tonic-gate  */
403*7c478bd9Sstevel@tonic-gate static void
404*7c478bd9Sstevel@tonic-gate usage(void)
405*7c478bd9Sstevel@tonic-gate {
406*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "%s\t%s %s\n", gettext(ERR_usage), "filesync",
407*7c478bd9Sstevel@tonic-gate 					gettext(USE_simple));
408*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "\t%s %s\n", "filesync", gettext(USE_all));
409*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "\t-a .......... %s\n", gettext(USE_a));
410*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "\t-e .......... %s\n", gettext(USE_e));
411*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "\t-h .......... %s\n", gettext(USE_h));
412*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "\t-m .......... %s\n", gettext(USE_m));
413*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "\t-n .......... %s\n", gettext(USE_n));
414*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "\t-q .......... %s\n", gettext(USE_q));
415*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "\t-v .......... %s\n", gettext(USE_v));
416*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "\t-y .......... %s\n", gettext(USE_y));
417*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "\t-s dir ...... %s\n", gettext(USE_s));
418*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "\t-d dir ...... %s\n", gettext(USE_d));
419*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "\t-r dir ...... %s\n", gettext(USE_r));
420*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "\t-f [sdon].... %s\n", gettext(USE_f));
421*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "\t-o src/dst... %s\n", gettext(USE_o));
422*7c478bd9Sstevel@tonic-gate }
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate /*
425*7c478bd9Sstevel@tonic-gate  * routine:
426*7c478bd9Sstevel@tonic-gate  *	confirm
427*7c478bd9Sstevel@tonic-gate  *
428*7c478bd9Sstevel@tonic-gate  * purpose:
429*7c478bd9Sstevel@tonic-gate  *	to confirm that the user is willing to do something dangerous
430*7c478bd9Sstevel@tonic-gate  *
431*7c478bd9Sstevel@tonic-gate  * parameters:
432*7c478bd9Sstevel@tonic-gate  *	warning message to be printed
433*7c478bd9Sstevel@tonic-gate  *
434*7c478bd9Sstevel@tonic-gate  * returns:
435*7c478bd9Sstevel@tonic-gate  * 	void
436*7c478bd9Sstevel@tonic-gate  *
437*7c478bd9Sstevel@tonic-gate  * notes:
438*7c478bd9Sstevel@tonic-gate  *	if this is a "notouch" or if the user has pre-confirmed,
439*7c478bd9Sstevel@tonic-gate  *	we should not obtain the confirmation and just return that
440*7c478bd9Sstevel@tonic-gate  *	the user has confirmed.
441*7c478bd9Sstevel@tonic-gate  */
442*7c478bd9Sstevel@tonic-gate void
443*7c478bd9Sstevel@tonic-gate confirm(char *message)
444*7c478bd9Sstevel@tonic-gate {	FILE *ttyi, *ttyo;
445*7c478bd9Sstevel@tonic-gate 	char ansbuf[ MAX_LINE ];
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 	/* if user pre-confirmed, we don't have to ask	*/
448*7c478bd9Sstevel@tonic-gate 	if (opt_yes || opt_notouch)
449*7c478bd9Sstevel@tonic-gate 		return;
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate 	ttyo = fopen("/dev/tty", "w");
452*7c478bd9Sstevel@tonic-gate 	ttyi = fopen("/dev/tty", "r");
453*7c478bd9Sstevel@tonic-gate 	if (ttyi == NULL || ttyo == NULL)
454*7c478bd9Sstevel@tonic-gate 		exit(ERR_OTHER);
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 	/* explain the problem and prompt for confirmation	*/
457*7c478bd9Sstevel@tonic-gate 	fprintf(ttyo, message);
458*7c478bd9Sstevel@tonic-gate 	fprintf(ttyo, gettext(WARN_proceed));
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate 	/* if the user doesn't kill us, we can continue		*/
461*7c478bd9Sstevel@tonic-gate 	(void) fgets(ansbuf, sizeof (ansbuf), ttyi);
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 	/* close the files and return				*/
464*7c478bd9Sstevel@tonic-gate 	(void) fclose(ttyi);
465*7c478bd9Sstevel@tonic-gate 	(void) fclose(ttyo);
466*7c478bd9Sstevel@tonic-gate }
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate void
469*7c478bd9Sstevel@tonic-gate nomem(char *reason)
470*7c478bd9Sstevel@tonic-gate {
471*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, gettext(ERR_nomem), reason);
472*7c478bd9Sstevel@tonic-gate 	exit(ERR_OTHER);
473*7c478bd9Sstevel@tonic-gate }
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate /*
476*7c478bd9Sstevel@tonic-gate  * routine:
477*7c478bd9Sstevel@tonic-gate  *	findfiles
478*7c478bd9Sstevel@tonic-gate  *
479*7c478bd9Sstevel@tonic-gate  * purpose:
480*7c478bd9Sstevel@tonic-gate  *	to locate our baseline and rules files
481*7c478bd9Sstevel@tonic-gate  *
482*7c478bd9Sstevel@tonic-gate  * parameters:
483*7c478bd9Sstevel@tonic-gate  *	none
484*7c478bd9Sstevel@tonic-gate  *
485*7c478bd9Sstevel@tonic-gate  * returns:
486*7c478bd9Sstevel@tonic-gate  *	error mask
487*7c478bd9Sstevel@tonic-gate  *	settings of file_base and file_rules
488*7c478bd9Sstevel@tonic-gate  *
489*7c478bd9Sstevel@tonic-gate  * side-effects:
490*7c478bd9Sstevel@tonic-gate  *	in order to keep multiple filesyncs from running in parallel
491*7c478bd9Sstevel@tonic-gate  *	we put an advisory lock on the baseline file.  If the baseline
492*7c478bd9Sstevel@tonic-gate  *	file does not exist we create one.  The unlocking (and deletion
493*7c478bd9Sstevel@tonic-gate  *	of extraneous baselines) is handled in cleanup.
494*7c478bd9Sstevel@tonic-gate  */
495*7c478bd9Sstevel@tonic-gate static errmask_t
496*7c478bd9Sstevel@tonic-gate findfiles(void)		/* find rule and baseline files	*/
497*7c478bd9Sstevel@tonic-gate { 	char *s, *where;
498*7c478bd9Sstevel@tonic-gate 	char namebuf[MAX_PATH];
499*7c478bd9Sstevel@tonic-gate 	int ret;
500*7c478bd9Sstevel@tonic-gate 	errmask_t errs = 0;
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 	/* figure out where the files should be located	*/
503*7c478bd9Sstevel@tonic-gate 	s = getenv("FILESYNC");
504*7c478bd9Sstevel@tonic-gate 	where = (s && *s) ? expand(s) : expand(DFLT_PRFX);
505*7c478bd9Sstevel@tonic-gate 
506*7c478bd9Sstevel@tonic-gate 	/* see if we got a viable name		*/
507*7c478bd9Sstevel@tonic-gate 	if (where == 0) {
508*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext(ERR_nofsync));
509*7c478bd9Sstevel@tonic-gate 		return (ERR_FILES);
510*7c478bd9Sstevel@tonic-gate 	}
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	/* try to form the name of the rules file */
513*7c478bd9Sstevel@tonic-gate 	strcpy(namebuf, where);
514*7c478bd9Sstevel@tonic-gate 	strcat(namebuf, SUFX_RULES);
515*7c478bd9Sstevel@tonic-gate 	s = strdup(namebuf);
516*7c478bd9Sstevel@tonic-gate 	errs = check_access(namebuf, &new_rules);
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 	/* if we cannot find a proper rules file, look in the old place */
519*7c478bd9Sstevel@tonic-gate 	if (new_rules && errs == 0) {
520*7c478bd9Sstevel@tonic-gate 		strcpy(namebuf, where);
521*7c478bd9Sstevel@tonic-gate 		strcat(namebuf, SUFX_OLD);
522*7c478bd9Sstevel@tonic-gate 		file_rules = strdup(namebuf);
523*7c478bd9Sstevel@tonic-gate 		errs = check_access(namebuf, &new_rules);
524*7c478bd9Sstevel@tonic-gate 
525*7c478bd9Sstevel@tonic-gate 		/* if we couldn't find that either, go with new name	*/
526*7c478bd9Sstevel@tonic-gate 		if (new_rules && errs == 0)
527*7c478bd9Sstevel@tonic-gate 			file_rules = s;
528*7c478bd9Sstevel@tonic-gate 	} else
529*7c478bd9Sstevel@tonic-gate 		file_rules = s;
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate 	/* try to form the name of the baseline file */
532*7c478bd9Sstevel@tonic-gate 	strcpy(namebuf, where);
533*7c478bd9Sstevel@tonic-gate 	strcat(namebuf, SUFX_BASE);
534*7c478bd9Sstevel@tonic-gate 	file_base = strdup(namebuf);
535*7c478bd9Sstevel@tonic-gate 	errs |= check_access(namebuf, &new_baseline);
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate 	if (opt_debug & DBG_FILES) {
538*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "FILE: %s rules file: %s\n",
539*7c478bd9Sstevel@tonic-gate 			new_rules ? "new" : "existing", file_rules);
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "FILE: %s base file:  %s\n",
542*7c478bd9Sstevel@tonic-gate 			new_baseline ? "new" : "existing", file_base);
543*7c478bd9Sstevel@tonic-gate 	}
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 	/*
546*7c478bd9Sstevel@tonic-gate 	 * in order to lock out other filesync programs we need some
547*7c478bd9Sstevel@tonic-gate 	 * file we can lock.  We do an advisory lock on the baseline
548*7c478bd9Sstevel@tonic-gate 	 * file.  If no baseline file exists, we create an empty one.
549*7c478bd9Sstevel@tonic-gate 	 */
550*7c478bd9Sstevel@tonic-gate 	if (new_baseline)
551*7c478bd9Sstevel@tonic-gate 		lockfd = creat(file_base, 0666);
552*7c478bd9Sstevel@tonic-gate 	else
553*7c478bd9Sstevel@tonic-gate 		lockfd = open(file_base, O_RDWR);
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 	if (lockfd < 0) {
556*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, new_baseline ? ERR_creat : ERR_open,
557*7c478bd9Sstevel@tonic-gate 			TXT_base, file_base);
558*7c478bd9Sstevel@tonic-gate 		errs |= ERR_FILES;
559*7c478bd9Sstevel@tonic-gate 	} else {
560*7c478bd9Sstevel@tonic-gate 		ret = lockf(lockfd, F_TLOCK, 0L);
561*7c478bd9Sstevel@tonic-gate 		if (ret < 0) {
562*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, ERR_lock, TXT_base, file_base);
563*7c478bd9Sstevel@tonic-gate 			errs |= ERR_FILES;
564*7c478bd9Sstevel@tonic-gate 		} else if (opt_debug & DBG_FILES)
565*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "FILE: locking baseline file %s\n",
566*7c478bd9Sstevel@tonic-gate 				file_base);
567*7c478bd9Sstevel@tonic-gate 	}
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	return (errs);
570*7c478bd9Sstevel@tonic-gate }
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate /*
573*7c478bd9Sstevel@tonic-gate  * routine:
574*7c478bd9Sstevel@tonic-gate  *	cleanup
575*7c478bd9Sstevel@tonic-gate  *
576*7c478bd9Sstevel@tonic-gate  * purpose:
577*7c478bd9Sstevel@tonic-gate  *	to clean up temporary files and locking prior to exit
578*7c478bd9Sstevel@tonic-gate  *
579*7c478bd9Sstevel@tonic-gate  * paremeters:
580*7c478bd9Sstevel@tonic-gate  *	error mask
581*7c478bd9Sstevel@tonic-gate  *
582*7c478bd9Sstevel@tonic-gate  * returns:
583*7c478bd9Sstevel@tonic-gate  *	void
584*7c478bd9Sstevel@tonic-gate  *
585*7c478bd9Sstevel@tonic-gate  * notes:
586*7c478bd9Sstevel@tonic-gate  *	if there are no errors, the baseline file is assumed to be good.
587*7c478bd9Sstevel@tonic-gate  *	Otherwise, if we created a temporary baseline file (just for
588*7c478bd9Sstevel@tonic-gate  *	locking) we will delete it.
589*7c478bd9Sstevel@tonic-gate  */
590*7c478bd9Sstevel@tonic-gate static void
591*7c478bd9Sstevel@tonic-gate cleanup(errmask_t errmask)
592*7c478bd9Sstevel@tonic-gate {
593*7c478bd9Sstevel@tonic-gate 	/* unlock the baseline file	*/
594*7c478bd9Sstevel@tonic-gate 	if (opt_debug & DBG_FILES)
595*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "FILE: unlock baseline file %s\n", file_base);
596*7c478bd9Sstevel@tonic-gate 	(void) lockf(lockfd, F_ULOCK, 0);
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate 	/* see if we need to delete a temporary copy	*/
599*7c478bd9Sstevel@tonic-gate 	if (errmask && new_baseline) {
600*7c478bd9Sstevel@tonic-gate 		if (opt_debug & DBG_FILES)
601*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "FILE: unlink temp baseline file %s\n",
602*7c478bd9Sstevel@tonic-gate 				file_base);
603*7c478bd9Sstevel@tonic-gate 		(void) unlink(file_base);
604*7c478bd9Sstevel@tonic-gate 	}
605*7c478bd9Sstevel@tonic-gate }
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate /*
608*7c478bd9Sstevel@tonic-gate  * routine:
609*7c478bd9Sstevel@tonic-gate  *	check_access
610*7c478bd9Sstevel@tonic-gate  *
611*7c478bd9Sstevel@tonic-gate  * purpose:
612*7c478bd9Sstevel@tonic-gate  *	to determine whether or not we can access an existing file
613*7c478bd9Sstevel@tonic-gate  *	or create a new one
614*7c478bd9Sstevel@tonic-gate  *
615*7c478bd9Sstevel@tonic-gate  * parameters:
616*7c478bd9Sstevel@tonic-gate  *	name of file (in a clobberable buffer)
617*7c478bd9Sstevel@tonic-gate  *	pointer to new file flag
618*7c478bd9Sstevel@tonic-gate  *
619*7c478bd9Sstevel@tonic-gate  * returns:
620*7c478bd9Sstevel@tonic-gate  *	error mask
621*7c478bd9Sstevel@tonic-gate  *	setting of the new file flag
622*7c478bd9Sstevel@tonic-gate  *
623*7c478bd9Sstevel@tonic-gate  * note:
624*7c478bd9Sstevel@tonic-gate  *	it is kind of a kluge that this routine clobbers the name,
625*7c478bd9Sstevel@tonic-gate  *	but it is only called from one place, it needs a modified
626*7c478bd9Sstevel@tonic-gate  *	copy of the name, and the one caller doesn't mind.
627*7c478bd9Sstevel@tonic-gate  */
628*7c478bd9Sstevel@tonic-gate static errmask_t
629*7c478bd9Sstevel@tonic-gate check_access(char *name, int *newflag)
630*7c478bd9Sstevel@tonic-gate {	char *s;
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 	/* start out by asking for what we want		*/
633*7c478bd9Sstevel@tonic-gate 	if (access(name, R_OK|W_OK) == 0) {
634*7c478bd9Sstevel@tonic-gate 		*newflag = 0;
635*7c478bd9Sstevel@tonic-gate 		return (0);
636*7c478bd9Sstevel@tonic-gate 	}
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate 	/* if the problem is isn't non-existance, lose	*/
639*7c478bd9Sstevel@tonic-gate 	if (errno != ENOENT) {
640*7c478bd9Sstevel@tonic-gate 		*newflag = 0;
641*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext(ERR_rdwri), name);
642*7c478bd9Sstevel@tonic-gate 		return (ERR_FILES);
643*7c478bd9Sstevel@tonic-gate 	}
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate 	/*
646*7c478bd9Sstevel@tonic-gate 	 * the file doesn't exist, so there is still hope if we can
647*7c478bd9Sstevel@tonic-gate 	 * write in the directory that should contain the file
648*7c478bd9Sstevel@tonic-gate 	 */
649*7c478bd9Sstevel@tonic-gate 	*newflag = 1;
650*7c478bd9Sstevel@tonic-gate 
651*7c478bd9Sstevel@tonic-gate 	/* truncate the file name to its containing directory */
652*7c478bd9Sstevel@tonic-gate 	for (s = name; s[1]; s++);
653*7c478bd9Sstevel@tonic-gate 	while (s > name && *s != '/')
654*7c478bd9Sstevel@tonic-gate 		s--;
655*7c478bd9Sstevel@tonic-gate 	if (s > name)
656*7c478bd9Sstevel@tonic-gate 		*s = 0;
657*7c478bd9Sstevel@tonic-gate 	else if (*s == '/')
658*7c478bd9Sstevel@tonic-gate 		s[1] = 0;
659*7c478bd9Sstevel@tonic-gate 	else
660*7c478bd9Sstevel@tonic-gate 		name = ".";
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 	/* then see if we have write access to the directory	*/
663*7c478bd9Sstevel@tonic-gate 	if (access(name, W_OK) == 0)
664*7c478bd9Sstevel@tonic-gate 		return (0);
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, gettext(ERR_dirwac), name);
667*7c478bd9Sstevel@tonic-gate 	return (ERR_FILES);
668*7c478bd9Sstevel@tonic-gate }
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate /*
671*7c478bd9Sstevel@tonic-gate  * routine:
672*7c478bd9Sstevel@tonic-gate  *	whoami
673*7c478bd9Sstevel@tonic-gate  *
674*7c478bd9Sstevel@tonic-gate  * purpose:
675*7c478bd9Sstevel@tonic-gate  *	to figure out who I am and what the default modes/ownership
676*7c478bd9Sstevel@tonic-gate  *	is on files that I create.
677*7c478bd9Sstevel@tonic-gate  */
678*7c478bd9Sstevel@tonic-gate static void
679*7c478bd9Sstevel@tonic-gate whoami()
680*7c478bd9Sstevel@tonic-gate {
681*7c478bd9Sstevel@tonic-gate 	my_uid = geteuid();
682*7c478bd9Sstevel@tonic-gate 	my_gid = getegid();
683*7c478bd9Sstevel@tonic-gate 	my_umask = umask(0);
684*7c478bd9Sstevel@tonic-gate 
685*7c478bd9Sstevel@tonic-gate 	if (opt_debug & DBG_MISC)
686*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "MISC: my_uid=%ld, my_gid=%ld, my_umask=%03o\n",
687*7c478bd9Sstevel@tonic-gate 			my_uid, my_gid, my_umask);
688*7c478bd9Sstevel@tonic-gate }
689