Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 1 Feb 1996 18:50:37 +0100 (MET)
From:      haury@sagem.fr
To:        hackers@freebsd.org
Subject:   CTM: evolutions of ctm
Message-ID:   <199602011750.SAA05008@sagem.fr>

next in thread | raw e-mail | index | archive | help
I hope it's the right list for that and not <ctm@freebsd.org> :

Have been using CTM for a while and have changed it a little bit according to
Poul-Henning Kamp's future plans (Handbook 14.5.5 and sources comments).

These changes seem to work (I'have been testing them for 3 weeks now
with official ctm inputs on my -current tree) - I hope these patches could help
the community.

Evolutions :

2 new options

	-b <basedir>	path (relative or absolute) prepend on every files names
	-V <level>	verbose level added to current one ( -V 2 == -v -v  and
			-V 2 -v == -v -v -v )

*and*
	possibility of local modifications to the tree :

	before working on a file <name>, CTM first checks for the existence
	of the file <name>#ctm. If this file exists, CTM works on it instead.

	this substitution works for :

	    FM : CTM exits if <file>#ctm exists (and no -F)
	    FS : CTM substitutes the contents of file <file>#ctm
	FE, FN : CTM edits <file>#ctm
	    FR : CTM removes *only* <file>#ctm
	    AS : CTM changes permissions of <file>#ctm

	side effects :
	    DR : CTM *does not* check for the existance of <dir>#ctm and
			the contents of <dir> before removing it.

I didn't find a real good idea to manage dependencies between
<file> and <file>#ctm with make since it seems that make :

	- does not understand suffix rules like
		%\#ctm %:
			production

	- does not check any dependencies for Makefile itself before working.

So I have added several targets on the Top Makefile. The idea is :
        if <file> is created then <file>#ctm is created with null size
        if <file> is modified then <file>#ctm is created with the original
		content

	<file>#ctm *is* the reference
	<file> is produced by patching <file>#ctm with <file>.diff

I have put the patch of the top Makefile to show you what kind of rules I use.

The patch script  below works on the top of the source directory and modifies :

in . :
Makefile:	$Id: Makefile,v 1.74 1996/01/30 05:46:35 nate Exp $

in ./usr.sbin/ctm/ctm :
ctm.1:          $Id: ctm.1,v 1.3 1996/01/31 01:58:29 nate Exp $
ctm.c:          $Id: ctm.c,v 1.11 1995/05/30 03:47:19 rgrimes Exp $
ctm.h:          $Id: ctm.h,v 1.7 1995/05/30 03:47:21 rgrimes Exp $
ctm_input.c:    $Id: ctm_input.c,v 1.4 1994/09/22 02:49:18 phk Exp $
ctm_pass1.c:    $Id: ctm_pass1.c,v 1.11 1995/07/12 09:16:08 phk Exp $
ctm_pass2.c:    $Id: ctm_pass2.c,v 1.10 1995/11/10 12:17:23 phk Exp $
ctm_pass3.c:    $Id: ctm_pass3.c,v 1.11 1995/07/12 09:16:13 phk Exp $
ctm_syntax.c:   $Id: ctm_syntax.c,v 1.5 1995/05/30 03:47:28 rgrimes Exp $

==== CUT HERE (and don't forget to remove my signature) ====
*** ./Makefile#ctm	Wed Jan 31 20:34:35 1996
--- ./Makefile	Thu Feb  1 12:08:43 1996
***************
*** 355,358 ****
--- 355,414 ----
  	cd ${.CURDIR}/usr.sbin/zic && \
  		${MAKE} depend all install ${CLEANDIR} ${OBJDIR}
  
+ # CTM Hack
+ 
+ _CTM_SRC_CUR=	${.CURDIR}/../CTM/deltas
+ _CTM_STATUS=	.ctm_status
+ _CTM_LIST=	.ctm_list
+ 
+ ctm: $(_CTM_LIST) ctm-diff
+ 	@echo "Starting CTM"
+ 	@perl -e 'while(<>){chop;$$l=$$1+1 if(/^src-cur\s+(\d+)$$/); \
+ 	  while(1){$$f="$(_CTM_SRC_CUR)/src-cur.$$l.gz"; \
+ 	  last unless -f $$f; print "$$f\n"; $$l++}}' \
+ 	  $(_CTM_STATUS) | while read file; do \
+ 		echo ctm -V 2 $${file}; \
+ 		ctm -V 2 $${file}; \
+ 	done
+ 	@echo "DONE"
+ 	@echo "Starting file checking"
+ 	@perl -e 'while(<>){chop;foreach $$s ("",".diff","#ctm"){ \
+ 	  $$f="$$_$$s";print "Warning : $$f not found\n" unless -f $$f;}}' \
+ 	  $(_CTM_LIST)
+ 	@echo "DONE"
+ 
+ ctm-list:
+ 	find . -name '*#ctm' -print | sed 's/#ctm$$//' > $(_CTM_LIST)
+ 	@cat $(_CTM_LIST)
+ 
+ ctm-diff:
+ 	@echo "Starting DIFF"
+ 	@perl -e 'while(<>){chop;print"$$_\n" \
+ 	  if(!-f$$_.".diff"||-C$$_.".diff">-C$$_);}' \
+ 	  $(_CTM_LIST) | while read file; do \
+ 		echo diff -c $${file}\#ctm $${file} \> $${file}.diff; \
+ 		diff -c $${file}\#ctm $${file} > $${file}.diff \
+ 		&& ( echo "NO DIFFERENCE !!!!!"; rm -f $${file}.diff; exit 1 ) \
+ 		|| case $$? in 1);; *) exit $$?;; esac; \
+ 	done;
+ 	@echo "DONE"
+ 
+ ctm-patch:
+ 	@echo "Starting PATCH"
+ 	@perl -e 'while(<>){chop;print"$$_\n"if(!-f$$_||-C$$_>-C$$_."#ctm");}' \
+ 	  $(_CTM_LIST) | while read file; do \
+ 	    if [ -f $${file}.diff ]; then \
+ 		dest=`basename $${file}`; \
+ 		echo "Patching $${file} from $${file}#ctm"; \
+ 		cp $${file}\#ctm /tmp/$${dest}; \
+ 		patch /tmp/$${dest} $${file}.diff || exit 1; \
+ 		mv /tmp/$${dest} $${file}; \
+ 		rm -f /tmp/$${dest}.orig; \
+ 	    else \
+ 		echo "No diffs to create $${file} from $${file}#ctm"; \
+ 		exit 1; \
+ 	    fi; \
+ 	done;
+ 	@echo "DONE"
+ 		
  .include <bsd.subdir.mk>
*** ctm.1#ctm	Thu Feb  1 16:54:55 1996
--- ctm.1	Thu Feb  1 17:49:14 1996
***************
*** 21,27 ****
--- 21,29 ----
  .Sh SYNOPSIS
  .Nm ctm
  .Op Fl cFpPqv
+ .Op Fl b Ar basedir
  .Op Fl T Ar tmpdir
+ .Op Fl V Ar level
  .Ar file Op ...
  .Sh DESCRIPTION
  .Nm Ctm
***************
*** 53,58 ****
--- 55,69 ----
  command runs in a number of passes.  It will process the entire
  input file in each pass, before commencing with the next pass.
  
+ Before working one a file
+ .Ar name
+ .Nm ctm
+ first checks for the existence of the file
+ .Ar name#ctm .
+ If this file exists,
+ .Nm ctm
+ works on it instead.
+ 
  Pass 1 will validate that the input file is OK.  The syntax, the data
  and the global MD5 checksum will be checked.  If any of these fail,
  .Nm ctm
***************
*** 77,82 ****
--- 88,98 ----
  
  .Bl -tag -width indent -compact
  
+ .It Fl b Ar basedir
+ Prepend the path
+ .Ar basedir
+ on every filename.
+ 
  .It Fl c
  Check it out, don't do anything.
  
***************
*** 98,103 ****
--- 114,124 ----
  
  .It Fl v
  Tell us more.
+ 
+ .It Fl V Ar level
+ Tell us more.
+ .Ar Level
+ is the level of verbosity.
  
  .El
  
*** ./usr.sbin/ctm/ctm/ctm.c#ctm	Thu Feb  1 11:10:16 1996
--- ./usr.sbin/ctm/ctm/ctm.c	Thu Feb  1 10:20:09 1996
***************
*** 14,20 ****
   * Options we'd like to see:
   *
   * -a 			Attempt best effort.
-  * -b <dir>		Base-dir
   * -B <file>		Backup to tar-file.
   * -d <int>		Debug TBD.
   * -m <mail-addr>	Email me instead.
--- 14,19 ----
***************
*** 22,27 ****
--- 21,27 ----
   * -R <file>		Read list of files to reconstruct.
   *
   * Options we have:
+  * -b <dir>		Base-dir
   * -c			Check it out, don't do anything.
   * -F      		Force
   * -p			Less paranoid.
***************
*** 29,34 ****
--- 29,35 ----
   * -q 			Tell us less.
   * -T <tmpdir>.		Temporary files.
   * -v 			Tell us more.
+  * -V <level>		Tell us more level = number of -v
   *
   */
  
***************
*** 46,61 ****
      int c;
      extern int optopt,optind;
      extern char * optarg;
-     FILE *statfile;
      unsigned applied = 0;
  
      Verbose = 1;
      Paranoid = 1;
      setbuf(stderr,0);
      setbuf(stdout,0);
  
!     while((c=getopt(argc,argv,"ab:B:cd:Fm:pPqr:R:T:Vv")) != -1) {
  	switch (c) {
  	    case 'c': CheckIt++;	break; /* Only check it */
  	    case 'p': Paranoid--;	break; /* Less Paranoid */
  	    case 'P': Paranoid++;	break; /* More Paranoid */
--- 47,65 ----
      int c;
      extern int optopt,optind;
      extern char * optarg;
      unsigned applied = 0;
+     FILE *statfile;
+     u_char * basedir;
  
+     basedir = NULL;
      Verbose = 1;
      Paranoid = 1;
      setbuf(stderr,0);
      setbuf(stdout,0);
  
!     while((c=getopt(argc,argv,"ab:B:cd:Fm:pPqr:R:T:V:v")) != -1) {
  	switch (c) {
+ 	    case 'b': basedir = optarg;	break; /* Base Directory */
  	    case 'c': CheckIt++;	break; /* Only check it */
  	    case 'p': Paranoid--;	break; /* Less Paranoid */
  	    case 'P': Paranoid++;	break; /* More Paranoid */
***************
*** 63,68 ****
--- 67,75 ----
  	    case 'v': Verbose++;	break; /* Verbose */
  	    case 'T': TmpDir = optarg;	break;
  	    case 'F': Force = 1;	break;
+ 	    case 'V': sscanf(optarg,"%d", &c); /* Verbose */
+ 		      Verbose += c;
+ 		      break;
  	    case ':':
  		fprintf(stderr,"Option '%c' requires an argument.\n",optopt);
  		stat++;
***************
*** 85,92 ****
      argc -= optind;
      argv += optind;
  
!     if((statfile = fopen(CTM_STATUS, "r")) == NULL)
! 	fprintf(stderr, "Warning: " CTM_STATUS " not found.\n");
      else {
  	fscanf(statfile, "%*s %u", &applied);
  	fclose(statfile);
--- 92,114 ----
      argc -= optind;
      argv += optind;
  
!     if (basedir == NULL) {
! 	Buffer = (u_char *)malloc(BUFSIZ + strlen(SUBSUFF) +1);
! 	CatPtr = Buffer;
! 	*Buffer  = '\0';
!     } else {
! 	Buffer = (u_char *)malloc(strlen(basedir)+ BUFSIZ + strlen(SUBSUFF) +1);
! 	strcpy(Buffer, basedir);
! 	CatPtr = Buffer + strlen(basedir);
! 	if (CatPtr[-1] != '/') {
! 		strcat(Buffer, "/");
! 		CatPtr++;
! 	}
!     }
!     strcat(Buffer, CTM_STATUS);
! 
!     if((statfile = fopen(Buffer, "r")) == NULL)
! 	fprintf(stderr, "Warning: %s not found.\n", Buffer);
      else {
  	fscanf(statfile, "%*s %u", &applied);
  	fclose(statfile);
*** ./usr.sbin/ctm/ctm/ctm.h#ctm	Tue Jan 30 11:44:21 1996
--- ./usr.sbin/ctm/ctm/ctm.h	Wed Jan 31 16:40:52 1996
***************
*** 24,29 ****
--- 24,32 ----
  #define VERSION "2.0"
  #define MAXSIZE (1024*1024*10)
  
+ #define SUBSUFF "#ctm"
+ #define TMPSUFF ".ctm"
+ 
  /* The fields... */
  #define CTM_F_MASK		0xff
  #define CTM_F_Name		0x01
***************
*** 39,44 ****
--- 42,48 ----
  #define CTM_Q_Name_File		0x0100
  #define CTM_Q_Name_Dir		0x0200
  #define CTM_Q_Name_New		0x0400
+ #define CTM_Q_Name_Subst	0x0800
  #define CTM_Q_MD5_After		0x0100
  #define CTM_Q_MD5_Before	0x0200
  #define CTM_Q_MD5_Chunk		0x0400
***************
*** 63,70 ****
  EXTERN u_char *TimeStamp;
  EXTERN u_char *Prefix;
  EXTERN u_char *FileName;
- EXTERN u_char *BaseDir;
  EXTERN u_char *TmpDir;
  
  /*
   * Paranoid -- Just in case they should be after us...
--- 67,75 ----
  EXTERN u_char *TimeStamp;
  EXTERN u_char *Prefix;
  EXTERN u_char *FileName;
  EXTERN u_char *TmpDir;
+ EXTERN u_char *CatPtr;
+ EXTERN u_char *Buffer;
  
  /*
   * Paranoid -- Just in case they should be after us...
***************
*** 115,120 ****
--- 120,126 ----
  #define WRONG {Assert(); return Exit_Mess;}
  
  u_char * Ffield(FILE *fd, MD5_CTX *ctx,u_char term);
+ u_char * Fname(FILE *fd, MD5_CTX *ctx,u_char term,int qual, int verbose);
  
  int Fbytecnt(FILE *fd, MD5_CTX *ctx, u_char term);
  
***************
*** 124,129 ****
--- 130,136 ----
  #define GETFIELDCOPY(p,q) if(!((p)=Ffield(fd,&ctx,(q)))) return BADREAD; else p=String(p)
  #define GETBYTECNT(p,q) if(0 >((p)= Fbytecnt(fd,&ctx,(q)))) return BADREAD
  #define GETDATA(p,q) if(!((p) = Fdata(fd,(q),&ctx))) return BADREAD
+ #define GETNAMECOPY(p,q,r,v) if(!((p)=Fname(fd,&ctx,(q),(r),(v)))) return BADREAD; else p=String(p)
  
  int Pass1(FILE *fd, unsigned applied);
  int Pass2(FILE *fd);
*** ./usr.sbin/ctm/ctm/ctm_input.c#ctm	Thu Feb  1 10:52:53 1996
--- ./usr.sbin/ctm/ctm/ctm_input.c	Thu Feb  1 11:55:34 1996
***************
*** 111,113 ****
--- 111,146 ----
      p[u_chars] = '\0';
      return p;
  }
+ 
+ /*---------------------------------------------------------------------------*/
+ /* get the filename in the next field, prepend BaseDir and give back the result
+    strings. The sustitute filename is return (the one with the suffix SUBSUFF) 
+    if it exists and the qualifier contains CTM_Q_Name_Subst
+    NOTA: Buffer is already initialize with BaseDir, CatPtr is the insertion
+    point on this buffer + the length test in Ffield() is enough for Fname() */
+ 
+ u_char *
+ Fname(FILE *fd, MD5_CTX *ctx,u_char term,int qual, int verbose)
+ {
+     u_char * p;
+     struct stat st;
+ 
+     if ((p = Ffield(fd,ctx,term)) == NULL) return(NULL);
+ 
+     strcpy(CatPtr, p);
+ 
+     if (!(qual & CTM_Q_Name_Subst)) return(Buffer);
+ 
+     p = Buffer + strlen(Buffer);
+ 
+     strcat(Buffer, SUBSUFF);
+ 
+     if ( -1 == stat(Buffer, &st) ) {
+ 	*p = '\0';
+     } else {
+ 	if(verbose > 2)
+ 	    fprintf(stderr,"Using %s as substitute file\n", Buffer);
+     }
+ 
+     return (Buffer);
+ }
*** ./usr.sbin/ctm/ctm/ctm_pass1.c#ctm	Tue Jan 30 11:44:21 1996
--- ./usr.sbin/ctm/ctm/ctm_pass1.c	Thu Feb  1 09:46:04 1996
***************
*** 184,189 ****
--- 184,193 ----
  	    putc('\n',stderr);
  	continue;
      }
+ 
+     if(md5)	Free(md5);
+     if(trash)	Free(trash);
+ 
      q = MD5End (&ctx,md5_1);
      if(Verbose > 2)
  	printf("Expecting Global MD5 <%s>\n",q);
*** ./usr.sbin/ctm/ctm/ctm_pass2.c#ctm	Tue Jan 30 11:44:21 1996
--- ./usr.sbin/ctm/ctm/ctm_pass2.c	Thu Feb  1 09:46:05 1996
***************
*** 69,75 ****
  
  	    switch (j & CTM_F_MASK) {
  		case CTM_F_Name:
! 		    GETFIELDCOPY(name,sep);
  		    /* XXX Check DR DM rec's for parent-dir */
  		    if(j & CTM_Q_Name_New) {
  			/* XXX Check DR FR rec's for item */
--- 69,75 ----
  
  	    switch (j & CTM_F_MASK) {
  		case CTM_F_Name:
! 		    GETNAMECOPY(name,sep,j,0);
  		    /* XXX Check DR DM rec's for parent-dir */
  		    if(j & CTM_Q_Name_New) {
  			/* XXX Check DR FR rec's for item */
***************
*** 171,176 ****
--- 171,181 ----
  	    }
          }
      }
+ 
+     if(trash)	Free(trash);
+     if(name)	Free(name);
+     if(md5)	Free(md5);
+ 
      q = MD5End (&ctx,md5_1);
      GETFIELD(p,'\n');			/* <MD5> */
      if(strcmp(q,p)) WRONG
*** ./usr.sbin/ctm/ctm/ctm_pass3.c#ctm	Tue Jan 30 11:44:21 1996
--- ./usr.sbin/ctm/ctm/ctm_pass3.c	Thu Feb  1 09:46:06 1996
***************
*** 69,75 ****
  		sep = '\n';
  
  	    switch (j & CTM_F_MASK) {
! 		case CTM_F_Name: GETFIELDCOPY(name,sep); break;
  		case CTM_F_Uid:  GETFIELDCOPY(uid,sep); break;
  		case CTM_F_Gid:  GETFIELDCOPY(gid,sep); break;
  		case CTM_F_Mode: GETFIELDCOPY(mode,sep); break;
--- 69,75 ----
  		sep = '\n';
  
  	    switch (j & CTM_F_MASK) {
! 		case CTM_F_Name: GETNAMECOPY(name,sep,j, Verbose); break;
  		case CTM_F_Uid:  GETFIELDCOPY(uid,sep); break;
  		case CTM_F_Gid:  GETFIELDCOPY(gid,sep); break;
  		case CTM_F_Mode: GETFIELDCOPY(mode,sep); break;
***************
*** 132,138 ****
  	}
  	if(!strcmp(sp->Key,"FN")) {
  	    strcpy(buf,name);
! 	    strcat(buf,".ctm");
  	    i = ctm_edit(trash,cnt,name,buf);
  	    if(i) {
  		fprintf(stderr," %s %s Edit failed with code %d.\n",
--- 132,138 ----
  	}
  	if(!strcmp(sp->Key,"FN")) {
  	    strcpy(buf,name);
! 	    strcat(buf,TMPSUFF);
  	    i = ctm_edit(trash,cnt,name,buf);
  	    if(i) {
  		fprintf(stderr," %s %s Edit failed with code %d.\n",
***************
*** 177,182 ****
--- 177,191 ----
  	}
  	WRONG
      }
+ 
+     if(md5)		Free(md5);
+     if(uid)		Free(uid);
+     if(gid)		Free(gid);
+     if(mode)		Free(mode);
+     if(md5before)	Free(md5before);
+     if(trash)		Free(trash);
+     if(name)		Free(name);
+ 
      q = MD5End (&ctx,md5_1);
      GETFIELD(p,'\n');
      if(strcmp(q,p)) WRONG
*** ./usr.sbin/ctm/ctm/ctm_syntax.c#ctm	Tue Jan 30 11:44:21 1996
--- ./usr.sbin/ctm/ctm/ctm_syntax.c	Thu Feb  1 09:46:07 1996
***************
*** 25,52 ****
  #define File	CTM_Q_Name_File
  #define Dir	CTM_Q_Name_Dir
  #define New	CTM_Q_Name_New
  #define After	CTM_Q_MD5_After
  #define Before	CTM_Q_MD5_Before
  #define Chunk	CTM_Q_MD5_Chunk
  #define Force	CTM_Q_MD5_Force
  
  static int ctmFM[] = /* File Make */
!     { Name|File|New, Uid, Gid, Mode,
  	MD5|After|Chunk, Count, Bytes,0 };
  
  static int ctmFS[] = /* File Substitute */
!     { Name|File, Uid, Gid, Mode,
  	MD5|Before|Force, MD5|After|Chunk, Count, Bytes,0 };
  
  static int ctmFE[] = /* File Edit */
!     { Name|File, Uid, Gid, Mode,
  	MD5|Before, MD5|After, Count, Bytes,0 };
  
  static int ctmFR[] = /* File Remove */
!     { Name|File, MD5|Before, 0 };
  
  static int ctmAS[] = /* Attribute Substitute */
!     { Name, Uid, Gid, Mode, 0 };
  
  static int ctmDM[] = /* Directory Make */
      { Name|Dir|New , Uid, Gid, Mode, 0 };
--- 25,53 ----
  #define File	CTM_Q_Name_File
  #define Dir	CTM_Q_Name_Dir
  #define New	CTM_Q_Name_New
+ #define Subst	CTM_Q_Name_Subst
  #define After	CTM_Q_MD5_After
  #define Before	CTM_Q_MD5_Before
  #define Chunk	CTM_Q_MD5_Chunk
  #define Force	CTM_Q_MD5_Force
  
  static int ctmFM[] = /* File Make */
!     { Name|File|New|Subst, Uid, Gid, Mode,
  	MD5|After|Chunk, Count, Bytes,0 };
  
  static int ctmFS[] = /* File Substitute */
!     { Name|File|Subst, Uid, Gid, Mode,
  	MD5|Before|Force, MD5|After|Chunk, Count, Bytes,0 };
  
  static int ctmFE[] = /* File Edit */
!     { Name|File|Subst, Uid, Gid, Mode,
  	MD5|Before, MD5|After, Count, Bytes,0 };
  
  static int ctmFR[] = /* File Remove */
!     { Name|File|Subst, MD5|Before, 0 };
  
  static int ctmAS[] = /* Attribute Substitute */
!     { Name|Subst, Uid, Gid, Mode, 0 };
  
  static int ctmDM[] = /* Directory Make */
      { Name|Dir|New , Uid, Gid, Mode, 0 };
-- 
		=Christian Haury (Christian.Haury@sagem.fr)

	 ---------------------------------------------------------
	|   SAGEM Eragny - Avenue du Gros Chene - Eragny BP 51    |
	|             95612 Cergy Pontoise Cedex - France         |
	| phone   : +33 (1) 34 30 53 93 | telex   : 607387F       |
	| fax     : +33 (1) 34 30 50 28 | teletex : 933-130731770 |
	 ---------------------------------------------------------



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi? <199602011750.SAA05008>