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

This is rcvs_main.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"
#include "rcvs.h"
#include "patchlevel.h"

static FILE *fp;
static struct cmd *cm;
static char *CurDir = NULL;
static char *host = NULL;
static char *margv[MAXARG];
static char msg1[] = "CVSROOT ----> clone";
static char msg2[] = "CVSROOT <---- clone";
static char bar[] = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
                    "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
static char *rcvsid = NULL;
static int Margc = 0;
static int margc = 0;
static int lock_checked = FALSE;
static int get_CVSROOT = FALSE;
static int lockSet_onServer = FALSE;
static int phase1_err_reported = FALSE;
static char *cvsroot_gid;
static int cvsroot_mode;
static int local = FALSE;

/* version number */
int ver_rcvs_client = 0;
int ver_rcvs_server = 0;

/* flow control variables */
int rcvs_inshell = FALSE;
int rcvs_native = FALSE;
int rcvs_native_CVS = FALSE;
int rcvs_native_RCVS = FALSE;
int rcvs_set_p3_lock = FALSE;
int rcvs_sync = FALSE;
int rcvs_sync_backward = FALSE;
int rcvs_sync_forward = FALSE;
int rcvs_sync_check_error = 1;
int rcvs_copt_change_repos = FALSE;
int rcvs_Copt_change_repos = FALSE;
int rcvs_Ropt_remote = FALSE;
char *rcvs_Popt_phases = NULL;

/* lock variables */
int rcvs_lock_WFL_local = FALSE;
int rcvs_lock_WFL_remote = FALSE;
int rcvs_lock_RFL = FALSE;
int rcvs_lock_wfl = FALSE;
int rcvs_lock_rfl = FALSE;
int rcvs_Uopt_unlock = FALSE;
int rcvs_Lopt_lock = FALSE;
int rcvs_lock_phase3 = FALSE;

char *rcvs_ID = NULL;
char *rcvs_Id = NULL;
char *CVSroot_v = NULL;
char *CVSroot_n = NULL;
char *CVSrootr_v = NULL;
char *CVSrootr_n = NULL;
char *CVSrootd_v = NULL;
char *CVSrootd_n = NULL;
char *CVSrootD_v = NULL;
char *CVSrootD_n = NULL;
char *rcvs_domain = NULL;
char *rcvs_cvsrec = NULL;
char *rcvs_username = NULL;
char *rcvs_tmpname = NULL;
char *rcvs_module = NULL;
char *rcvs_dopt_where = NULL;
int rcvs_level = 0;
int rcvs_gen_optind = 0;         

char *RCVSdir = NULL;
char *RCVShost = NULL;
char *RCVSroot = NULL;
char *RCVSuser = NULL;

struct CMD *rcvs_CM;
List *rcvs_chmodlist = (List *) NULL;
List *rcvs_rmlist = (List *) NULL;
List *rcvs_dirlist = (List *) NULL;
List *rcvs_filelist = (List *) NULL;
int rcvs_file_mode = FALSE;
int rcvs_cmd_optind;             
int rcvs_parse_opt = FALSE;
int rcvs_do_rdist = TRUE;
char *rcvs_msgfile = NULL;
FILE *msgfp = (FILE *) NULL;

#if __STDC__
char *rcvs_get_repos (char *dir, char **Id, char **Repository);
int rcvs_do_host (int argc, char *argv[], Node *p);
int rcvs_add_sync_arg (int margc, char *margv[], Node *p);
int rcvs_add_original_arg (int margc, char *margv[], Node *p);
#else
char *rcvs_get_repos ();
int rcvs_do_host ();
int rcvs_add_sync_arg ();
int rcvs_add_original_arg ();
#endif   		     /* __STDC__ */

struct cmd
{
    char *fullname;    
    char *nick1;       
    char *nick2;       
    int (*func) ();    
};

/* rcvs: this is core of RCVS. Process all folders if there is remote one */
int
rcvs_main (argc, argv, Cm)
    int argc;
    char *argv[];
    struct cmd *Cm;
{
    char tmp[PATH_MAX];
    int err = 0;
    cm = Cm;

    /* initialization */
    host = rcvs_gethostdomain ();
    (void) sprintf (tmp,"%s.%d",RCVSMSG, getpid ());
    rcvs_msgfile = xstrdup(tmp);
    {
        char *curDir;
	curDir = xmalloc (PATH_MAX);
	(void) getwd (curDir);
	CurDir = xstrdup (curDir);
	free (curDir);
    }	

    /* adjust argument pointer */
    argc += rcvs_gen_optind;
    argv -= rcvs_gen_optind;       /* e.g. ^cvs -t co -A me */  

    /* call rcvs_do_host */
    if (rcvs_dirlist)
        rcvs_walklist (argc, argv, "#4", rcvs_dirlist, rcvs_do_host);
    else
        error (1, 0, "rcvs_main: bug #1: no directory found");


    /* return to main() only if there is only local folder */
    exit (err);
}

/* rcvs: create an empty file then do chmod */
int
emptyfile (repository)
    char *repository;
{
    FILE *histfp;
    if (!repository)
        return(2);
    histfp = open_file (repository, "w");
    if (fclose (histfp))
    {
        error(0, 0,"emptyfile: cannot access %s", repository);
	return(1);
    }
    (void) rcvs_chmod ( repository, cvsroot_gid, cvsroot_mode);
    return(0);
}

/* rcvs: process folders that belong to a local or remote host. */
int
rcvs_do_host ( argc, argv, p )
    int argc;
    char *argv[];
    Node *p;
{
    int err = 0;
    local = 0;
    rcvsid = NULL;
    margc = 0;
    cvsroot_gid = NULL;
    cvsroot_mode = 0;

    if (rcvs_Popt_phases == NULL)
        rcvs_Popt_phases = rcvs_CM->phases;

    /* print name of folder */ 
    {
        List *L;
        char tmp[PATH_MAX];
        register int i;
        tmp[0] = '\0';
        L = (void *) p->data;
        margc = Margc = 0;
        rcvs_walklist (margc, margv, "#2", L, rcvs_add_sync_arg);
        for ( i = 0; i < Margc; i++) 
        {  
            (void) strcat ( tmp, margv[i]);
            (void) strcat ( tmp, " ");
        }   
	if (!quiet)
	{  
	    char title[PATH_MAX];
            if (index (p->key, ':') == NULL )
	    {  
                /*printf("<< LOCAL FOLDER >> %s\n", tmp);*/
                (void) sprintf(title, "LOCAL FOLDER: %s", tmp);
	    }	
            else
	    {  
                /*printf("\n<< REMOTE FOLDER >> %s\n", tmp);*/
                (void) sprintf(title, "REMOTE FOLDER: %s", tmp);
	    }	
	    fprintf (stderr, "%s\n", title);
	    (void) strncpy (tmp, bar, strlen(title)-1);
	    *(tmp+strlen(title)-1) = '\0';
	    fprintf (stderr, "%s\n", tmp);
	}    
    }

    /* parse RCVS ID */
    rcvsid = p->key;
    (void) rcvs_Parse_ID (p->key, &RCVSuser, &RCVShost,
			      &RCVSroot,&RCVSdir, &CVSroot);

    /* process this host in three phases */
    {
	if (index (p->key, ':') == NULL)
	    local = TRUE;

	err = 0;
	if (rcvs_msgfile != NULL && isfile(rcvs_msgfile))
	    if ( unlink_file (rcvs_msgfile) )
                error (1, 0, "cannot remove message file %s\n", rcvs_msgfile);
	if ( !local && index (rcvs_Popt_phases,'1') )
	    if ( !really_quiet || !noexec || trace)
  	        err = rcvs_do_host_phase1 ( argc, argv, p );

	if ( local || (! err && index (rcvs_Popt_phases,'2')) )
	    err = rcvs_do_host_phase2 (argc, argv, p);

	if ( !local && (! err && index (rcvs_Popt_phases,'3')) )
	    if ( !really_quiet || !noexec || trace)
	        err = rcvs_do_host_phase3 (argc, argv, p);

        /* append history + remove file + clear lock on server 
	 * if 1. remove list not empty 2. no error 3. phase-3 4. has history
	 */
	{
	    char tmp[PATH_MAX];
	    char line[PATH_MAX];
	    (void) sprintf( tmp,"%s/CVSROOT/%s",CVSroot, CVSROOTADM_HISTORY_NEW);

	    if (rcvs_rmlist != NULL || 
		(!local && (index (rcvs_Popt_phases,'3') || filesize(tmp)))) 
		(void) rcvs_hist_and_lock(err, CVSroot, RCVSuser, RCVShost,
				      RCVSroot, RCVSdir);
	    /* clean up temporary history and commit file */
	    if (isfile(tmp) && !local)
	        unlink (tmp);
	    (void) sprintf( tmp,"%s/CVSROOT/%s",CVSroot, CVSROOTADM_COMMITLOG_NEW);
	    if (isfile(tmp) && !local)
	        unlink (tmp);
	    (void) sprintf( tmp,"%s/CVSROOT/%s",CVSroot, CVSROOTADM_HISTORY);
	    if (isfile(tmp) && !local)
	        emptyfile (tmp);
	    (void) sprintf( tmp,"%s/CVSROOT/%s",CVSroot, CVSROOTADM_COMMITLOG);
	    if (isfile(tmp) && !local)
	        emptyfile (tmp);
	    if (rcvs_msgfile != NULL && isfile(rcvs_msgfile))
	        (void) unlink(rcvs_msgfile);
	}	
	rcvs_Clear_my_lock ();
	if (cvsroot_gid)
	    free (cvsroot_gid);
    }
    return (err);
}

/* do chmod on a file or directory */
int
rcvs_chmod (repository, gid, mode)
    char * repository;  
    char * gid;
    int mode;
{
    struct group *Gid;
    if (isfile(repository) && gid)
    {  
        struct stat sbuf;
	uid_t uid;
	if ( stat(repository, &sbuf) == 0)
	{  
	    uid = getuid();
	    Gid = getgrnam(gid);
	    if ( uid == sbuf.st_uid )
	    {  
	        /* chgrp only if has group write access */ 
	        if ( S_IWGRP&(mode))
		{	 
		    int err; 
		    err = ( Gid == NULL ||
			   chown (repository, -1, Gid->gr_gid));
		    if (trace && err)   
		        error(0,0, "cannot chgrp %s %s", gid, repository);
		}	  
		if ( chmod (repository, mode))
		    error(0,0, "cannot chmod %o %s", mode, repository);
	    }  
	}	 
    }	  
}

/* examine stdout for sync session */
int
rcvs_check_sync_stdout(line)
    char * line;
{
    char *cp = NULL;
    char tmp[PATH_MAX];
    char repository[PATH_MAX];
    int err = 0;

    {  
                                                          /* CVSROOT= */
        if ( (strncmp ( "CVSROOT=", line, 8) == 0) ||    
	    (strncmp ( "CVSroot=", line, 8) == 0) )       
        {
	    if (trace)
	        fprintf (stderr, "-> %s", line);
	    if (RCVSroot == NULL)
	    {
	        *(line + strlen(line) -1) = '\0';
	        cp = line + 8;
	        RCVSroot = xstrdup (cp);
	    }
	    /* CVSROOT= is a signal that CVS sync is ok !!
	     * CVSroot= is a signal that CVS lock on server is ok !!*/
	    if (strncmp ( "CVSROOT=", line, 8) == 0)
	        get_CVSROOT = TRUE;
	    else
	        lockSet_onServer = TRUE;
        }	  
                                                          /* REMOVE= */
        else if ( strncmp ( "REMOVE=", line, 7) == 0 )  
	{  
	    if (trace)
	        fprintf (stderr, "-> %s", line);
	    *(line + strlen(line) -1) = '\0';
	    cp = line + 7;
            sprintf (tmp, "%s/%s", CVSroot, cp);
	    if (trace && unlink_file (tmp))
	        fprintf (stderr, "-> cannot remove %s\n", cp);
	}

                                                          /* GROUP/MODE= */
        else if ( strncmp ( "GROUP/MODE=", line, 11) == 0 )  
	{  
	    char dir[PATH_MAX];
	    char gid[PATH_MAX];
	    int mode;
	    if (trace)
	        fprintf (stderr, "-> %s", line);
	    *(line + strlen(line) -1) = '\0';
	    cp = line + 11;
	    sscanf (cp, "%s %s %o", dir, gid, &mode); 
	    if (strcmp(dir,CVSROOTADM)== 0)
	    {  
	        cvsroot_mode=mode;
	        cvsroot_gid=xstrdup(gid);
	    }	
            sprintf (repository, "%s/%s", CVSroot, dir);
	    (void) rcvs_chmod (repository, gid, mode);
	}   

                                                           /* RCVSLOCK= */
	else if ( strncmp ( "RCVSLOCK=", line, 9) == 0 )
	{  
	    if (trace)
	        fprintf (stderr, "-> %s", line);
	    rcvs_lock_WFL_remote = TRUE;
	}    

        else if ( strncmp ( "RSH_STATUS=", line, 11) == 0) /* RSH_STATUS */
	{
	    int Err;
	    if (trace)
	        fprintf (stderr, "-> %s", line);
	    Err = atoi(line + 11);
	    if (Err) 
	    {  
	        fprintf (stderr, "rsh return err <> 0\n");
		phase1_err_reported = TRUE;
	        err = Err;
	    }	 
	}
	                                                /* RDIST_STATUS */ 
        else if ( strncmp ( "RDIST_STATUS=1", line, 14) == 0) 
	{
	    if (trace)
	        fprintf (stderr, "-> %s", line);
	    fprintf (stderr, "rdist returns err <> 0\n");
	    phase1_err_reported = TRUE;
	    err = 1;
	}
	                                                /* SERVER VERSION*/ 
        else if ( strncmp ( "SERVER_VERSION=", line, 15) == 0) 
	{
	    if (trace)
	        fprintf (stderr, "-> %s", line);
	    *(line + strlen(line) -1) = '\0';
	    cp = line + 15;
	    ver_rcvs_server = (int)cp;
	}

	else
	    fprintf(stderr, "%s",line);
    }   
    return (err);
}

/* rcvs: do forward sync for a remote folder. */
int
rcvs_do_host_phase1 ( argc, argv, p )
    int argc;
    char *argv[];
    Node *p;
{
    int err = 0;
    int err2 = 0;
    int err3 = 0;
    FILE *fp_err;
    char tmp[PATH_MAX];
    char line[PATH_MAX];
    List *L;
    register int i;
    get_CVSROOT = FALSE;

    /* create clone directory if not already exist */
    (void) rcvs_mkdir (RCVSdir);

    /* check lock */
    (void) rcvs_Check_lock ();
    lock_checked = TRUE;

    if (!quiet)
    {
        sprintf(line, "phase [1]. Sending rdist request to %s@%s", 
		RCVSuser, RCVShost);
        fprintf (stderr, "%s\n", line);
	if (trace)
	{  
	    (void) strncpy (tmp, bar, strlen(line));
	    *(tmp+strlen(line)) = '\0';
	    fprintf (stderr, "%s\n", tmp);
	}    
        fprintf(stderr, "%s\n", msg1);
    }

    /* generate command to do rsh */ 
/*+IS*/
    (void) sprintf (tmp,"%s %s -l %s ", rshcmd, RCVShost, RCVSuser );
/*-IS*/
    (void) strcat ( tmp, "cvs " );
    if (index(rcvs_Popt_phases,'3'))
        (void) strcat ( tmp, "-L " );

    if (noexec)
        (void) strcat ( tmp, "-n " );
    if (quiet)
        (void) strcat ( tmp, "-q " );
    if (really_quiet)
        (void) strcat ( tmp, "-Q " );
    if (trace)
       (void) sprintf (tmp+strlen(tmp), "-t ");
    if ( rcvs_Uopt_unlock) 
       (void) strcat ( tmp, "-U " );

    (void) sprintf (tmp+strlen(tmp),"-S -e %d -d %s@%s:%s:%s ", 
		    ver_rcvs, rcvs_username, host, RCVSdir, RCVSroot );

    if (rcvs_cvsrec != NULL)
        (void) sprintf (tmp+strlen(tmp),"-X %s ", rcvs_cvsrec );

    (void) sprintf (tmp+strlen(tmp),"%s ", rcvs_CM->sync_name );

    /* add relative repository stored in data field to margv */ 
    L = (void *) p->data;
    margc = Margc = 0;
    rcvs_walklist (margc, margv, "#1", L, rcvs_add_sync_arg);

    for ( i = 0; i < Margc; i++) 
        (void) sprintf (tmp+strlen(tmp), "%s ",margv[i]); 
    (void) strcat( tmp, "2>&1; echo RSH_STATUS=$?" );  
    /*-> put all cvs message into stdout */

    if (trace)
        (void) fprintf(stderr, "-> %s\n",tmp);

    /* open pipe to receive data back from rsh */
    fp = popen (tmp, "r");

    /* check stdout, output from cvs's stdout */
    if (trace)
        (void) fprintf(stderr, "-> rcvs_do_host_phase1: output from stdout ...\n");
    while (fgets (line, sizeof (line), fp))
    {
        if ( strncmp ( "|", line, 1) == 0)    /* rdist message */
	    fprintf(stderr, "%s",line);
	else
	{  
	    err = rcvs_check_sync_stdout (line);
	    if (err) 
	        break;
	    (void) rcvs_check_rsh_output (line); /* give user suggestion */
	}    
    }

    err3 =  pclose (fp);
    if (err3)
    {
        if (!phase1_err_reported)
	    fprintf (stderr, "rsh return err <> 0\n");
	phase1_err_reported = TRUE;
	err = 1;
    }

    if (!get_CVSROOT  && !phase1_err_reported)
    {  
        fprintf (stderr, "cvs on server return err <> 0\n");
	err = 1;
	phase1_err_reported = TRUE;
    }	

    if (err && !phase1_err_reported)
	fprintf (stderr, "phase 1 returns err <> 0\n");

    if (err && rcvs_CM->need_repos)
	error (1, 0, "fail to get modules");

    /* make sure history exist, it must exist to start history logging*/
    (void) sprintf( line,"%s/CVSROOT/%s",CVSroot,CVSROOTADM_HISTORY);
    if (!local && !isfile(line))
        (void) emptyfile (line);

    /* make sure commitlog exist */
    (void) sprintf(line,"%s/CVSROOT/%s",CVSroot,CVSROOTADM_COMMITLOG);
    if (!local && !isfile(line))
        (void) emptyfile (line);

    return (err);
}

/* rcvs: process folders locally. */
int
rcvs_do_host_phase2 ( argc, argv, p )
    int argc;
    char *argv[];
    Node *p;
{
    char tmp[PATH_MAX];
    char line[PATH_MAX];
    List *L;
    int err = 0;

    /* check lock */
    if (!lock_checked)
        (void) rcvs_Check_lock ();
    lock_checked = TRUE;

    if ( (chdir (CurDir) < 0))
        error (1, 0, "cannot chdir to %s", CurDir);

    /* run CVS command locally */
    if (!quiet)
    {
        sprintf(line, "phase [2]. Local %s on clone",cm->fullname);
        fprintf (stderr, "%s\n", line);
	if (trace)
	{  
	    (void) strncpy (tmp, bar, strlen(line));
	    *(tmp+strlen(line)) = '\0';
	    fprintf (stderr, "%s\n", tmp);
	}    
        fprintf(stderr,"%s\n", rcvs_CM->msg);
    }	

    /* construct the argument for local cvs !! */
    {
        int i = 0;
	int narg; 
	narg = rcvs_gen_optind + rcvs_cmd_optind -1;
	(void) sprintf (tmp, "CVSROOT=%s; export CVSROOT; ", CVSroot);

        for ( i = 0; i <= narg; i++) 
        {  
            if ( i == 1 )
	    {  
	        if (index (p->key, ':') == NULL )      /* local folder */
                    (void) sprintf (tmp+strlen(tmp), "-Y %s -d %s ", 
				    rcvs_msgfile, CVSroot_v);
		else
                    (void) sprintf (tmp+strlen(tmp), "-Y %s -d %s ",
				    rcvs_msgfile, rcvsid);
            }		

	    if ( index (argv[i], ' ') != NULL )
	        (void) sprintf (tmp+strlen(tmp), "\'%s\' ", argv[i]);
	    else
	    {
	        if (i < rcvs_gen_optind && strcmp (argv[i], "-d") == 0)
		    i++;
		else
		{  
		    (void) strcat ( tmp, argv[i]);
		    (void) strcat ( tmp, " ");
		}    
            }	  
        }   

        /* add relative repository of this folder to margv */ 
	L = (void *) p->data;
	margc = Margc = 0;
        rcvs_walklist (margc, margv, "#2", L, rcvs_add_original_arg);
        for ( i = 0; i < Margc; i++) 
        {  
            (void) strcat ( tmp, margv[i]);
	    (void) strcat ( tmp, " ");
        }   
    }

    /* run it in shell in order to catch error and/or set CVSROOT */
    if (trace)
        fprintf(stderr, "-> %s\n", tmp);
    err = system ( tmp );

    if (trace && err)
        fprintf(stderr, "-> err=%d setlock=%d\n", err, rcvs_lock_WFL_local);       
    /* copy history to history.tmp and commitlog to commitlog.tmp */
    (void) sprintf( tmp,"%s/CVSROOT/%s",CVSroot,CVSROOTADM_HISTORY);
    (void) sprintf( line,"%s/CVSROOT/%s",CVSroot,CVSROOTADM_HISTORY_NEW);
    if (!local && filesize(tmp))
    {  
        copy_file (tmp, line);
        (void) emptyfile (tmp);
    }	

    (void) sprintf( tmp,"%s/CVSROOT/%s",CVSroot,CVSROOTADM_COMMITLOG);
    (void) sprintf( line,"%s/CVSROOT/%s",CVSroot,CVSROOTADM_COMMITLOG_NEW);
    if (!local && filesize(tmp))
    {  
        copy_file (tmp, line);
        (void) emptyfile (tmp);
    }	

    /* cleanup lock if error */
    if ( err )
    {  
        int i;
        fprintf (stderr, "phase 2 returns err <> 0\n");
	if (index(rcvs_Popt_phases,'3'))
	{  
	    err = 0;   /* reset error to sync back */
	    fprintf (stderr, "sync clone back anyway for safety..\n");
	}
	if (rcvs_native)
	    rcvs_Clear_my_lock ();
        return (err);
    }

    return (0);
}

/* rcvs: do backward sync for remote folder that need to sync back. */
int
rcvs_do_host_phase3 ( argc, argv, p )
    int argc;
    char *argv[];
    Node *p;
{
    List *L;
    char *Argv[MAXARG];
    char tmp[PATH_MAX];
    char line[PATH_MAX];
    register int i;
    int Argc;
    int err = 0;

    /* check lock */
    if (!lock_checked)
        (void) rcvs_Check_lock ();
    lock_checked = TRUE;

    /* cleanup lock if commit, then sync modules back to server */
    {   
        /* rdist modules back to master repository,
 	 * simply call checkout once rcs_sync flag is set 
         */
        if (!quiet)
        {	 
            sprintf (line,
		"phase [3]. Rdist modules back to %s@%s", RCVSuser, RCVShost);
	    fprintf (stderr, "%s\n", line);
	    if (trace)
	    {  
	        (void) strncpy (tmp, bar, strlen(line));
		*(tmp+strlen(line)) = '\0';
		fprintf (stderr, "%s\n", tmp);
	    }    
            fprintf(stderr, "%s\n", msg2);
        }	   


        /* add relative repository stored in data field to margv */ 
        L = (void *) p->data;
        margc = Margc = 0;
        rcvs_walklist (margc, margv, "#3", L, rcvs_add_sync_arg);

        Argv[0] = "checkout";
        Argc=Margc + 1;
        for ( i = 1; i <= Margc; i++) 
            Argv[i] = margv[i-1];

        if (trace)
        {
            for ( i = 0; i < Argc; i++)
	        fprintf(stderr, "%s ", Argv[i]);
	    fprintf (stderr, "\n");
        }

        rcvs_sync = rcvs_sync_backward = TRUE;
	rcvs_native = FALSE;
        rcvs_chmodlist = rcvs_dirlist = rcvs_filelist = NULL;

	/* skip phase 3 if -n */
	if (noexec)
	    return;

	if (strcmp (cm->fullname, "import") == 0)
	{  
	    err = rcvs_Rdist_init ();
	    (void) addlist (&rcvs_dirlist, Argv[1]);
	    err = rcvs_Rdist();
	}
	else
            err = checkout (Argc, Argv);

        rcvs_sync = rcvs_sync_backward = FALSE;
	rcvs_native = TRUE;
    }   


    if (err)
    {  
	rcvs_lock_phase3 = TRUE;

	/* construct instruction for recovering */
	(void) sprintf (tmp, "cvs -U -P 3 ");
	for ( i = 1; i < argc; i++)
	{  
	    if (strcmp(argv[i],"-P") == 0)
	    {  
	        i++;  
		continue;
	    }	
	    if (strcmp(argv[i],"-U") == 0)
		continue;
            (void) strcat ( tmp, argv[i]);
            (void) strcat ( tmp, " ");
	}    
        fprintf (stderr, "phase 3 returns err <> 0\n");
        error (1, 0, "aborted, system remain locked.\nPlease do '%s' once the problem is solved ASAP !!!", tmp);
    }	

    /* this is not the end yet. rcvs_hist_and_lock (in rcvs_lock.c) will
       conduct the additional tasks:
       1. Append history file to main repository.
       2. Cleanup lock for commit.
       3. Remove files if rmlist is not empty.
       4. chmod for added directories.
     */  

    return (err);
}

/* determine CVSROOT */
int
rcvs_do_cvsroot (cvs_update_env)
    int cvs_update_env;  
{
    int remote_mode = FALSE;
    char *cvsroot;
    char *cp;
    if (rcvs_username == NULL)
	rcvs_username = xstrdup (getcaller());
    if (rcvs_cvsrec == NULL)                       /* get CVSREC */
    {
        if ((cp = getenv (CVSREC_ENV)) != NULL) 
	rcvs_cvsrec = cp;  
    }
    if (rcvs_sync)
        remote_mode = TRUE;
    else                                        /* check CVSMODE */
    {
        if ((cp = getenv (CVSMODE_ENV)) != NULL) 
	{
	    if ( strcmp (cp, "remote") == 0 || strcmp (cp, "REMOTE") == 0)
	        remote_mode = TRUE;
	    else if (!( strcmp (cp, "local") == 0 || strcmp (cp, "LOCAL") == 0))
	    error (1, 0, "set %s to 'local' or 'remote'", CVSMODE_ENV);
        }
    }	

    if (CVSrootd_v != NULL)                     /* -d */
    {       
        rcvs_ID = CVSrootd_v;
	rcvs_Id = CVSrootd_n;
	if (index (rcvs_ID, ':') == NULL)       /* local format */
	{
	    CVSroot = CVSrootd_v;
	    CVSroot_v = CVSrootd_v;
	    CVSroot_n = CVSrootd_n;
	}
	else                                    /* remote format */
	{  
	    if (rcvs_sync || rcvs_inshell)
	        (void) rcvs_Parse_ID (rcvs_ID, &RCVSuser, &RCVShost,
		      &RCVSroot,&RCVSdir, &CVSroot); 
	    else
	    {    
	        CVSrootr_v = rcvs_ID;
		CVSrootr_n = rcvs_Id;
	    }  
	}    
    }

    else                                         /* no -d */ 
    {
        if (!remote_mode && CVSroot_v != NULL)   /* CVSROOT */
	{       
            rcvs_ID = CVSroot_v;
	    rcvs_Id = CVSroot_n;
	    if (index (rcvs_ID, ':') != NULL && (rcvs_sync || rcvs_inshell))
	        (void) rcvs_Parse_ID (rcvs_ID, &RCVSuser, &RCVShost,
				      &RCVSroot,&RCVSdir, &CVSroot); 
	}

	if ( (remote_mode && CVSrootr_v != NULL) ||     /* CVSMODE=remote*/
	     (CVSroot_v == NULL && CVSrootr_v != NULL) )  /* CVSROOTr only*/
	{       
	    rcvs_ID = CVSrootr_v;
	    rcvs_Id = CVSrootr_n;
	    if (index (rcvs_ID, ':') != NULL)
	        (void) rcvs_Parse_ID (rcvs_ID, &RCVSuser, &RCVShost,
				      &RCVSroot,&RCVSdir, &cvsroot); 
	}

    }	

    if (rcvs_Ropt_remote)                    /* -R */
    {  
        if (CVSrootr_v == NULL || index (CVSrootr_v, ':') == NULL)
	    error (1, 0, "set %s to user@host:cvsroot:clone to use -R option", CVSROOTr_ENV);
	rcvs_ID = CVSrootr_v;
	rcvs_Id = CVSrootr_n;
    }

    if (rcvs_Copt_change_repos)             /* -C */
    {  
        if (CVSrootr_v == NULL || index (CVSrootr_v, ':') == NULL)
	    error (1, 0, "set %s to user@host:cvsroot:clone to use -C option", CVSROOTr_ENV);
	rcvs_ID = CVSrootr_v;
	rcvs_Id = CVSrootr_n;
    }

    if (rcvs_copt_change_repos)             /* -c */         
    {  
        if (CVSroot_v == NULL)
	{       
	    CVSroot_v = rcvs_ID;
	    CVSroot_n = rcvs_Id;
	}
	if (CVSroot_v != NULL)
	{  
	    if (index (CVSroot_v, ':') == NULL)
	    {       
	        rcvs_ID = CVSroot_v;
		rcvs_Id = CVSroot_n;
	    }  
	    else
	        error (1, 0, "set %s to local format to use -c option",
		       CVSROOT_ENV);
	}	
    }    

    /* add user's name to ID if it's missing */
    if (rcvs_ID != NULL && index (rcvs_ID, ':') != NULL)
    {
        cp = index (rcvs_ID, '@');
	if (cp == NULL || cp == rcvs_ID)
	{
	    char tmp[PATH_MAX];
	    if (cp == NULL)
	        sprintf (tmp, "%s@%s", rcvs_username, rcvs_ID);
	    else
	        sprintf (tmp, "%s%s", rcvs_username, rcvs_ID);
	    rcvs_ID = xstrdup (tmp);
	}    
    }

    if (rcvs_ID == NULL)         /* neither CVSROOT nor CVSROOTr was set */ 
        error (1, 0, "neither %s nor %s is set", CVSROOT_ENV, CVSROOTr_ENV);

    /* print a warm fuzzy message */
    if (!quiet && rcvs_ID != NULL && !rcvs_sync && !rcvs_inshell)
    {  
        if (remote_mode &&  index (rcvs_ID, ':') != NULL)
	{  
	    fprintf (stderr, "turn on remote mode\n");
            fprintf (stderr, "%s =  %s\n", rcvs_Id, rcvs_ID);
	}	
    }	
}

/* rcvs: add argument for sync to buffer */
int 
rcvs_add_sync_arg(margc, margv, p)
    int margc;
    char *margv[];
    Node *p;
{ 
    char *cp;
    cp = p->data;
    if (strcmp (cp, "") != 0)
        margv[Margc++] = cp;
    return 0;
}

/* rcvs: put original argument into buffer */
int 
rcvs_add_original_arg(margc, margv, p)
    int margc;
    char *margv[];
    Node *p;
{ 
    char *cp;
    cp = p->key;
    margv[Margc++] = cp;
    return (0);
}

/* create $RCVSDIR if not already exist */
int
rcvs_mkdir (rcvsdir)
    char *rcvsdir;
{
    char *cp = NULL;
    char tmp[PATH_MAX];
    char repository[PATH_MAX];
    cp = rcvsdir;
    if (!isdir (cp))
    {    
        if ( mkdir ( cp, 0777) )
	{  
	    program_name = xstrdup ("rcvs_mkdir");
	    error (1, 0 ,"cannot create %s", cp); 
	}  
	else
	{
	    chmod ( cp, 0775);
	    (void ) sprintf (tmp, "%s/%s", cp, RCVS_CLONE);
	    fp = open_file (tmp, "w");
	    fprintf (fp, "This is label for RCVS clone directory\n");
	    fprintf (fp, "Do not remove this file!\n");
	    if (fclose (fp) == EOF)
	        error (1, 0, "cannot close %s", tmp);
	}    
    }		
    else 
    {  
        if (!iswritable (cp))
	{  
	    program_name = xstrdup ("rcvs_mkdir");
	    error (1, 0, "Sorry, you don't have sufficient access to %s", cp);
        }
	(void ) sprintf (tmp, "%s/%s", cp, RCVS_CLONE);
	if (!isreadable (tmp)) 
	{  
	    fprintf(stderr,"Humm..directory %s is not labelled as clone,\n", cp);
	    fprintf(stderr,"if you're sure it can be used as clone, \n");
	    fprintf(stderr,"please type 'touch %s/%s' to create a label \n",
		    cp, RCVS_CLONE);
	    exit (1);
        }
    }

    /* create CVSROOT if not already exist */
    (void) strcpy(repository,rcvsdir);
    (void) strcat(repository,"/CVSROOT");
    cp = repository;
    if (!isdir (cp))
	if ( mkdir ( cp, 0777) ) 
	{  
	    program_name = xstrdup ("rcvs_mkdir");
	    error (1, 0 ,"cannot create %s", cp); 
	}  
	else
	    chmod ( cp, 0775);
    else if (!iswritable (cp))
    {  
        program_name = xstrdup ("rcvs_mkdir");
        error (1, 0 , "Sorry, you don't have sufficient access to %s", cp);
    }
    return (0);
}

/* this is a special lock, if phase 3 is executed without phase 1,
 * we need to set lock on server. This is done by executing  
 * 'cvs -S -L -P 9 co' on server
 */
int 
rcvs_set_phase3_lock( )
{
    int err = 0; 
    char line[PATH_MAX];
    char tmp[PATH_MAX];
    char *host = NULL;
    host = rcvs_gethostdomain ();
    /* generate command to do rsh */ 
/*+IS*/
    (void) sprintf (tmp,"%s %s -l %s ", rshcmd, RCVShost, RCVSuser );
/*-IS*/
    (void) strcat ( tmp, "cvs " );
    if (index(rcvs_Popt_phases,'3'))
        (void) strcat ( tmp, "-L -P 9 " );

    if (trace)
       (void) sprintf (tmp+strlen(tmp), "-t ");
    if ( rcvs_Uopt_unlock) 
       (void) strcat ( tmp, "-U " );

    (void) sprintf (tmp+strlen(tmp),
		    "-S -d %s@%s:%s:%s co 2>&1; echo RSH_STATUS=$?",
		    rcvs_username, host, RCVSdir, RCVSroot );
    if (trace)
        fprintf (stderr, "-> %s\n", tmp);

     /* open pipe to receive data back from rsh */
    fp = popen (tmp, "r");
    if (trace)
        (void) fprintf(stderr, "-> rcvs_set_phase3_lock: output from stdout ...\n");
    while (fgets (line, sizeof (line), fp))
    {
        err = rcvs_check_sync_stdout (line);
	if (err) 
	    error (1, 0, "abort rcvs_set_phase3_lock");
    }

    if (pclose (fp))
        error (1, 0, "rsh return err <> 0\n");

    if (!lockSet_onServer)
        error (1, 0, "fail to set lock\n");
}

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