This is rcvs_sync.c in view mode; [Download] [Up]
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License
* as specified in the README file that comes with the CVS 1.3 kit.
*/
#include "cvs.h"
/* rcvs: */
#include "rcvs.h"
#include "patchlevel.h"
static char *current = NULL;
static char *distfile;
static char *distfile2;
static FILE *distfp = NULL;
static char *cp = NULL;
static int sync_root_only = FALSE;
#if __STDC__
int checkout (int argc, char **argv);
int history (int argc, char **argv);
int patch (int argc, char **argv);
int rtag (int argc, char **argv);
int rcvs_sync_add (int argc, char **argv);
int rcvs_sync_commit (int argc, char **argv);
int rcvs_sync_history (int argc, char **argv);
int rcvs_sync_import (int argc, char **argv);
int rcvs_sync_rdiff (int argc, char **argv);
int rcvs_sync_remove (int argc, char **argv);
int rcvs_sync_rtag (int argc, char **argv);
#else
int checkout ();
int history ();
int patch ();
int rtag ();
int rcvs_sync_add ();
int rcvs_sync_commit ();
int rcvs_sync_history ();
int rcvs_sync_import ();
int rcvs_sync_rdiff ();
int rcvs_sync_remove ();
int rcvs_sync_rtag ();
#endif /* __STDC__ */
struct cmd
{
char *fullname;
char *nick1;
char *nick2;
int (*func) ();
};
static struct CMd
{
char *fullname;
int (*func) ();
int check_error;
} CMds [] =
{
{ "add", rcvs_sync_add, 0 },
{ "checkout", checkout, 1 },
{ "commit", rcvs_sync_commit, 1 },
{ "history", rcvs_sync_history, 0 },
{ "import", rcvs_sync_import, 0 },
{ "rdiff", rcvs_sync_rdiff, 0 },
{ "remove", rcvs_sync_remove, 0 },
{ "rtag", rcvs_sync_rtag, 0 },
{ NULL, NULL },
};
/* error message from rdist */
struct RMsg
{
char *keyword; /* error keywords */
char *suggestion; /* suggestion, fix */
int at_head; /* keywords is at the head of message*/
};
/* the order of this table is alphabetical, but if a message is a subset of
another, make sure the longer message is before the shorter one, else
the longer one will never be detected */
struct RMsg rmsg[] =
{
{ "Connection timed out", "check host can rsh to destination, then try again", 0 },
{ "Login incorrect.", "check user name in network address", 1},
{ "No more processes.\".", "reduce # of processes, i.e. reduce #windows", 0},
{ "No space left on device", "clean up disk space", 0},
{ "Permission denied.", "check .rhosts file", 1},
{ "Permission is denied.", "check .rhosts file", 0},
{ "rcmd: socket: Permission denied",
" 1. check rsh is working 2. check owner of rdist is root 2. check s bit of rdist", 0},
{ "Permission denied", "check write access of destination", 0},
{ "rdist: connection failed", "check host can rsh to destination, then try again", 1 },
{ "rdist: lost connection", "check host can rsh to destination, then try again", 1 },
{ "syntax error", "rdist problem", 0},
{ "The file access permissions do not allow the specified action.",
"1. check write access of destination 2. check s bit of rdist", 0},
{ "The remote user login is not correct.",
"check user name in net address", 0},
{ "timed out", "check host can rsh to destination, then try again", 0 },
{ "Too many processes already exist.\".", "reduce # of processes", 0},
{ "Unknown host", "check host name", 0},
{ "unknown host", "check host name", 0},
{ NULL, " ", 0},
};
/* warning fuzzy message from rdist to be filtered out */
struct WMsg
{
char *keyword; /* warning keywords */
int at_head; /* keywords is at the head of message*/
};
struct WMsg wmsg[] =
{
{ "Not owner", 0},
{ "Operation not permitted.", 0},
{ NULL, 0},
};
/* rcvs: sync from root to clone (sync forward) */
int
rcvs_Sync (argc, argv, cm)
int argc;
char *argv[];
struct cmd *cm;
{
int err = 0;
struct CMd *CM;
extern char *version_rcvs;
if (!quiet)
fprintf (stderr, "(%s on server)\n", version_rcvs);
/* turn off -n in phase 1 */
if (noexec && rcvs_sync)
noexec = FALSE;
/* change stdout and stderr to line-buffered mode */
(void) setlinebuf(stderr);
(void) setlinebuf(stdout);
for (CM = CMds; CM->fullname; CM++)
if (!strcmp (cm->fullname, CM->fullname))
break;
if (!CM->fullname)
error (1, 0, "rcvs_Sync: bad command '%s'", cm->fullname);
rcvs_sync_check_error = CM->check_error;
err = (*(CM->func)) (argc, argv);
if (trace)
fprintf ( stderr, "-> rcvs_Sync: error from %s = %d\n", CM->fullname, err);
/* if we go this far, this is a successful sync,
* this is the only way to tell that cvs on server is working.
* CVSROOT= is a signal that CVS sync operation is successful.
*/
if (!err)
{
fprintf(stderr,"CVSROOT=%s\n",CVSroot);
if (ver_rcvs_client >=67)
fprintf(stderr, "SERVER_VERSION=%d\n", ver_rcvs);
}
exit(err);
}
/* rcvs: Add directory to directory list */
int
rcvs_Add_Dirlist ( mlist, prepath, realdir)
List **mlist;
char *prepath;
char *realdir;
{
char repository[PATH_MAX];
char *cp;
int err;
if (*mlist == NULL)
*mlist = getlist ();
sprintf (repository, "%s/%s", prepath, realdir);
cp = repository + strlen(CVSroot);
*cp = '\0';
if (strcmp (repository, CVSroot) != 0)
error (1, 0, "rcvs_Add_Dirlist: bug #1 %s\n", repository);
else if (! isdir (CVSroot))
error (1, 0, "rcvs_Add_Dirlist: bug #2 %s does not exists\n", CVSroot);
cp += 1;
if (strncmp(cp, "/", 1) == 0)
cp += 1;
(void) addlist (mlist, cp);
if (trace)
fprintf(stderr, "-> directory: %s\n", cp);
return (0);
}
/* rcvs: Add file to file list */
int
rcvs_Add_filelist ( mlist, dir, filename )
List **mlist;
char *dir;
char *filename;
{
char repository[PATH_MAX];
char *cp;
if (*mlist == NULL)
*mlist = getlist ();
if (rcvs_sync)
(void) sprintf (repository, "%s/%s,v", dir, filename);
else
error(1, 0, "rcvs_Add_filelist: bug #1\n" );
if (strncmp (repository, CVSroot, strlen(CVSroot)) != 0)
{
error (0, 0, "rcvs_Add_filelist: bug #3, repository= %s", repository);
error (1, 0, "repository does not match %s: %s", CVSROOT_ENV, CVSroot);
}
if (! isfile (repository)) /* file not exist */
{
cp = repository+strlen(CVSroot)+1;
if (rcvs_sync_forward)
fprintf( stderr, "REMOVE=%s\n",cp);
else
(void) addlist ( &rcvs_rmlist, cp);
if (trace)
fprintf ( stderr, "no file: %s\n", cp);
}
else
{
cp = repository+strlen(CVSroot)+1;
(void) addlist ( mlist, cp);
if (!quiet)
fprintf(stderr, "file: %s\n", cp);
}
/* add Attic file also */
{
(void) sprintf (repository, "%s/%s/%s,v", dir, CVSATTIC, filename);
if (! isfile (repository))
{
cp = repository+strlen(CVSroot)+1;
if (rcvs_sync_forward)
fprintf(stderr, "REMOVE=%s\n",cp);
else
(void) addlist ( &rcvs_rmlist, cp);
if (trace)
fprintf ( stderr, "no file: %s\n", cp);
}
else
{
cp = repository+strlen(CVSroot)+1;
(void) addlist ( mlist, cp);
if (!quiet)
fprintf(stderr, "file: %s\n", cp);
}
}
return (0);
}
/* rcvs: Add directory to chmod directory list */
int
rcvs_Add_chmodlist ( mlist, repository, update_dir, realdir )
List **mlist;
char *repository;
char *update_dir; /* NOT USED !! */
char *realdir;
{
char *cp;
char dir[PATH_MAX];
int err;
if (*mlist == NULL)
*mlist = getlist ();
/* derive relative path of directory */
if ( strcmp(realdir, ".") == 0)
{
if (strncmp (repository, CVSroot, strlen (CVSroot)) != 0)
error (1, 0,
"rcvs_Add_chmodlist: bug #1 %s does not match CVSROOT %s\n",
repository, CVSroot);
cp = repository + strlen(CVSroot) + 1;
sprintf (dir, "%s", cp);
}
else if ( strcmp(update_dir, "") == 0)
sprintf (dir, "%s", realdir);
else
{
cp = repository + strlen(CVSroot) + 1;
sprintf (dir, "%s/%s", cp, realdir);
}
/* add relative path of directory to list */
(void) addlist ( mlist, dir);
if (!quiet)
fprintf( stderr, "chmod dir: %s\n", dir);
return(0);
}
/* rcvs: cleanup temporary directory */
int rcvs_Cleanup()
{
char tmp[PATH_MAX];
(void) sprintf (tmp, "rm -r -f %s", CVSADM);
(void) system (tmp);
return (0);
}
/* rcvs: get Group/Access attribute of directory */
int
rcvs_GetAttr (p)
Node *p;
{
List *dirlist = NULL;
char *dir;
char *olddir;
char repository[PATH_MAX];
olddir = current;
sprintf (repository, "%s/%s", current, p->key);
/* if not directory, simply return */
if (!isdir(repository))
error (0, 0, "rcvs_GetAttr: #1 %s is not a directory\n",
repository);
dir = repository + strlen(CVSroot) + 1;
if (trace)
fprintf(stderr, "-> rcvs_GetAttr: dir=%s\n", dir);
dirlist=Find_Dirs ( repository, W_REPOS);
current = repository;
if ( strcmp(p->key, ".") == 0 || !walklist (dirlist, rcvs_GetAttr))
{
struct stat sbuf;
struct group *Gid;
if ( stat(current, &sbuf) == 0)
Gid = getgrgid(sbuf.st_gid);
if (Gid != NULL)
fprintf(stderr, "GROUP/MODE=%s %s %o \n",
dir, Gid->gr_name, sbuf.st_mode);
}
current = olddir;
return (0);
}
/* rcvs: Print key of one node from module list into distfile */
int
rcvs_Print_Mod (p)
Node *p;
{
fprintf(distfp,"%s ",p->key);
return (0);
}
/* rcvs: create input file (distfile) for rdist */
int rcvs_Rdist_init ()
{
char tmp[PATH_MAX];
int err;
/* rcvs: use /tmp/RCVS as working directory */
cp = RCVSTMP;
if ( !isdir(cp) )
{
if ( mkdir (cp, 0777) )
error (1, 0, "sorry, not enough access to %s\n", cp);
else if ( chmod (cp, 0777))
error (1, 0, "sorry, cannot chmod 777 for %s\n", cp);
}
if ( (chdir (cp) < 0))
error (1, 0, "cannot chdir to %s", cp);
/* rcvs: create a dummy working directory in /tmp/RCVS for user */
(void) sprintf( tmp,"%s/%s.%d", RCVSTMP, RCVSuser, getpid ());
cp = rcvs_tmpname = xstrdup(tmp);
if ( !isdir(cp) )
if ( mkdir (cp, 0777) )
error (1, 0, "sorry, not enough access to %s",RCVSTMP);
if ( (chdir (cp) < 0))
error (1, 0 , "cannot chdir to %s", cp);
/* rcvs: open distfile */
(void) sprintf ( tmp,"%s/distfile", rcvs_tmpname);
distfile = xstrdup (tmp);
(void) sprintf ( tmp,"%s/distfile.%s", RCVSTMP, RCVSuser);
distfile2 = xstrdup (tmp);
distfp = open_file (distfile, "w+");
if (distfp == NULL)
err = 1;
else
err = 0;
return (err);
}
/* examine output from rsh.
*/
int
rcvs_check_rsh_output(line)
char * line;
{
int err = 0;
struct RMsg *Rm;
int size;
size = strlen(line);
/* check rsh error messages */
for (Rm = rmsg; Rm->keyword; Rm++)
{
int ksize;
ksize = strlen(Rm->keyword);
if (Rm->at_head)
{
if (!strncmp (Rm->keyword, line, strlen(Rm->keyword)))
{
err = 1 ;
break;
}
}
else
{
if (0 && trace && size > ksize) /* set 1 to debug */
fprintf(stderr, "-> rcvs_check_rdist_output: %s",
line+size-ksize-1);
if (size > ksize && !strncmp (Rm->keyword,
line+size-ksize-1, ksize))
{
err = 1 ;
break;
}
}
}
if (err)
fprintf (stderr, "suggestion: <<%s>>\n", Rm->suggestion);
return (err);
}
/* examine stderr for rdist.
* Why check error for rdist? Because USC's rdist does not return error code
* properly.
* return code: 1=error 2=fuzzy warning (can be filtered)
*/
int
rcvs_check_rdist_output(line)
char * line;
{
int err = 0;
struct RMsg *Rm;
struct WMsg *Wm;
int size;
size = strlen(line);
/* check rsh & rdist error messages */
for (Rm = rmsg; Rm->keyword; Rm++)
{
int ksize;
ksize = strlen(Rm->keyword);
if (Rm->at_head)
{
if (!strncmp (Rm->keyword, line, strlen(Rm->keyword)))
{
err = 1 ;
break;
}
}
else
{
if (0 && trace && size > ksize) /* set 1 to debug */
fprintf(stderr, "-> rcvs_check_rdist_output: %s",
line+size-ksize-1);
if (size > ksize && !strncmp (Rm->keyword,
line+size-ksize-1, ksize))
{
err = 1 ;
break;
}
}
}
if (err)
fprintf (stderr, "| suggestion: <<%s>>\n", Rm->suggestion);
/* filter out excessive rdist fuzzy warm messages */
for (Wm = wmsg; Wm->keyword; Wm++)
{
int ksize;
ksize = strlen(Wm->keyword);
if (Wm->at_head)
{
if (!strncmp (Wm->keyword, line, strlen(Wm->keyword)))
{
err = 2;
break;
}
}
else
{
if (0 && trace && size > ksize) /* set 1 to debug */
fprintf(stderr, "-> rcvs_check_rdist_output: %s",
line+size-ksize-1);
if (size > ksize && !strncmp (Wm->keyword,
line+size-ksize-1, ksize))
{
err = 2;
break;
}
}
}
return (err);
}
/* rcvs: run rdist to send modules over */
int rcvs_Rdist()
{
FILE *fp;
FILE *fp_err;
char line[PATH_MAX];
char tmp[PATH_MAX];
char *cvsrec;
int err = 0;
int err2 = 0;
int Err = 0;
register int i;
fprintf(distfp,"SRC = (");
if (!sync_root_only)
{
/*if ( (rcvs_dirlist == NULL && rcvs_filelist == NULL) && !quiet)
error (0, 0, "both dirlist and filelist are empty");*/
if (rcvs_dirlist != NULL)
{
if (trace)
rcvs_dump_list ("#dirlist: ", rcvs_dirlist );
(void) walklist (rcvs_dirlist, rcvs_Print_Mod );
}
if (rcvs_filelist != NULL)
{
if (trace)
rcvs_dump_list ("#filelist: ", rcvs_filelist );
(void) walklist (rcvs_filelist, rcvs_Print_Mod );
}
}
fprintf(distfp,"CVSROOT)\n");
if (rcvs_cvsrec == NULL) /* rdist receiver */
cvsrec = RCVSuser;
else
cvsrec = rcvs_cvsrec;
fprintf (distfp,"HOST = (%s@%s)\n", cvsrec, RCVShost);
/* if client is eariler than cvs-0.6.7, send commitlog over */
if (rcvs_sync_forward && ver_rcvs_client < 67)
fprintf (distfp,"EXCEPT = (CVSROOT/%s )\n", CVSROOTADM_HISTORY);
else
{
/* in phase 3, always send history.tmp and commitlog.tmp back */
if (rcvs_sync_backward)
fprintf (distfp,"EXCEPT = (CVSROOT/%s CVSROOT/%s)\n",
CVSROOTADM_HISTORY, CVSROOTADM_COMMITLOG);
/* in phase 2, send neither history nor commitlog over */
else
fprintf (distfp,"EXCEPT = (CVSROOT/%s CVSROOT/%s CVSROOT/%s CVSROOT/%s)\n",
CVSROOTADM_HISTORY, CVSROOTADM_COMMITLOG,
CVSROOTADM_HISTORY_NEW, CVSROOTADM_COMMITLOG_NEW);
}
if (trace)
{
if (rcvs_sync_forward && ver_rcvs_client < 67)
fprintf (stderr, "-> old rcvs client, send commitlog to client\n");
else if (rcvs_sync_backward)
fprintf (stderr, "-> always send commitlog.tmp to server\n");
}
fprintf(distfp,"${SRC} -> ${HOST}\n");
fprintf(distfp,"install ");
/*+IS*/
#ifdef USCrdist
fprintf(distfp,"-oremove,whole %s;\n", RCVSroot);
#else
/*-IS*/
fprintf(distfp,"-R ");
fprintf(distfp,"-w %s;\n", RCVSroot);
/*+IS*/
#endif
/*-IS*/
fprintf(distfp,"except ${EXCEPT};\n");
fprintf(distfp,"except_pat (CVSROOT/\\%s\\*);\n", RCVSLOCK);
(void) fclose (distfp);
copy_file (distfile, distfile2);
if (trace)
fprintf(stderr, "rdist %s to %s (at %s)\n", CVSroot, RCVSroot, RCVShost);
if ( (chdir (CVSroot) < 0))
error (1, errno, "cannot chdir to %s",CVSroot);
(void) sprintf (tmp,"rdist");
if (noexec)
(void) strcat (tmp, " -n");
if (quiet)
(void) strcat (tmp, " -q");
(void) sprintf (tmp+strlen(tmp)," -f %s", distfile);
(void) strcat (tmp, " 2>&1"); /* put all rdist output in stdout */
fprintf (stderr, "rdist modules to %s@%s\n", cvsrec, RCVShost);
if (trace)
fprintf (stderr, "-> %s\n", tmp);
{
fp = popen (tmp, "r");
/* since some version of rdist send output into stdout instead of
* stderr, we have to check error in both
*/
while (fgets (line, sizeof (line), fp))
{
Err = rcvs_check_rdist_output (line);
if (Err == 1)
{
err2 = 1; /* record error within a loop */
fprintf (stderr, "| %s", line);
break;
}
if (trace || Err != 2) /* not a fuzzy warning message */
fprintf (stderr, "| %s", line);
}
err = pclose (fp);
if (trace)
fprintf (stderr, "-> rcvs_Rdist: err from rdist msg=%d\n",
err2);
}
if (trace)
fprintf (stderr, "-> rcvs_Rdist: err from rdist=%d\n", err);
if (err2)
err = 1;
if (rcvs_sync_forward && err)
fprintf(stderr, "RDIST_STATUS=1\n");
/* send back CVSROOT= */
if (!err && rcvs_sync_forward)
{
/* collect group/mode attribute list */
current = CVSroot;
if ( ! sync_root_only)
addlist (&rcvs_chmodlist, ".");
addlist (&rcvs_chmodlist, CVSROOTADM);
walklist (rcvs_chmodlist, rcvs_GetAttr);
}
/* cleanup temporary file in /tmp/RCVS */
if (rcvs_tmpname != NULL)
{
sprintf (tmp,"rm -r -f %s", rcvs_tmpname);
(void) system (tmp);
}
return (err);
}
/* do synchorization for add */
int
rcvs_sync_add (argc, argv)
int argc;
char *argv[];
{
int err = 0;
if (!quiet)
fprintf (stderr, "check if it's in cvsroot already, ok if not\n");
err = (*checkout) (argc, argv);
/* signal ok if file not found under file mode */
if (err)
fprintf(stderr, "CVSROOT=%s\n",CVSroot);
return (err);
}
/* do synchorization for commit */
int
rcvs_sync_commit (argc, argv)
int argc;
char *argv[];
{
int err = 0;
if (!quiet)
fprintf (stderr, "check if it's in cvsroot already, ok if not\n");
err = (*checkout) (argc, argv);
/* signal ok if file not found under file mode */
if (err)
fprintf( stderr, "CVSROOT=%s\n",CVSroot);
return (err);
}
/* do history command on server and send result back */
int
rcvs_sync_history (argc, argv)
int argc;
char *argv[];
{
int err = 0;
rcvs_do_rdist = FALSE;
err = (*history) (argc, argv);
return (err);
}
/* do synchronization for import */
int
rcvs_sync_import (argc, argv)
int argc;
char *argv[];
{
int err = 0;
if (!quiet)
fprintf (stderr, "check if it's in cvsroot already, ok if not\n");
err = (*checkout) (argc, argv);
return (err);
}
/* do rdiff command on server directly */
int
rcvs_sync_rdiff (argc, argv)
int argc;
char *argv[];
{
int err = 0;
rcvs_do_rdist = FALSE;
err = (*patch) (argc, argv);
return (err);
}
/* do synchorization for remove */
int
rcvs_sync_remove (argc, argv)
int argc;
char *argv[];
{
int err = 0;
if (!quiet)
fprintf (stderr, "check if it's in cvsroot already, ok if not\n");
err = (*checkout) (argc, argv);
/* signal ok if file not found under file mode */
if (err)
fprintf( stderr, "CVSROOT=%s\n",CVSroot);
return (err);
}
/* do rtag command on server directly */
int
rcvs_sync_rtag (argc, argv)
int argc;
char *argv[];
{
int err = 0;
rcvs_do_rdist = FALSE;
err = (*rtag) (argc, argv);
return (err);
}
/*+IS*/
#ifdef __hpux
/*
* setlinebuf (FILE *fp)
*
* Routine to set line buffering on "fp".
*/
/* From: system@alchemy.chem.utoronto.ca (System Admin (Mike Peterson))
hp tricks
*/
int
setlinebuf (FILE *fp)
{
(void) setvbuf (fp, NULL, _IOLBF, 0);
return(0);
}
#endif /* __hpux */
/*-IS*/
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.