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

This is rcvs_lock.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.
 */

/* RCVS lock mechanism:

   There are four type of RCVS locks: 

  1. 'WFL' lock is set by write-type commands (add(directory), admin, ci, 
import, tag) issued by remote CVS that lock against any write-type command,
this lock protects the integrity of clone and main repository. This lock 
should also lock against read-type commands (add(file) diff export log
remove rtag status update) issued by remote CVS to protect the integrity of
the clone. 

  2. 'wfl' lock is set by write-type commands issued by local CVS that 
lock against any write-type commands issue by remote CVS, this lock 
protects the integrity of main repository. This lock does not lock against 
write-type commands, since it is handled by local CVS itself. (thus more 
than one local CVS users can do commit different modules in the same time).

  3. 'RFL' lock is set by read-type commands issued by remote CVS that 
lock against write-type commands issued by remote CVS, this lock protects 
the integrity of the clone. This lock does not lock against read-type 
commands, since they are all just copying files from main repository to 
clone. (thus more than one remote users can do update in the same time,
occasionally the read-lock set by local CVS in phase-2 may cause rdist
error, but this is a minor price we can afford).

  4. 'rfl' lock is set by read-type commands issued by local CVS that 
lock against write-type commands issued by remote CVS, this lock protects 
the integrity of the main repository. This lock does not lock against 
read-type commands issued by local CVS.
*/

#include "cvs.h"
/* rcvs: */
#include "rcvs.h"
#include "patchlevel.h"

static char *rmlist = NULL;
static char *rshtmp = NULL;
static char *adddirlist = NULL;
static char lockfile[PATH_MAX];

static char *lock_msg[] =
{ "local",
  "remote"
};

/* rcvs: lock errors */
int rcvs_lock_error (lockfile, msg)
    char *lockfile;
    char *msg;
{
    FILE *lockfp;
    char line[PATH_MAX];

    lockfp = open_file (lockfile, "r");
    (void) fgets (line, sizeof(line), lockfp);  
    /*line[32] = '\0';*/
    if (fclose (lockfp) == EOF)
        error (1, 0, "rcvs_lock_error: cannot close %s", lockfile);
    if (trace)
        fprintf(stderr, "-> rcvs_lock_error %s\n", msg);
    error (1, 0, "lock [%s] is set by %s\n consider using -U option (or try later if lock is recent)",
	   lockfile, line );
    return (0);
}  

/* rcvs: check locks */
int rcvs_Check_lock ()
{

    if (noexec) return(0);
    if (rcvs_native_CVS)                   /* local CVS */
    {
        if (rcvs_Uopt_unlock)  
	    rcvs_Clearlock_all ();

	if (index(rcvs_CM->phases,'3'))    /* write type commands */
	{  
	    if ( rcvs_lock_exist("WFL") && !rcvs_Uopt_unlock)
	        (void) rcvs_lock_error (lockfile, "#1/1");
	}    
	else                               /* read type commands */ 
	    if ( rcvs_lock_exist("WFL") && !rcvs_Uopt_unlock)
	        (void) rcvs_lock_error (lockfile, "#1/2");

	if (rcvs_Lopt_lock || index(rcvs_CM->phases,'3'))
	{
	    if ( rcvs_lock_exist("WFL"))
	        (void) rcvs_lock_error (lockfile, "#1/3");
            (void) rcvs_Setlock ("wfl");
	}    
    }

    else if (rcvs_native_RCVS)           /* remote CVS, client's side */
    {
	if (rcvs_CM == NULL)
	    error (1, 0, "rcvs_Check_lock: bug#1, rcvs_CM = NULL");
        if (rcvs_Uopt_unlock)  
	    rcvs_Clearlock_all ();

	if (index(rcvs_Popt_phases,'3'))   /* set write lock */
	{
	    if ( rcvs_lock_exist("WFL") && !rcvs_Uopt_unlock)
	        (void) rcvs_lock_error (lockfile, "#2/1");
	    if ( rcvs_lock_exist("RFL") && !rcvs_Uopt_unlock)
	        (void) rcvs_lock_error (lockfile, "#2/2");
	    (void) rcvs_Setlock ("WFL");
	    if (!index(rcvs_Popt_phases,'1'))   /* no phase 1 */
		(void) rcvs_set_phase3_lock ();
	}    
	else if (index(rcvs_Popt_phases,'8'))  /* set read lock */
	{
	    if ( rcvs_lock_exist("WFL") && !rcvs_Uopt_unlock)
	        (void) rcvs_lock_error (lockfile, "#2/3");
	    (void) rcvs_Setlock ("RFL");
	}    
    }

    else if (rcvs_sync_forward || rcvs_set_p3_lock) /* remote CVS, server*/ 
    {
        if (rcvs_Uopt_unlock)  
	    rcvs_Clearlock_all ();
	if (rcvs_Lopt_lock)
	{
	    if (!rcvs_Uopt_unlock)
	    {  
		if ( rcvs_lock_exist("WFL") && !rcvs_Uopt_unlock) 
	            (void) rcvs_lock_error (lockfile, "#3/1");
	        if ( rcvs_lock_exist("wfl") && !rcvs_Uopt_unlock) 
	            (void) rcvs_lock_error (lockfile, "#3/2");
	        if ( rcvs_lock_exist("rfl") && !rcvs_Uopt_unlock) 
	            (void) rcvs_lock_error (lockfile, "#3/3");
     	    }	

	    (void) rcvs_Setlock ("WFL");
	    if (rcvs_sync_forward)
	        fprintf(stderr, "CVSroot=%s\nRCVSLOCK=1\n", CVSroot);
	}    
    }

    return(0);
}

/* cleanup lock */
int 
rcvs_lock_exist (type)
     char *type;
{
    DIR *dirp;
    struct direct *dp;
    CONST char *regex_err;
    char tmp[PATH_MAX];
    char cvsrootadm[PATH_MAX];
    int found=0;
    
    sprintf (cvsrootadm, "%s/%s", CVSroot, CVSROOTADM);
    if ((dirp = opendir (cvsrootadm)) == NULL)
        error (1, 0, "cannot open directory %s", cvsrootadm);
    if (strcmp(type,"WFL") == 0)
        (void) sprintf (tmp, "^%s$", RCVSLOCK_WFL);
    else if (strcmp(type,"RFL") == 0)
        (void) sprintf (tmp, "^%s\\..*", RCVSLOCK_RFL);
    else if (strcmp(type,"wfl") == 0)
        (void) sprintf (tmp, "^%s\\..*", RCVSLOCK_wfl);
    else if (strcmp(type,"rfl") == 0)
        (void) sprintf (tmp, "^%s\\..*", RCVSLOCK_rfl);
    else 
        error (1, 0, "rcvs_lock_exist: bug #1");
    if ((regex_err = re_comp (tmp)) != NULL)
        error (1, 0, "%s", regex_err);
    while ((dp = readdir (dirp)) != NULL)
    {  
        (void) sprintf (tmp, "%s/%s", cvsrootadm, dp->d_name);
	if (re_exec (dp->d_name))       /* found a match, lock exist */
	{ 
	   found=1;
	   (void) sprintf (lockfile, "%s/%s", cvsrootadm, dp->d_name);
	   break;
	}   
   }				      
   (void) closedir (dirp);       
   return (found);    
}

/* cleanup lock */
int 
rcvs_Clearlock_all()
{
    char tmp[PATH_MAX];
    int ret = 0;
    (void) sprintf (tmp,"cd %s/%s; rm -f \\%s* \\%s* \\%s* \\%s*", 
		    CVSroot, CVSROOTADM, RCVSLOCK_WFL, RCVSLOCK_RFL, 
		    RCVSLOCK_wfl, RCVSLOCK_rfl);
    ret = system ( tmp );
    if (trace)
      fprintf(stderr, "rcvs_Clearlock_all: %s\n", tmp);
    return (ret);  
}

/* cleanup my lock */
int 
rcvs_Clear_my_lock()
{
    if (rcvs_lock_WFL_remote || rcvs_lock_WFL_local)
        (void) rcvs_Clearlock_WFL ();
    if (rcvs_lock_RFL)
	(void) rcvs_Clearlock ("RFL");
    if (rcvs_lock_wfl)	
	(void) rcvs_Clearlock ("wfl");
    if (rcvs_lock_rfl)	
	(void) rcvs_Clearlock ("rfl");
}

/* cleanup WFL lock */
int 
rcvs_Clearlock_WFL()
{
    char tmp[PATH_MAX];
    char lockfile[PATH_MAX];
    if (trace)
        fprintf(stderr, "-> rcvs_Clearlock_WFL:\n");

    /* rcvs: clear local lock */
    (void) sprintf( lockfile,"%s/CVSROOT/%s",CVSroot,RCVSLOCK_WFL);
    if ( ( rcvs_lock_WFL_local || rcvs_Uopt_unlock) && isreadable (lockfile))
    {
        if ( unlink_file (lockfile) )
	   error (1, 0, "cannot remove lockfile %s\n", lockfile);
	rcvs_lock_WFL_local = FALSE;
        if (trace)
	    fprintf(stderr, "-> remove local RCVS lock %s\n", lockfile);
    }

    /* rcvs: clear remote lock */
    if ( (rcvs_lock_WFL_remote || (rcvs_Uopt_unlock && rcvs_native_RCVS))
	  && RCVSroot != NULL )
    {  
        int err = FALSE;
        (void) sprintf( lockfile,"%s/CVSROOT/%s",RCVSroot,RCVSLOCK);
	{
	    if ( RCVSuser == NULL )
		RCVSuser = rcvs_username;
/*+IS*/
            (void) sprintf (tmp,"%s %s -l %s sh -c \"\' rm %s \'\"", 
			rshcmd, RCVShost, RCVSuser, lockfile );
/*-IS*/
	 }	
	 if (trace)
	     fprintf(stderr, "-> %s\n", tmp);
	 else 
             fprintf(stderr, "Remove lock from server\n");
	 err = system ( tmp );
	 if (err)
	     fprintf(stderr, "failed to remove remote lock \n");
	 else
	     rcvs_lock_WFL_remote = FALSE;
    }   
}

/* cleanup lock RFL, wfl, rfl */
int 
rcvs_Clearlock(type)
     char *type;
{
    char tmp[PATH_MAX];
    char lockfile[PATH_MAX];
    FILE *lockfp;
    if (trace)
        fprintf(stderr, "-> rcvs_Clearlock: %s\n", type);

    if (strcmp(type,"RFL") == 0)
        (void) sprintf( lockfile,"%s/CVSROOT/%s.%d",CVSroot,RCVSLOCK_RFL, 
		   getpid ());
    else if (strcmp(type,"wfl") == 0)
        (void) sprintf( lockfile,"%s/CVSROOT/%s.%d",CVSroot,RCVSLOCK_wfl, 
		   getpid ());
    else if (strcmp(type,"rfl") == 0)
        (void) sprintf( lockfile,"%s/CVSROOT/%s.%d",CVSroot,RCVSLOCK_rfl, 
		   getpid ());
    else 
        error (1, 0, "rcvs_Clearlock: bug #1");

    if ( isreadable (lockfile))
    {
        if ( unlink_file (lockfile) )
	   error (1, 0, "cannot remove lockfile %s\n", lockfile);
        if (trace)
	    fprintf(stderr, "-> remove lock %s\n", lockfile);

	if (strcmp(type,"RFL") == 0)
	    rcvs_lock_RFL = FALSE;
	else if (strcmp(type,"wfl") == 0)
	    rcvs_lock_wfl = FALSE;
	else 
	    rcvs_lock_rfl = FALSE;
    }
    else 
        error (0, 0, "lock file %s not found\n", lockfile);
}


/* rcvs: set RCVS lock in $CVSroot/CVSROOT 
 *   CVSroot could be either CVSROOT or RCVSDIR
 */
int rcvs_Setlock (type)
     char *type;
{
    char host[PATH_MAX];
    char line[PATH_MAX];
    FILE *fp;
    FILE *lockfp;
    char *cp;
    char *msg;
    int err = 0;
    {
        if (rcvs_sync_forward)
	    (void) strcpy (host, RCVShost);
	else
	    (void) gethostname ( host, sizeof(host) );
        cp = index( host, '.');
        if ( cp != NULL)
	    *cp = '\0';
    }   

    fp = popen ("date", "r"); 
    while (fgets (line, sizeof (line), fp))
	    ;
    (void) pclose (fp);

    if (strcmp(type,"WFL") == 0)
    {
        (void) sprintf( lockfile,"%s/CVSROOT/%s",CVSroot,RCVSLOCK_WFL);
	msg = lock_msg[1];
    }
    else if (strcmp(type,"wfl") == 0)
    {
        (void) sprintf( lockfile,"%s/CVSROOT/%s.%d",CVSroot,RCVSLOCK_wfl, 
		   getpid ());
	msg = lock_msg[0];
    }
    else if (strcmp(type,"RFL") == 0)
    {
        (void) sprintf( lockfile,"%s/CVSROOT/%s.%d",CVSroot,RCVSLOCK_RFL, 
		   getpid ());
	msg = lock_msg[1];
    }
    else if (strcmp(type,"rfl") == 0)
    {
        (void) sprintf( lockfile,"%s/CVSROOT/%s.%d",CVSroot,RCVSLOCK_rfl, 
		   getpid ());
	msg = lock_msg[0];
    }
    else 
        error (1, 0, "rcvs_Setlock: bug #2");
	 
    lockfp = open_file (lockfile, "w+");
    *(line+strlen(line)-1) = '\0';
    if (command_name == NULL)
        error (1, 0, "rcvs_Setlock: bug #1\n");
    (void) fprintf (lockfp, "%s at [%s] from %s, %s-%s-lock,", 
		    rcvs_username, line, host, msg, command_name);
  
    err = fclose (lockfp);
    if (err)
        error (1, 0, "fail to set lock in %s", lockfile);
    else if (trace)
        fprintf(stderr, "-> rcvs_Setlock: set %s lock in %s\n", type, 
		lockfile);

    if (strcmp(type,"WFL") == 0)
        rcvs_lock_WFL_local = TRUE;
    else if (strcmp(type,"RFL") == 0)
        rcvs_lock_RFL = TRUE;
    else if (strcmp(type,"wfl") == 0)
        rcvs_lock_wfl = TRUE;
    else 
        rcvs_lock_rfl = TRUE;
    return err;
}

/* rcvs: do chmod on main repository on server for added directory */
int
rcvs_add_dir_chmod ( p )
    Node *p;
{
    struct stat sbuf;
    char repository[PATH_MAX];
    register int i;
    int err = 0;
    sprintf (repository, "%s/%s", CVSroot, p->key);
    if ( stat(repository, &sbuf) == 0)
        sprintf (adddirlist+strlen(adddirlist), 
		 "chmod %o %s/%s;", sbuf.st_mode, RCVSroot, p->key);
    return (0);
}

/* collect files to be removed */
int
rcvs_do_rmlist (p)
    Node *p;
{
    sprintf(rmlist+strlen(rmlist),"%s/%s ", RCVSroot, p->key);
    return (0);
}

/* 1. Append history file to main repository. 
 * 2. Cleanup lock for commit. 
 * 3. Remove files if requested.
 * 4. chmod for added directories in main repository.
*/
int 
rcvs_hist_and_lock( err , cvsroot, rcvsuser, rcvshost, rcvsroot, rcvsdir)
    int err; 
    char *cvsroot;
    char *rcvsuser;
    char *rcvshost;
    char *rcvsroot;
    char *rcvsdir;
{
    char line[PATH_MAX];
    char lockfile[PATH_MAX];
    char hist_svr[PATH_MAX];
    char hist_clt[PATH_MAX];
    int Err;
    int send = 0;
    int msgfile_size = 0;

    if (trace)
      fprintf (stderr, "-> rcvs_hist_and_lock\n");
    
    if (rcvs_msgfile != NULL)
        msgfile_size = filesize(rcvs_msgfile);
    if (trace) 
       fprintf (stderr, "-> size of msgfile=%d\n", msgfile_size);
    rshtmp = xmalloc (PATH_MAX+msgfile_size);   /* make a big buffer */
    rshtmp[0] = '\0';
    lockfile[0] = '\0';
    hist_svr[0] = '\0';
    hist_clt[0] = '\0';
    (void) sprintf( lockfile,"%s/CVSROOT/%s",cvsroot,RCVSLOCK);
    if ( (rcvs_lock_WFL_local || rcvs_Uopt_unlock) && isreadable (lockfile))
        if ( unlink_file (lockfile) )
           error (1, 0, "cannot remove lockfile %s\n", lockfile);
        else
	   rcvs_lock_WFL_local = FALSE;

    /* append history file to the one in main repository */    
    (void) sprintf( hist_clt,"%s/CVSROOT/%s",cvsroot,CVSROOTADM_HISTORY_NEW);
    (void) sprintf( hist_svr,"%s/CVSROOT/%s",rcvsroot,CVSROOTADM_HISTORY);
    if ( RCVSuser == NULL )
        RCVSuser = rcvs_username;

    (void) sprintf( line, "%s/CVSROOT/%s", CVSroot, CVSROOTADM_HISTORY_NEW);

    /* if no phase-3 and has history, pipe history file
     * otherwise do not pipe history file */
    if ((!index (rcvs_Popt_phases,'3')) && filesize(line))
/*+IS*/
        (void) sprintf (rshtmp,"cat %s | %s %s -l %s \" sh -c \\\" cat - >> %s;",
                hist_clt, rshcmd, rcvshost, RCVSuser, hist_svr );
    else
        (void) sprintf (rshtmp,
		"%s %s -l %s \" sh -c \\\"" , rshcmd, rcvshost, RCVSuser);
/*-IS*/

    /* history file is not empty*/
    if (filesize(line) && (index(rcvs_Popt_phases,'3') ))
    {
        (void) sprintf (rshtmp+strlen(rshtmp),
		"cat %s/CVSROOT/%s >> %s/CVSROOT/%s; rm -f %s/CVSROOT/%s;", 
		rcvsroot, CVSROOTADM_HISTORY_NEW,
		rcvsroot, CVSROOTADM_HISTORY,
		rcvsroot, CVSROOTADM_HISTORY_NEW);
	send = 1;
    }			

    /* commitlog file is not empty*/
    (void) sprintf( line, "%s/CVSROOT/%s", CVSroot, CVSROOTADM_COMMITLOG_NEW);
    if (filesize(line)  && (index(rcvs_Popt_phases,'3') ))
    {
	(void) sprintf (rshtmp+strlen(rshtmp),
		"cat %s/CVSROOT/%s >> %s/CVSROOT/%s; rm -f %s/CVSROOT/%s; ", 
		rcvsroot, CVSROOTADM_COMMITLOG_NEW,
		rcvsroot, CVSROOTADM_COMMITLOG,
		rcvsroot, CVSROOTADM_COMMITLOG_NEW);
	send = 1;
    }			

    /* rcvs: cleanup lock on server */
    if ( ( rcvs_lock_WFL_remote || rcvs_Uopt_unlock ) && rcvsroot != NULL )
    {  
	(void) sprintf( lockfile,"%s/CVSROOT/%s",rcvsroot,RCVSLOCK);
	(void) sprintf (rshtmp+strlen(rshtmp),"rm %s; ", lockfile );
        if (!trace && err == 1)
           fprintf (stderr, "remove lock on server\n");
	send = 1;
    }   

    /* chmod for added directory */
    if (strcmp (rcvs_CM->fullname, "add") == 0)
    {  
	adddirlist = xmalloc (PATH_MAX);
	adddirlist[0] = '\0';
        (void) walklist (rcvs_dirlist, rcvs_add_dir_chmod);
	(void) sprintf (rshtmp+strlen(rshtmp)," %s ", adddirlist);
	free (adddirlist);
	send = 1;
    }	

    /* remove files if list not empty */
    if (rcvs_rmlist != NULL)
    {
	rmlist = xmalloc (PATH_MAX);
	rmlist[0] = '\0';
        (void) walklist (rcvs_rmlist, rcvs_do_rmlist);
	(void) sprintf (rshtmp+strlen(rshtmp),"rm -f %s; ", rmlist);
	free (rmlist);
	send = 1;
    }

    /* execute message from in-shell CVS, mostly to execute shell script */
    if (rcvs_msgfile != NULL && isfile(rcvs_msgfile))
    {
        sprintf(rshtmp+strlen(rshtmp),"CVSROOT=%s; export CVSROOT; ", 
		RCVSroot);
        msgfp = open_file (rcvs_msgfile,"r");
	while (fgets (line, sizeof (line), msgfp))
	    sprintf(rshtmp+strlen(rshtmp),"%s", line);
	if (fclose (msgfp) == EOF)
	    error (1, 0, "rcvs_hist_and_lock: cannot close %s", rcvs_msgfile);
	send = 1;
    }

    (void) sprintf (rshtmp+strlen(rshtmp),"\\\"\"" );
    if (trace && send)
	fprintf(stderr, "-> %s\n", rshtmp);
    if (send)
        Err = system ( rshtmp );

    if (!Err) 
        rcvs_lock_WFL_remote = FALSE;
    free (rshtmp);                            /* free buffer */
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.