main.c revision 3aceb801c46d1081eea8772ecb3c0d61d6ebd1e8
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* module:
* main.c
*
* purpose:
* argument handling and top level dispatch
*
* contents:
* main argument handling and main loop
* usage (static) print out usage message
* confirm prompt the user for a confirmation and get it
* nomem fatal error handler for malloc failures
* findfiles (static) locate our baseline and rules files
* cleanup (static) unlock baseline and delete temp file
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include "filesync.h"
#include "database.h"
#include "messages.h"
#include "debug.h"
/*
* local routines in this module:
*/
static void cleanup(int); /* cleanup locks and temps */
static void whoami(); /* gather information about me */
static void usage(void); /* general usage */
/*
* globals exported to the rest of the program
*/
static char *file_rules; /* name of rules file */
static char *file_base; /* name of baseline file */
static int new_baseline; /* are we creating a new baseline */
static int new_rules; /* are we creating a new rules file */
static int my_umask; /* default UMASK for files I create */
static int lockfd; /* file descriptor for locking baseline */
static int num_restrs = 0;
/*
* routine:
* main
*
* purpose:
* argument processing and primary dispatch
*
* returns:
* error codes per filesync.1 (ERR_* in filesync.h)
*
* notes:
* read filesync.1 in order to understand the argument processing
*
* most of the command line options just set some opt_ global
* variable that is later looked at by the code that actually
* implements the features. Only file names are really processed
* in this routine.
*/
int
{ int i;
int c;
int do_prune = 0;
char *srcname = 0;
char *dstname = 0;
/* keep the error messages simple */
argv[0] = "filesync";
/* gather together all of the options */
switch (c) {
case 'a': /* always scan for acls */
break;
case 'e': /* everything agrees */
break;
case 'h': /* halt on error */
break;
case 'm': /* preserve modtimes */
break;
case 'n': /* notouch */
opt_notouch = TRUE;
break;
case 'q': /* quiet */
break;
case 'v': /* verbose */
opt_verbose = TRUE;
break;
case 'y': /* yes */
break;
case 'D': /* debug options */
dbg_usage();
}
break;
case 'E': /* error simulation */
if (dbg_set_error(optarg)) {
err_usage();
}
opt_errors = TRUE;
break;
case 'f': /* force conflict resolution */
switch (optarg[0]) {
case 's':
break;
case 'd':
break;
case 'o':
break;
case 'n':
break;
default:
c, optarg);
break;
}
break;
case 'o': /* one way propagation */
switch (optarg[0]) {
case 's':
break;
case 'd':
break;
default:
c, optarg);
break;
}
break;
case 'r': /* restricted reconciliation */
if (num_restrs < MAX_RLIST)
else {
}
break;
case 's':
errs |= ERR_MISSING;
break;
case 'd':
errs |= ERR_MISSING;
break;
default:
case '?':
break;
}
/* if we have file names, we need a source and destination */
if (srcname == 0) {
}
if (dstname == 0) {
}
}
/* check for simple usage errors */
usage();
}
/* locate our baseline and rules files */
if (c = findfiles())
exit(c);
/* figure out file creation defaults */
whoami();
/* read in our initial baseline */
errs |= c;
/* read in the rules file if we need or have rules */
} else if (!new_rules)
/* if anything has failed with our setup, go no further */
if (errs) {
}
/*
* figure out whether or not we are willing to do a one-sided
* analysis (where we don't even look at the other side. This
* is an "I'm just curious what has changed" query, and we are
* only willing to do it if:
* we aren't actually going to do anything
* we have a baseline we can compare against
* otherwise, we are going to insist on being able to access
* both the source and destination.
*/
if (opt_notouch && !new_baseline)
/*
* there are two interested usage scenarios:
* file names specified
* create new rules for the specified files
* evaulate and reconcile only the specified files
* no file names specified
* use already existing rules
*/
/* figure out what base pair we're working on */
/* perverse default rules to avoid trouble */
if (new_rules) {
}
/*
* evaluate the specified base on each side,
* being careful to limit evaulation to new rules
*/
} else {
/* note any possible evaluation restrictions */
for (i = 0; i < num_restrs; i++)
/*
* we can only prune the baseline file if we have done
* a complete (unrestricted) analysis.
*/
if (i == 0)
do_prune = 1;
/* evaulate each base on each side */
}
}
/* if anything serious happened, skip reconciliation */
}
/* analyze and deal with the differenecs */
/* see if there is any dead-wood in the baseline */
if (do_prune) {
c = prune();
if (c > 0 && opt_verbose)
}
/* print out a final summary */
summary();
/* update the rules and baseline files (if needed) */
/* just returning ERR_RESOLVABLE upsets some people */
errs = 0;
/* all done */
cleanup(0);
return (errs);
}
/*
* routine:
* usage
*
* purpose:
* print out a usage message
*
* parameters:
* none
*
* returns:
* none
*
* note:
* the -D and -E switches are for development/test/support
* use only and do not show up in the general usage message.
*/
static void
usage(void)
{
}
/*
* routine:
* confirm
*
* purpose:
* to confirm that the user is willing to do something dangerous
*
* parameters:
* warning message to be printed
*
* returns:
* void
*
* notes:
* if this is a "notouch" or if the user has pre-confirmed,
* we should not obtain the confirmation and just return that
* the user has confirmed.
*/
void
/* if user pre-confirmed, we don't have to ask */
if (opt_yes || opt_notouch)
return;
/* explain the problem and prompt for confirmation */
/* if the user doesn't kill us, we can continue */
/* close the files and return */
}
void
{
}
/*
* routine:
* findfiles
*
* purpose:
* to locate our baseline and rules files
*
* parameters:
* none
*
* returns:
* error mask
* settings of file_base and file_rules
*
* side-effects:
* in order to keep multiple filesyncs from running in parallel
* we put an advisory lock on the baseline file. If the baseline
* file does not exist we create one. The unlocking (and deletion
* of extraneous baselines) is handled in cleanup.
*/
static errmask_t
findfiles(void) /* find rule and baseline files */
{ char *s, *where;
int ret;
/* figure out where the files should be located */
s = getenv("FILESYNC");
/* see if we got a viable name */
if (where == 0) {
return (ERR_FILES);
}
/* try to form the name of the rules file */
/* if we cannot find a proper rules file, look in the old place */
/* if we couldn't find that either, go with new name */
file_rules = s;
} else
file_rules = s;
/* try to form the name of the baseline file */
}
/*
* in order to lock out other filesync programs we need some
* file we can lock. We do an advisory lock on the baseline
* file. If no baseline file exists, we create an empty one.
*/
if (new_baseline)
else
if (lockfd < 0) {
} else {
if (ret < 0) {
}
return (errs);
}
/*
* routine:
* cleanup
*
* purpose:
* to clean up temporary files and locking prior to exit
*
* paremeters:
* error mask
*
* returns:
* void
*
* notes:
* if there are no errors, the baseline file is assumed to be good.
* Otherwise, if we created a temporary baseline file (just for
* locking) we will delete it.
*/
static void
{
/* unlock the baseline file */
/* see if we need to delete a temporary copy */
if (errmask && new_baseline) {
}
}
/*
* routine:
* check_access
*
* purpose:
* to determine whether or not we can access an existing file
* or create a new one
*
* parameters:
* name of file (in a clobberable buffer)
* pointer to new file flag
*
* returns:
* error mask
* setting of the new file flag
*
* note:
* it is kind of a kluge that this routine clobbers the name,
* but it is only called from one place, it needs a modified
* copy of the name, and the one caller doesn't mind.
*/
static errmask_t
{ char *s;
/* start out by asking for what we want */
*newflag = 0;
return (0);
}
/* if the problem is isn't non-existance, lose */
*newflag = 0;
return (ERR_FILES);
}
/*
* the file doesn't exist, so there is still hope if we can
* write in the directory that should contain the file
*/
*newflag = 1;
/* truncate the file name to its containing directory */
for (s = name; s[1]; s++);
while (s > name && *s != '/')
s--;
if (s > name)
*s = 0;
else if (*s == '/')
s[1] = 0;
else
name = ".";
/* then see if we have write access to the directory */
return (0);
return (ERR_FILES);
}
/*
* routine:
* whoami
*
* purpose:
* is on files that I create.
*/
static void
whoami()
{
}