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
54321Scasper * Common Development and Distribution License (the "License").
64321Scasper * 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 /*
224321Scasper * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate * module:
280Sstevel@tonic-gate * main.c
290Sstevel@tonic-gate *
300Sstevel@tonic-gate * purpose:
310Sstevel@tonic-gate * argument handling and top level dispatch
320Sstevel@tonic-gate *
330Sstevel@tonic-gate * contents:
340Sstevel@tonic-gate * main argument handling and main loop
350Sstevel@tonic-gate * usage (static) print out usage message
360Sstevel@tonic-gate * confirm prompt the user for a confirmation and get it
370Sstevel@tonic-gate * nomem fatal error handler for malloc failures
380Sstevel@tonic-gate * findfiles (static) locate our baseline and rules files
390Sstevel@tonic-gate * cleanup (static) unlock baseline and delete temp file
400Sstevel@tonic-gate * check_access (static) do we have adequate access to a file/directory
410Sstevel@tonic-gate * whoami (static) get uid/gid/umask
420Sstevel@tonic-gate */
430Sstevel@tonic-gate
440Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
450Sstevel@tonic-gate
460Sstevel@tonic-gate #include <unistd.h>
470Sstevel@tonic-gate #include <stdlib.h>
480Sstevel@tonic-gate #include <fcntl.h>
490Sstevel@tonic-gate #include <stdio.h>
500Sstevel@tonic-gate #include <string.h>
510Sstevel@tonic-gate #include <ctype.h>
520Sstevel@tonic-gate #include <errno.h>
530Sstevel@tonic-gate #include <sys/stat.h>
540Sstevel@tonic-gate
550Sstevel@tonic-gate #include "filesync.h"
560Sstevel@tonic-gate #include "database.h"
570Sstevel@tonic-gate #include "messages.h"
580Sstevel@tonic-gate #include "debug.h"
590Sstevel@tonic-gate
600Sstevel@tonic-gate /*
610Sstevel@tonic-gate * local routines in this module:
620Sstevel@tonic-gate */
630Sstevel@tonic-gate static errmask_t findfiles(); /* find rule and baseline files */
640Sstevel@tonic-gate static void cleanup(int); /* cleanup locks and temps */
650Sstevel@tonic-gate static errmask_t check_access(char *, int *); /* check access to file */
660Sstevel@tonic-gate static void whoami(); /* gather information about me */
670Sstevel@tonic-gate static void usage(void); /* general usage */
680Sstevel@tonic-gate
690Sstevel@tonic-gate
700Sstevel@tonic-gate /*
710Sstevel@tonic-gate * globals exported to the rest of the program
720Sstevel@tonic-gate */
730Sstevel@tonic-gate bool_t opt_mtime; /* preserve modification times on propagations */
740Sstevel@tonic-gate bool_t opt_notouch; /* don't actually make any changes */
750Sstevel@tonic-gate bool_t opt_quiet; /* disable reconciliation command output */
760Sstevel@tonic-gate bool_t opt_verbose; /* enable analysis descriptions */
770Sstevel@tonic-gate side_t opt_force; /* designated winner for conflicts */
780Sstevel@tonic-gate side_t opt_oneway; /* one way only propagation */
790Sstevel@tonic-gate side_t opt_onesided; /* permit one-sided evaluation */
800Sstevel@tonic-gate bool_t opt_everything; /* everything must agree (modes/uid/gid) */
810Sstevel@tonic-gate bool_t opt_yes; /* pre-confirm massive deletions are OK */
820Sstevel@tonic-gate bool_t opt_acls; /* always scan for acls on all files */
830Sstevel@tonic-gate bool_t opt_errors; /* simulate errors on specified files */
840Sstevel@tonic-gate bool_t opt_halt; /* halt on propagation errors */
850Sstevel@tonic-gate dbgmask_t opt_debug; /* debug mask */
860Sstevel@tonic-gate
870Sstevel@tonic-gate uid_t my_uid; /* default UID for files I create */
880Sstevel@tonic-gate gid_t my_gid; /* default GID for files I create */
890Sstevel@tonic-gate
900Sstevel@tonic-gate static char *file_rules; /* name of rules file */
910Sstevel@tonic-gate static char *file_base; /* name of baseline file */
920Sstevel@tonic-gate
930Sstevel@tonic-gate static int new_baseline; /* are we creating a new baseline */
940Sstevel@tonic-gate static int new_rules; /* are we creating a new rules file */
950Sstevel@tonic-gate static int my_umask; /* default UMASK for files I create */
960Sstevel@tonic-gate static int lockfd; /* file descriptor for locking baseline */
970Sstevel@tonic-gate
980Sstevel@tonic-gate static char *rlist[MAX_RLIST];
990Sstevel@tonic-gate static int num_restrs = 0;
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate /*
1020Sstevel@tonic-gate * routine:
1030Sstevel@tonic-gate * main
1040Sstevel@tonic-gate *
1050Sstevel@tonic-gate * purpose:
1060Sstevel@tonic-gate * argument processing and primary dispatch
1070Sstevel@tonic-gate *
1080Sstevel@tonic-gate * returns:
1090Sstevel@tonic-gate * error codes per filesync.1 (ERR_* in filesync.h)
1100Sstevel@tonic-gate *
1110Sstevel@tonic-gate * notes:
1120Sstevel@tonic-gate * read filesync.1 in order to understand the argument processing
1130Sstevel@tonic-gate *
1140Sstevel@tonic-gate * most of the command line options just set some opt_ global
1150Sstevel@tonic-gate * variable that is later looked at by the code that actually
1160Sstevel@tonic-gate * implements the features. Only file names are really processed
1170Sstevel@tonic-gate * in this routine.
1180Sstevel@tonic-gate */
119363Sjwahlig int
main(int argc,char ** argv)1200Sstevel@tonic-gate main(int argc, char **argv)
1210Sstevel@tonic-gate { int i;
1220Sstevel@tonic-gate int c;
1230Sstevel@tonic-gate errmask_t errs = ERR_OK;
1240Sstevel@tonic-gate int do_prune = 0;
1250Sstevel@tonic-gate char *srcname = 0;
1260Sstevel@tonic-gate char *dstname = 0;
1270Sstevel@tonic-gate struct base *bp;
1280Sstevel@tonic-gate
1290Sstevel@tonic-gate /* keep the error messages simple */
1300Sstevel@tonic-gate argv[0] = "filesync";
1310Sstevel@tonic-gate
1320Sstevel@tonic-gate /* gather together all of the options */
1330Sstevel@tonic-gate while ((c = getopt(argc, argv, "AaehmnqvyD:E:r:s:d:f:o:")) != EOF)
1340Sstevel@tonic-gate switch (c) {
1350Sstevel@tonic-gate case 'a': /* always scan for acls */
1360Sstevel@tonic-gate opt_acls = TRUE;
1370Sstevel@tonic-gate break;
1380Sstevel@tonic-gate case 'e': /* everything agrees */
1390Sstevel@tonic-gate opt_everything = TRUE;
1400Sstevel@tonic-gate break;
1410Sstevel@tonic-gate case 'h': /* halt on error */
1420Sstevel@tonic-gate opt_halt = TRUE;
1430Sstevel@tonic-gate break;
1440Sstevel@tonic-gate case 'm': /* preserve modtimes */
1450Sstevel@tonic-gate opt_mtime = TRUE;
1460Sstevel@tonic-gate break;
1470Sstevel@tonic-gate case 'n': /* notouch */
1480Sstevel@tonic-gate opt_notouch = TRUE;
1490Sstevel@tonic-gate break;
1500Sstevel@tonic-gate case 'q': /* quiet */
1510Sstevel@tonic-gate opt_quiet = TRUE;
1520Sstevel@tonic-gate break;
1530Sstevel@tonic-gate case 'v': /* verbose */
1540Sstevel@tonic-gate opt_verbose = TRUE;
1550Sstevel@tonic-gate break;
1560Sstevel@tonic-gate case 'y': /* yes */
1570Sstevel@tonic-gate opt_yes = TRUE;
1580Sstevel@tonic-gate break;
1590Sstevel@tonic-gate case 'D': /* debug options */
1600Sstevel@tonic-gate if (!isdigit(optarg[0])) {
1610Sstevel@tonic-gate dbg_usage();
1620Sstevel@tonic-gate exit(ERR_INVAL);
1630Sstevel@tonic-gate }
164363Sjwahlig opt_debug |= strtol(optarg, (char **)NULL, 0);
1650Sstevel@tonic-gate break;
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate case 'E': /* error simulation */
1680Sstevel@tonic-gate if (dbg_set_error(optarg)) {
1690Sstevel@tonic-gate err_usage();
1700Sstevel@tonic-gate exit(ERR_INVAL);
1710Sstevel@tonic-gate }
1720Sstevel@tonic-gate opt_errors = TRUE;
1730Sstevel@tonic-gate break;
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate case 'f': /* force conflict resolution */
1760Sstevel@tonic-gate switch (optarg[0]) {
1770Sstevel@tonic-gate case 's':
1780Sstevel@tonic-gate opt_force = OPT_SRC;
1790Sstevel@tonic-gate break;
1800Sstevel@tonic-gate case 'd':
1810Sstevel@tonic-gate opt_force = OPT_DST;
1820Sstevel@tonic-gate break;
1830Sstevel@tonic-gate case 'o':
1840Sstevel@tonic-gate opt_force = OPT_OLD;
1850Sstevel@tonic-gate break;
1860Sstevel@tonic-gate case 'n':
1870Sstevel@tonic-gate opt_force = OPT_NEW;
1880Sstevel@tonic-gate break;
1890Sstevel@tonic-gate default:
1900Sstevel@tonic-gate fprintf(stderr,
1910Sstevel@tonic-gate gettext(ERR_badopt),
1920Sstevel@tonic-gate c, optarg);
1930Sstevel@tonic-gate errs |= ERR_INVAL;
1940Sstevel@tonic-gate break;
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate break;
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate case 'o': /* one way propagation */
1990Sstevel@tonic-gate switch (optarg[0]) {
2000Sstevel@tonic-gate case 's':
2010Sstevel@tonic-gate opt_oneway = OPT_SRC;
2020Sstevel@tonic-gate break;
2030Sstevel@tonic-gate case 'd':
2040Sstevel@tonic-gate opt_oneway = OPT_DST;
2050Sstevel@tonic-gate break;
2060Sstevel@tonic-gate default:
2070Sstevel@tonic-gate fprintf(stderr,
2080Sstevel@tonic-gate gettext(ERR_badopt),
2090Sstevel@tonic-gate c, optarg);
2100Sstevel@tonic-gate errs |= ERR_INVAL;
2110Sstevel@tonic-gate break;
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate break;
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate case 'r': /* restricted reconciliation */
2160Sstevel@tonic-gate if (num_restrs < MAX_RLIST)
2170Sstevel@tonic-gate rlist[ num_restrs++ ] = optarg;
2180Sstevel@tonic-gate else {
2190Sstevel@tonic-gate fprintf(stderr, gettext(ERR_tomany),
2200Sstevel@tonic-gate MAX_RLIST);
2210Sstevel@tonic-gate errs |= ERR_INVAL;
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate break;
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate case 's':
2260Sstevel@tonic-gate if ((srcname = qualify(optarg)) == 0)
2270Sstevel@tonic-gate errs |= ERR_MISSING;
2280Sstevel@tonic-gate break;
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate case 'd':
2310Sstevel@tonic-gate if ((dstname = qualify(optarg)) == 0)
2320Sstevel@tonic-gate errs |= ERR_MISSING;
2330Sstevel@tonic-gate break;
2340Sstevel@tonic-gate
2350Sstevel@tonic-gate default:
2360Sstevel@tonic-gate case '?':
2370Sstevel@tonic-gate errs |= ERR_INVAL;
2380Sstevel@tonic-gate break;
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate
2410Sstevel@tonic-gate if (opt_debug & DBG_MISC)
2420Sstevel@tonic-gate fprintf(stderr, "MISC: DBG=%s\n", showflags(dbgmap, opt_debug));
2430Sstevel@tonic-gate
2440Sstevel@tonic-gate /* if we have file names, we need a source and destination */
2450Sstevel@tonic-gate if (optind < argc) {
2460Sstevel@tonic-gate if (srcname == 0) {
2470Sstevel@tonic-gate fprintf(stderr, gettext(ERR_nosrc));
2480Sstevel@tonic-gate errs |= ERR_INVAL;
2490Sstevel@tonic-gate }
2500Sstevel@tonic-gate if (dstname == 0) {
2510Sstevel@tonic-gate fprintf(stderr, gettext(ERR_nodst));
2520Sstevel@tonic-gate errs |= ERR_INVAL;
2530Sstevel@tonic-gate }
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate /* check for simple usage errors */
2570Sstevel@tonic-gate if (errs & ERR_INVAL) {
2580Sstevel@tonic-gate usage();
2590Sstevel@tonic-gate exit(errs);
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate
2620Sstevel@tonic-gate /* locate our baseline and rules files */
2630Sstevel@tonic-gate if (c = findfiles())
2640Sstevel@tonic-gate exit(c);
2650Sstevel@tonic-gate
2660Sstevel@tonic-gate /* figure out file creation defaults */
2670Sstevel@tonic-gate whoami();
2680Sstevel@tonic-gate
2690Sstevel@tonic-gate /* read in our initial baseline */
2700Sstevel@tonic-gate if (!new_baseline && (c = read_baseline(file_base)))
2710Sstevel@tonic-gate errs |= c;
2720Sstevel@tonic-gate
2730Sstevel@tonic-gate /* read in the rules file if we need or have rules */
2740Sstevel@tonic-gate if (optind >= argc && new_rules) {
2750Sstevel@tonic-gate fprintf(stderr, ERR_nonames);
2760Sstevel@tonic-gate errs |= ERR_INVAL;
2770Sstevel@tonic-gate } else if (!new_rules)
2780Sstevel@tonic-gate errs |= read_rules(file_rules);
2790Sstevel@tonic-gate
2800Sstevel@tonic-gate /* if anything has failed with our setup, go no further */
2810Sstevel@tonic-gate if (errs) {
2820Sstevel@tonic-gate cleanup(errs);
2830Sstevel@tonic-gate exit(errs);
2840Sstevel@tonic-gate }
2850Sstevel@tonic-gate
2860Sstevel@tonic-gate /*
2870Sstevel@tonic-gate * figure out whether or not we are willing to do a one-sided
2880Sstevel@tonic-gate * analysis (where we don't even look at the other side. This
2890Sstevel@tonic-gate * is an "I'm just curious what has changed" query, and we are
2900Sstevel@tonic-gate * only willing to do it if:
2910Sstevel@tonic-gate * we aren't actually going to do anything
2920Sstevel@tonic-gate * we have a baseline we can compare against
2930Sstevel@tonic-gate * otherwise, we are going to insist on being able to access
2940Sstevel@tonic-gate * both the source and destination.
2950Sstevel@tonic-gate */
2960Sstevel@tonic-gate if (opt_notouch && !new_baseline)
2970Sstevel@tonic-gate opt_onesided = opt_oneway;
2980Sstevel@tonic-gate
2990Sstevel@tonic-gate /*
3000Sstevel@tonic-gate * there are two interested usage scenarios:
3010Sstevel@tonic-gate * file names specified
3020Sstevel@tonic-gate * create new rules for the specified files
3030Sstevel@tonic-gate * evaulate and reconcile only the specified files
3040Sstevel@tonic-gate * no file names specified
3050Sstevel@tonic-gate * use already existing rules
3060Sstevel@tonic-gate * consider restricting them to specified subdirs/files
3070Sstevel@tonic-gate */
3080Sstevel@tonic-gate if (optind < argc) {
3090Sstevel@tonic-gate /* figure out what base pair we're working on */
3100Sstevel@tonic-gate bp = add_base(srcname, dstname);
3110Sstevel@tonic-gate
3120Sstevel@tonic-gate /* perverse default rules to avoid trouble */
3130Sstevel@tonic-gate if (new_rules) {
3140Sstevel@tonic-gate errs |= add_ignore(0, SUFX_RULES);
3150Sstevel@tonic-gate errs |= add_ignore(0, SUFX_BASE);
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate /* create include rules for each file/dir arg */
3190Sstevel@tonic-gate while (optind < argc)
3200Sstevel@tonic-gate errs |= add_include(bp, argv[ optind++ ]);
3210Sstevel@tonic-gate
3220Sstevel@tonic-gate /*
3230Sstevel@tonic-gate * evaluate the specified base on each side,
3240Sstevel@tonic-gate * being careful to limit evaulation to new rules
3250Sstevel@tonic-gate */
3260Sstevel@tonic-gate errs |= evaluate(bp, OPT_SRC, TRUE);
3270Sstevel@tonic-gate errs |= evaluate(bp, OPT_DST, TRUE);
3280Sstevel@tonic-gate } else {
3290Sstevel@tonic-gate /* note any possible evaluation restrictions */
3300Sstevel@tonic-gate for (i = 0; i < num_restrs; i++)
3310Sstevel@tonic-gate errs |= add_restr(rlist[i]);
3320Sstevel@tonic-gate
3330Sstevel@tonic-gate /*
3340Sstevel@tonic-gate * we can only prune the baseline file if we have done
3350Sstevel@tonic-gate * a complete (unrestricted) analysis.
3360Sstevel@tonic-gate */
3370Sstevel@tonic-gate if (i == 0)
3380Sstevel@tonic-gate do_prune = 1;
3390Sstevel@tonic-gate
3400Sstevel@tonic-gate /* evaulate each base on each side */
3410Sstevel@tonic-gate for (bp = bases; bp; bp = bp->b_next) {
3420Sstevel@tonic-gate errs |= evaluate(bp, OPT_SRC, FALSE);
3430Sstevel@tonic-gate errs |= evaluate(bp, OPT_DST, FALSE);
3440Sstevel@tonic-gate }
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate /* if anything serious happened, skip reconciliation */
3480Sstevel@tonic-gate if (errs & ERR_FATAL) {
3490Sstevel@tonic-gate cleanup(errs);
3500Sstevel@tonic-gate exit(errs);
3510Sstevel@tonic-gate }
3520Sstevel@tonic-gate
3530Sstevel@tonic-gate /* analyze and deal with the differenecs */
3540Sstevel@tonic-gate errs |= analyze();
3550Sstevel@tonic-gate
3560Sstevel@tonic-gate /* see if there is any dead-wood in the baseline */
3570Sstevel@tonic-gate if (do_prune) {
3580Sstevel@tonic-gate c = prune();
3590Sstevel@tonic-gate
3600Sstevel@tonic-gate if (c > 0 && opt_verbose)
3610Sstevel@tonic-gate fprintf(stdout, V_prunes, c);
3620Sstevel@tonic-gate }
3630Sstevel@tonic-gate
3640Sstevel@tonic-gate /* print out a final summary */
3650Sstevel@tonic-gate summary();
3660Sstevel@tonic-gate
3670Sstevel@tonic-gate /* update the rules and baseline files (if needed) */
3680Sstevel@tonic-gate (void) umask(my_umask);
3690Sstevel@tonic-gate errs |= write_baseline(file_base);
3700Sstevel@tonic-gate errs |= write_rules(file_rules);
3710Sstevel@tonic-gate
3720Sstevel@tonic-gate if (opt_debug & DBG_MISC)
3730Sstevel@tonic-gate fprintf(stderr, "MISC: EXIT=%s\n", showflags(errmap, errs));
3740Sstevel@tonic-gate
3750Sstevel@tonic-gate /* just returning ERR_RESOLVABLE upsets some people */
3760Sstevel@tonic-gate if (errs == ERR_RESOLVABLE && !opt_notouch)
3770Sstevel@tonic-gate errs = 0;
3780Sstevel@tonic-gate
3790Sstevel@tonic-gate /* all done */
3800Sstevel@tonic-gate cleanup(0);
381363Sjwahlig return (errs);
3820Sstevel@tonic-gate }
3830Sstevel@tonic-gate
3840Sstevel@tonic-gate
3850Sstevel@tonic-gate /*
3860Sstevel@tonic-gate * routine:
3870Sstevel@tonic-gate * usage
3880Sstevel@tonic-gate *
3890Sstevel@tonic-gate * purpose:
3900Sstevel@tonic-gate * print out a usage message
3910Sstevel@tonic-gate *
3920Sstevel@tonic-gate * parameters:
3930Sstevel@tonic-gate * none
3940Sstevel@tonic-gate *
3950Sstevel@tonic-gate * returns:
3960Sstevel@tonic-gate * none
3970Sstevel@tonic-gate *
3980Sstevel@tonic-gate * note:
3990Sstevel@tonic-gate * the -D and -E switches are for development/test/support
4000Sstevel@tonic-gate * use only and do not show up in the general usage message.
4010Sstevel@tonic-gate */
4020Sstevel@tonic-gate static void
usage(void)4030Sstevel@tonic-gate usage(void)
4040Sstevel@tonic-gate {
4050Sstevel@tonic-gate fprintf(stderr, "%s\t%s %s\n", gettext(ERR_usage), "filesync",
4060Sstevel@tonic-gate gettext(USE_simple));
4070Sstevel@tonic-gate fprintf(stderr, "\t%s %s\n", "filesync", gettext(USE_all));
4080Sstevel@tonic-gate fprintf(stderr, "\t-a .......... %s\n", gettext(USE_a));
4090Sstevel@tonic-gate fprintf(stderr, "\t-e .......... %s\n", gettext(USE_e));
4100Sstevel@tonic-gate fprintf(stderr, "\t-h .......... %s\n", gettext(USE_h));
4110Sstevel@tonic-gate fprintf(stderr, "\t-m .......... %s\n", gettext(USE_m));
4120Sstevel@tonic-gate fprintf(stderr, "\t-n .......... %s\n", gettext(USE_n));
4130Sstevel@tonic-gate fprintf(stderr, "\t-q .......... %s\n", gettext(USE_q));
4140Sstevel@tonic-gate fprintf(stderr, "\t-v .......... %s\n", gettext(USE_v));
4150Sstevel@tonic-gate fprintf(stderr, "\t-y .......... %s\n", gettext(USE_y));
4160Sstevel@tonic-gate fprintf(stderr, "\t-s dir ...... %s\n", gettext(USE_s));
4170Sstevel@tonic-gate fprintf(stderr, "\t-d dir ...... %s\n", gettext(USE_d));
4180Sstevel@tonic-gate fprintf(stderr, "\t-r dir ...... %s\n", gettext(USE_r));
4190Sstevel@tonic-gate fprintf(stderr, "\t-f [sdon].... %s\n", gettext(USE_f));
4200Sstevel@tonic-gate fprintf(stderr, "\t-o src/dst... %s\n", gettext(USE_o));
4210Sstevel@tonic-gate }
4220Sstevel@tonic-gate
4230Sstevel@tonic-gate /*
4240Sstevel@tonic-gate * routine:
4250Sstevel@tonic-gate * confirm
4260Sstevel@tonic-gate *
4270Sstevel@tonic-gate * purpose:
4280Sstevel@tonic-gate * to confirm that the user is willing to do something dangerous
4290Sstevel@tonic-gate *
4300Sstevel@tonic-gate * parameters:
4310Sstevel@tonic-gate * warning message to be printed
4320Sstevel@tonic-gate *
4330Sstevel@tonic-gate * returns:
4340Sstevel@tonic-gate * void
4350Sstevel@tonic-gate *
4360Sstevel@tonic-gate * notes:
4370Sstevel@tonic-gate * if this is a "notouch" or if the user has pre-confirmed,
4380Sstevel@tonic-gate * we should not obtain the confirmation and just return that
4390Sstevel@tonic-gate * the user has confirmed.
4400Sstevel@tonic-gate */
4410Sstevel@tonic-gate void
confirm(char * message)4420Sstevel@tonic-gate confirm(char *message)
4430Sstevel@tonic-gate { FILE *ttyi, *ttyo;
4440Sstevel@tonic-gate char ansbuf[ MAX_LINE ];
4450Sstevel@tonic-gate
4460Sstevel@tonic-gate /* if user pre-confirmed, we don't have to ask */
4470Sstevel@tonic-gate if (opt_yes || opt_notouch)
4480Sstevel@tonic-gate return;
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate ttyo = fopen("/dev/tty", "w");
4510Sstevel@tonic-gate ttyi = fopen("/dev/tty", "r");
4520Sstevel@tonic-gate if (ttyi == NULL || ttyo == NULL)
4530Sstevel@tonic-gate exit(ERR_OTHER);
4540Sstevel@tonic-gate
4550Sstevel@tonic-gate /* explain the problem and prompt for confirmation */
4560Sstevel@tonic-gate fprintf(ttyo, message);
4570Sstevel@tonic-gate fprintf(ttyo, gettext(WARN_proceed));
4580Sstevel@tonic-gate
4590Sstevel@tonic-gate /* if the user doesn't kill us, we can continue */
4600Sstevel@tonic-gate (void) fgets(ansbuf, sizeof (ansbuf), ttyi);
4610Sstevel@tonic-gate
4620Sstevel@tonic-gate /* close the files and return */
4630Sstevel@tonic-gate (void) fclose(ttyi);
4640Sstevel@tonic-gate (void) fclose(ttyo);
4650Sstevel@tonic-gate }
4660Sstevel@tonic-gate
4670Sstevel@tonic-gate void
nomem(char * reason)4680Sstevel@tonic-gate nomem(char *reason)
4690Sstevel@tonic-gate {
4700Sstevel@tonic-gate fprintf(stderr, gettext(ERR_nomem), reason);
4710Sstevel@tonic-gate exit(ERR_OTHER);
4720Sstevel@tonic-gate }
4730Sstevel@tonic-gate
4740Sstevel@tonic-gate /*
4750Sstevel@tonic-gate * routine:
4760Sstevel@tonic-gate * findfiles
4770Sstevel@tonic-gate *
4780Sstevel@tonic-gate * purpose:
4790Sstevel@tonic-gate * to locate our baseline and rules files
4800Sstevel@tonic-gate *
4810Sstevel@tonic-gate * parameters:
4820Sstevel@tonic-gate * none
4830Sstevel@tonic-gate *
4840Sstevel@tonic-gate * returns:
4850Sstevel@tonic-gate * error mask
4860Sstevel@tonic-gate * settings of file_base and file_rules
4870Sstevel@tonic-gate *
4880Sstevel@tonic-gate * side-effects:
4890Sstevel@tonic-gate * in order to keep multiple filesyncs from running in parallel
4900Sstevel@tonic-gate * we put an advisory lock on the baseline file. If the baseline
4910Sstevel@tonic-gate * file does not exist we create one. The unlocking (and deletion
4920Sstevel@tonic-gate * of extraneous baselines) is handled in cleanup.
4930Sstevel@tonic-gate */
4940Sstevel@tonic-gate static errmask_t
findfiles(void)4950Sstevel@tonic-gate findfiles(void) /* find rule and baseline files */
4960Sstevel@tonic-gate { char *s, *where;
4970Sstevel@tonic-gate char namebuf[MAX_PATH];
4980Sstevel@tonic-gate int ret;
4990Sstevel@tonic-gate errmask_t errs = 0;
5000Sstevel@tonic-gate
5010Sstevel@tonic-gate /* figure out where the files should be located */
5020Sstevel@tonic-gate s = getenv("FILESYNC");
5030Sstevel@tonic-gate where = (s && *s) ? expand(s) : expand(DFLT_PRFX);
5040Sstevel@tonic-gate
5050Sstevel@tonic-gate /* see if we got a viable name */
5060Sstevel@tonic-gate if (where == 0) {
5070Sstevel@tonic-gate fprintf(stderr, gettext(ERR_nofsync));
5080Sstevel@tonic-gate return (ERR_FILES);
5090Sstevel@tonic-gate }
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate /* try to form the name of the rules file */
5120Sstevel@tonic-gate strcpy(namebuf, where);
5130Sstevel@tonic-gate strcat(namebuf, SUFX_RULES);
5140Sstevel@tonic-gate s = strdup(namebuf);
5150Sstevel@tonic-gate errs = check_access(namebuf, &new_rules);
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate /* if we cannot find a proper rules file, look in the old place */
5180Sstevel@tonic-gate if (new_rules && errs == 0) {
5190Sstevel@tonic-gate strcpy(namebuf, where);
5200Sstevel@tonic-gate strcat(namebuf, SUFX_OLD);
5210Sstevel@tonic-gate file_rules = strdup(namebuf);
5220Sstevel@tonic-gate errs = check_access(namebuf, &new_rules);
5230Sstevel@tonic-gate
5240Sstevel@tonic-gate /* if we couldn't find that either, go with new name */
5250Sstevel@tonic-gate if (new_rules && errs == 0)
5260Sstevel@tonic-gate file_rules = s;
5270Sstevel@tonic-gate } else
5280Sstevel@tonic-gate file_rules = s;
5290Sstevel@tonic-gate
5300Sstevel@tonic-gate /* try to form the name of the baseline file */
5310Sstevel@tonic-gate strcpy(namebuf, where);
5320Sstevel@tonic-gate strcat(namebuf, SUFX_BASE);
5330Sstevel@tonic-gate file_base = strdup(namebuf);
5340Sstevel@tonic-gate errs |= check_access(namebuf, &new_baseline);
5350Sstevel@tonic-gate
5360Sstevel@tonic-gate if (opt_debug & DBG_FILES) {
5370Sstevel@tonic-gate fprintf(stderr, "FILE: %s rules file: %s\n",
5380Sstevel@tonic-gate new_rules ? "new" : "existing", file_rules);
5390Sstevel@tonic-gate
5400Sstevel@tonic-gate fprintf(stderr, "FILE: %s base file: %s\n",
5410Sstevel@tonic-gate new_baseline ? "new" : "existing", file_base);
5420Sstevel@tonic-gate }
5430Sstevel@tonic-gate
5440Sstevel@tonic-gate /*
5450Sstevel@tonic-gate * in order to lock out other filesync programs we need some
5460Sstevel@tonic-gate * file we can lock. We do an advisory lock on the baseline
5470Sstevel@tonic-gate * file. If no baseline file exists, we create an empty one.
5480Sstevel@tonic-gate */
5490Sstevel@tonic-gate if (new_baseline)
5500Sstevel@tonic-gate lockfd = creat(file_base, 0666);
5510Sstevel@tonic-gate else
5520Sstevel@tonic-gate lockfd = open(file_base, O_RDWR);
5530Sstevel@tonic-gate
5540Sstevel@tonic-gate if (lockfd < 0) {
5550Sstevel@tonic-gate fprintf(stderr, new_baseline ? ERR_creat : ERR_open,
5560Sstevel@tonic-gate TXT_base, file_base);
5570Sstevel@tonic-gate errs |= ERR_FILES;
5580Sstevel@tonic-gate } else {
5590Sstevel@tonic-gate ret = lockf(lockfd, F_TLOCK, 0L);
5600Sstevel@tonic-gate if (ret < 0) {
5610Sstevel@tonic-gate fprintf(stderr, ERR_lock, TXT_base, file_base);
5620Sstevel@tonic-gate errs |= ERR_FILES;
5630Sstevel@tonic-gate } else if (opt_debug & DBG_FILES)
5640Sstevel@tonic-gate fprintf(stderr, "FILE: locking baseline file %s\n",
5650Sstevel@tonic-gate file_base);
5660Sstevel@tonic-gate }
5670Sstevel@tonic-gate
5680Sstevel@tonic-gate return (errs);
5690Sstevel@tonic-gate }
5700Sstevel@tonic-gate
5710Sstevel@tonic-gate /*
5720Sstevel@tonic-gate * routine:
5730Sstevel@tonic-gate * cleanup
5740Sstevel@tonic-gate *
5750Sstevel@tonic-gate * purpose:
5760Sstevel@tonic-gate * to clean up temporary files and locking prior to exit
5770Sstevel@tonic-gate *
5780Sstevel@tonic-gate * paremeters:
5790Sstevel@tonic-gate * error mask
5800Sstevel@tonic-gate *
5810Sstevel@tonic-gate * returns:
5820Sstevel@tonic-gate * void
5830Sstevel@tonic-gate *
5840Sstevel@tonic-gate * notes:
5850Sstevel@tonic-gate * if there are no errors, the baseline file is assumed to be good.
5860Sstevel@tonic-gate * Otherwise, if we created a temporary baseline file (just for
5870Sstevel@tonic-gate * locking) we will delete it.
5880Sstevel@tonic-gate */
5890Sstevel@tonic-gate static void
cleanup(errmask_t errmask)5900Sstevel@tonic-gate cleanup(errmask_t errmask)
5910Sstevel@tonic-gate {
5920Sstevel@tonic-gate /* unlock the baseline file */
5930Sstevel@tonic-gate if (opt_debug & DBG_FILES)
5940Sstevel@tonic-gate fprintf(stderr, "FILE: unlock baseline file %s\n", file_base);
5950Sstevel@tonic-gate (void) lockf(lockfd, F_ULOCK, 0);
5960Sstevel@tonic-gate
5970Sstevel@tonic-gate /* see if we need to delete a temporary copy */
5980Sstevel@tonic-gate if (errmask && new_baseline) {
5990Sstevel@tonic-gate if (opt_debug & DBG_FILES)
6000Sstevel@tonic-gate fprintf(stderr, "FILE: unlink temp baseline file %s\n",
6010Sstevel@tonic-gate file_base);
6020Sstevel@tonic-gate (void) unlink(file_base);
6030Sstevel@tonic-gate }
6040Sstevel@tonic-gate }
6050Sstevel@tonic-gate
6060Sstevel@tonic-gate /*
6070Sstevel@tonic-gate * routine:
6080Sstevel@tonic-gate * check_access
6090Sstevel@tonic-gate *
6100Sstevel@tonic-gate * purpose:
6110Sstevel@tonic-gate * to determine whether or not we can access an existing file
6120Sstevel@tonic-gate * or create a new one
6130Sstevel@tonic-gate *
6140Sstevel@tonic-gate * parameters:
6150Sstevel@tonic-gate * name of file (in a clobberable buffer)
6160Sstevel@tonic-gate * pointer to new file flag
6170Sstevel@tonic-gate *
6180Sstevel@tonic-gate * returns:
6190Sstevel@tonic-gate * error mask
6200Sstevel@tonic-gate * setting of the new file flag
6210Sstevel@tonic-gate *
6220Sstevel@tonic-gate * note:
6230Sstevel@tonic-gate * it is kind of a kluge that this routine clobbers the name,
6240Sstevel@tonic-gate * but it is only called from one place, it needs a modified
6250Sstevel@tonic-gate * copy of the name, and the one caller doesn't mind.
6260Sstevel@tonic-gate */
6270Sstevel@tonic-gate static errmask_t
check_access(char * name,int * newflag)6280Sstevel@tonic-gate check_access(char *name, int *newflag)
6290Sstevel@tonic-gate { char *s;
6300Sstevel@tonic-gate
6310Sstevel@tonic-gate /* start out by asking for what we want */
6320Sstevel@tonic-gate if (access(name, R_OK|W_OK) == 0) {
6330Sstevel@tonic-gate *newflag = 0;
6340Sstevel@tonic-gate return (0);
6350Sstevel@tonic-gate }
6360Sstevel@tonic-gate
637*5331Samw /* if the problem is isn't non-existence, lose */
6380Sstevel@tonic-gate if (errno != ENOENT) {
6390Sstevel@tonic-gate *newflag = 0;
6400Sstevel@tonic-gate fprintf(stderr, gettext(ERR_rdwri), name);
6410Sstevel@tonic-gate return (ERR_FILES);
6420Sstevel@tonic-gate }
6430Sstevel@tonic-gate
6440Sstevel@tonic-gate /*
6450Sstevel@tonic-gate * the file doesn't exist, so there is still hope if we can
6460Sstevel@tonic-gate * write in the directory that should contain the file
6470Sstevel@tonic-gate */
6480Sstevel@tonic-gate *newflag = 1;
6490Sstevel@tonic-gate
6500Sstevel@tonic-gate /* truncate the file name to its containing directory */
6510Sstevel@tonic-gate for (s = name; s[1]; s++);
6520Sstevel@tonic-gate while (s > name && *s != '/')
6530Sstevel@tonic-gate s--;
6540Sstevel@tonic-gate if (s > name)
6550Sstevel@tonic-gate *s = 0;
6560Sstevel@tonic-gate else if (*s == '/')
6570Sstevel@tonic-gate s[1] = 0;
6580Sstevel@tonic-gate else
6590Sstevel@tonic-gate name = ".";
6600Sstevel@tonic-gate
6610Sstevel@tonic-gate /* then see if we have write access to the directory */
6620Sstevel@tonic-gate if (access(name, W_OK) == 0)
6630Sstevel@tonic-gate return (0);
6640Sstevel@tonic-gate
6650Sstevel@tonic-gate fprintf(stderr, gettext(ERR_dirwac), name);
6660Sstevel@tonic-gate return (ERR_FILES);
6670Sstevel@tonic-gate }
6680Sstevel@tonic-gate
6690Sstevel@tonic-gate /*
6700Sstevel@tonic-gate * routine:
6710Sstevel@tonic-gate * whoami
6720Sstevel@tonic-gate *
6730Sstevel@tonic-gate * purpose:
6740Sstevel@tonic-gate * to figure out who I am and what the default modes/ownership
6750Sstevel@tonic-gate * is on files that I create.
6760Sstevel@tonic-gate */
6770Sstevel@tonic-gate static void
whoami()6780Sstevel@tonic-gate whoami()
6790Sstevel@tonic-gate {
6800Sstevel@tonic-gate my_uid = geteuid();
6810Sstevel@tonic-gate my_gid = getegid();
6820Sstevel@tonic-gate my_umask = umask(0);
6830Sstevel@tonic-gate
6840Sstevel@tonic-gate if (opt_debug & DBG_MISC)
6854321Scasper fprintf(stderr, "MISC: my_uid=%u, my_gid=%u, my_umask=%03o\n",
6860Sstevel@tonic-gate my_uid, my_gid, my_umask);
6870Sstevel@tonic-gate }
688