ftp.nice.ch/pub/next/unix/developer/rcvs.0.7.9.s.tar.gz#/src/rcvs_sync.c

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.