mkctm.c revision 124993
169793Sobrien/* $FreeBSD: head/usr.sbin/ctm/mkCTM/mkctm.c 124993 2004-01-26 04:08:43Z mckay $ */ 269793Sobrien 315702Sphk/* Still missing: 415702Sphk * 515702Sphk * mkctm 615702Sphk * -B regex Bogus 715702Sphk * -I regex Ignore 815773Sphk * -D int Damage 915773Sphk * -q decrease verbosity 1015702Sphk * -v increase verbosity 1119813Sphk * -l file logfile 1215702Sphk * name cvs-cur 1315702Sphk * prefix src/secure 1415702Sphk * dir1 "Soll" 1515702Sphk * dir2 "Ist" 1615702Sphk * 17118583Simp * $FreeBSD: head/usr.sbin/ctm/mkCTM/mkctm.c 124993 2004-01-26 04:08:43Z mckay $ 1815702Sphk */ 1915702Sphk 2015702Sphk#include <sys/types.h> 2115702Sphk#include <sys/stat.h> 2215702Sphk#include <sys/mman.h> 2315702Sphk#include <sys/wait.h> 2415702Sphk#include <dirent.h> 2515702Sphk#include <regex.h> 2615702Sphk#include <stdio.h> 2715702Sphk#include <fcntl.h> 2815702Sphk#include <string.h> 2915702Sphk#include <stdlib.h> 3015702Sphk#include <unistd.h> 3115702Sphk#include <md5.h> 3215702Sphk#include <err.h> 3369793Sobrien#include <paths.h> 3415702Sphk#include <signal.h> 3515702Sphk 3615773Sphk#define DEFAULT_IGNORE "/CVS$|/\\.#|00_TRANS\\.TBL$" 3719813Sphk#define DEFAULT_BOGUS "\\.core$|\\.orig$|\\.rej$|\\.o$" 3815702Sphkregex_t reg_ignore, reg_bogus; 3915702Sphkint flag_ignore, flag_bogus; 4015702Sphk 4115773Sphkint verbose; 4215773Sphkint damage, damage_limit; 4315773Sphkint change; 4415773Sphk 4519813SphkFILE *logf; 4619813Sphk 4715702Sphku_long s1_ignored, s2_ignored; 4815702Sphku_long s1_bogus, s2_bogus; 4915702Sphku_long s1_wrong, s2_wrong; 5015773Sphku_long s_new_dirs, s_new_files, s_new_bytes; 5115773Sphku_long s_del_dirs, s_del_files, s_del_bytes; 5215773Sphku_long s_files_chg, s_bytes_add, s_bytes_del; 5315702Sphku_long s_same_dirs, s_same_files, s_same_bytes; 5415702Sphku_long s_edit_files, s_edit_bytes, s_edit_saves; 5515702Sphku_long s_sub_files, s_sub_bytes; 5615702Sphk 5715702Sphkvoid 5815773SphkUsage(void) 5915773Sphk{ 6029526Scharnier fprintf(stderr, 6129526Scharnier "usage: mkctm [-options] name number timestamp prefix dir1 dir2\n"); 6229526Scharnier fprintf(stderr, "options:\n"); 6315773Sphk fprintf(stderr, "\t\t-B bogus_regexp\n"); 6415773Sphk fprintf(stderr, "\t\t-D damage_limit\n"); 6515773Sphk fprintf(stderr, "\t\t-I ignore_regexp\n"); 6615773Sphk fprintf(stderr, "\t\t-q\n"); 6715773Sphk fprintf(stderr, "\t\t-v\n"); 6815773Sphk} 6915773Sphk 7015773Sphkvoid 7115702Sphkprint_stat(FILE *fd, char *pre) 7215702Sphk{ 7319813Sphk fprintf(fd, "%sNames:\n", pre); 7419813Sphk fprintf(fd, "%s ignore: %5lu ref %5lu target\n", 7515702Sphk pre, s1_ignored, s2_ignored); 7619813Sphk fprintf(fd, "%s bogus: %5lu ref %5lu target\n", 7715702Sphk pre, s1_bogus, s2_bogus); 7819813Sphk fprintf(fd, "%s wrong: %5lu ref %5lu target\n", 7915702Sphk pre, s1_wrong, s2_wrong); 8019813Sphk fprintf(fd, "%sDelta:\n", pre); 8119813Sphk fprintf(fd, "%s new: %5lu dirs %5lu files %9lu plus\n", 8215702Sphk pre, s_new_dirs, s_new_files, s_new_bytes); 8319813Sphk fprintf(fd, "%s del: %5lu dirs %5lu files %9lu minus\n", 8415702Sphk pre, s_del_dirs, s_del_files, s_del_bytes); 8519813Sphk fprintf(fd, "%s chg: %5lu files %9lu plus %9lu minus\n", 8615702Sphk pre, s_files_chg, s_bytes_add, s_bytes_del); 8719813Sphk fprintf(fd, "%s same: %5lu dirs %5lu files %9lu bytes\n", 8815702Sphk pre, s_same_dirs, s_same_files, s_same_bytes); 8919813Sphk fprintf(fd, "%sMethod:\n", pre); 9019813Sphk fprintf(fd, "%s edit: %5lu files %9lu bytes %9lu saved\n", 9115702Sphk pre, s_edit_files, s_edit_bytes, s_edit_saves); 9219813Sphk fprintf(fd, "%s sub: %5lu files %9lu bytes\n", 9315702Sphk pre, s_sub_files, s_sub_bytes); 9419813Sphk 9515702Sphk} 9615702Sphk 9715702Sphkvoid 9815702Sphkstat_info(int foo) 9915702Sphk{ 10019813Sphk signal(SIGINFO, stat_info); 10119813Sphk print_stat(stderr, "INFO: "); 10215702Sphk} 10315702Sphk 10415702Sphkvoid DoDir(const char *dir1, const char *dir2, const char *name); 10515702Sphk 10615702Sphkstatic struct stat st; 10715702Sphkstatic __inline struct stat * 10815702SphkStatFile(char *name) 10915702Sphk{ 11019813Sphk if (lstat(name, &st) < 0) 11129526Scharnier err(1, "couldn't stat %s", name); 11215702Sphk return &st; 11315702Sphk} 11415702Sphk 11515702Sphkint 11615702Sphkdirselect(struct dirent *de) 11715702Sphk{ 11819813Sphk if (!strcmp(de->d_name, ".")) return 0; 11919813Sphk if (!strcmp(de->d_name, "..")) return 0; 12015702Sphk return 1; 12115702Sphk} 12215702Sphk 12315702Sphkvoid 12415702Sphkname_stat(const char *pfx, const char *dir, const char *name, struct dirent *de) 12515702Sphk{ 12615702Sphk char *buf = alloca(strlen(dir) + strlen(name) + 12715702Sphk strlen(de->d_name) + 3); 12815702Sphk struct stat *st; 12915702Sphk 13019813Sphk strcpy(buf, dir); 13119813Sphk strcat(buf, "/"); strcat(buf, name); 13219813Sphk strcat(buf, "/"); strcat(buf, de->d_name); 13315702Sphk st = StatFile(buf); 13419813Sphk printf("%s %s%s %u %u %o", 13515702Sphk pfx, name, de->d_name, 13615702Sphk st->st_uid, st->st_gid, st->st_mode & ~S_IFMT); 13719813Sphk fprintf(logf, "%s %s%s\n", pfx, name, de->d_name); 13815773Sphk if (verbose > 1) { 13919813Sphk fprintf(stderr, "%s %s%s\n", pfx, name, de->d_name); 14015773Sphk } 14115702Sphk} 14215702Sphk 14315702Sphkvoid 14415702SphkEqu(const char *dir1, const char *dir2, const char *name, struct dirent *de) 14515702Sphk{ 14615702Sphk if (de->d_type == DT_DIR) { 14715702Sphk char *p = alloca(strlen(name)+strlen(de->d_name)+2); 14815702Sphk 14919813Sphk strcpy(p, name); strcat(p, de->d_name); strcat(p, "/"); 15019813Sphk DoDir(dir1, dir2, p); 15115702Sphk s_same_dirs++; 15215702Sphk } else { 15315702Sphk char *buf1 = alloca(strlen(dir1) + strlen(name) + 15415702Sphk strlen(de->d_name) + 3); 15515702Sphk char *buf2 = alloca(strlen(dir2) + strlen(name) + 15615702Sphk strlen(de->d_name) + 3); 15719813Sphk char *m1, md5_1[33], *m2, md5_2[33]; 15819813Sphk u_char *p1, *p2; 15919813Sphk int fd1, fd2; 16019813Sphk struct stat s1, s2; 16115702Sphk 16219813Sphk strcpy(buf1, dir1); 16319813Sphk strcat(buf1, "/"); strcat(buf1, name); 16419813Sphk strcat(buf1, "/"); strcat(buf1, de->d_name); 16519813Sphk fd1 = open(buf1, O_RDONLY); 16629526Scharnier if(fd1 < 0) { err(3, "%s", buf1); } 16719813Sphk fstat(fd1, &s1); 16819813Sphk strcpy(buf2, dir2); 16919813Sphk strcat(buf2, "/"); strcat(buf2, name); 17019813Sphk strcat(buf2, "/"); strcat(buf2, de->d_name); 17119813Sphk fd2 = open(buf2, O_RDONLY); 17229526Scharnier if(fd2 < 0) { err(3, "%s", buf2); } 17319813Sphk fstat(fd2, &s2); 17415773Sphk#if 0 17515773Sphk /* XXX if we could just trust the size to change... */ 17615702Sphk if (s1.st_size == s2.st_size) { 17715702Sphk s_same_files++; 17815702Sphk s_same_bytes += s1.st_size; 17915702Sphk close(fd1); 18015702Sphk close(fd2); 18115702Sphk goto finish; 18215702Sphk } 18315702Sphk#endif 18419813Sphk p1=mmap(0, s1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0); 18529526Scharnier if (p1 == (u_char *)MAP_FAILED) { err(3, "%s", buf1); } 18615702Sphk close(fd1); 18715702Sphk 18819813Sphk p2=mmap(0, s2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0); 18929526Scharnier if (p2 == (u_char *)MAP_FAILED) { err(3, "%s", buf2); } 19015702Sphk close(fd2); 19115702Sphk 19215702Sphk /* If identical, we're done. */ 19319813Sphk if((s1.st_size == s2.st_size) && !memcmp(p1, p2, s1.st_size)) { 19415702Sphk s_same_files++; 19515702Sphk s_same_bytes += s1.st_size; 19615702Sphk goto finish; 19715702Sphk } 19815702Sphk 19915702Sphk s_files_chg++; 20015773Sphk change++; 20115702Sphk if (s1.st_size > s2.st_size) 20215702Sphk s_bytes_del += (s1.st_size - s2.st_size); 20315702Sphk else 20415702Sphk s_bytes_add += (s2.st_size - s1.st_size); 20515702Sphk 20615702Sphk m1 = MD5Data(p1, s1.st_size, md5_1); 20715702Sphk m2 = MD5Data(p2, s2.st_size, md5_2); 20815702Sphk 20915702Sphk /* Just a curiosity... */ 21019813Sphk if(!strcmp(m1, m2)) { 21115702Sphk if (s1.st_size != s2.st_size) 21215702Sphk fprintf(stderr, 21315702Sphk "Notice: MD5 same for files of diffent size:\n\t%s\n\t%s\n", 21419813Sphk buf1, buf2); 21515702Sphk goto finish; 21615702Sphk } 21715702Sphk 21815702Sphk { 21915773Sphk u_long l = s2.st_size + 2; 22015773Sphk u_char *cmd = alloca(strlen(buf1)+strlen(buf2)+100); 22115773Sphk u_char *ob = alloca(l), *p; 22215773Sphk int j; 22315773Sphk FILE *F; 22415773Sphk 22519912Sphk if (s1.st_size && p1[s1.st_size-1] != '\n') { 22615773Sphk if (verbose > 0) 22715773Sphk fprintf(stderr, 22815773Sphk "last char != \\n in %s\n", 22915773Sphk buf1); 23015773Sphk goto subst; 23115773Sphk } 23215773Sphk 23319912Sphk if (s2.st_size && p2[s2.st_size-1] != '\n') { 23415773Sphk if (verbose > 0) 23515773Sphk fprintf(stderr, 23615773Sphk "last char != \\n in %s\n", 23715773Sphk buf2); 23815773Sphk goto subst; 23915773Sphk } 24015773Sphk 24115773Sphk for (p=p1; p<p1+s1.st_size; p++) 24215773Sphk if (!*p) { 24315773Sphk if (verbose > 0) 24415773Sphk fprintf(stderr, 24515773Sphk "NULL char in %s\n", 24615773Sphk buf1); 24715773Sphk goto subst; 24815773Sphk } 24915773Sphk 25015773Sphk for (p=p2; p<p2+s2.st_size; p++) 25115773Sphk if (!*p) { 25215773Sphk if (verbose > 0) 25315773Sphk fprintf(stderr, 25415773Sphk "NULL char in %s\n", 25515773Sphk buf2); 25615773Sphk goto subst; 25715773Sphk } 25815773Sphk 25915773Sphk strcpy(cmd, "diff -n "); 26015773Sphk strcat(cmd, buf1); 26115773Sphk strcat(cmd, " "); 26215773Sphk strcat(cmd, buf2); 26319813Sphk F = popen(cmd, "r"); 26415773Sphk for (j = 1, l = 0; l < s2.st_size; ) { 26515773Sphk j = fread(ob+l, 1, s2.st_size - l, F); 26615773Sphk if (j < 1) 26715773Sphk break; 26815773Sphk l += j; 26915773Sphk continue; 27015773Sphk } 27115773Sphk if (j) { 27215773Sphk l = 0; 27315773Sphk while (EOF != fgetc(F)) 27415773Sphk continue; 27515773Sphk } 27615773Sphk pclose(F); 27715773Sphk 27815702Sphk if (l && l < s2.st_size) { 27919813Sphk name_stat("CTMFN", dir2, name, de); 28019813Sphk printf(" %s %s %d\n", m1, m2, (unsigned)l); 28119813Sphk fwrite(ob, 1, l, stdout); 28215773Sphk putchar('\n'); 28315702Sphk s_edit_files++; 28415702Sphk s_edit_bytes += l; 28515702Sphk s_edit_saves += (s2.st_size - l); 28615702Sphk } else { 28715773Sphk subst: 28819813Sphk name_stat("CTMFS", dir2, name, de); 28919813Sphk printf(" %s %s %u\n", m1, m2, (unsigned)s2.st_size); 29019813Sphk fwrite(p2, 1, s2.st_size, stdout); 29115773Sphk putchar('\n'); 29215702Sphk s_sub_files++; 29315702Sphk s_sub_bytes += s2.st_size; 29415702Sphk } 29515702Sphk } 29615702Sphk finish: 29719813Sphk munmap(p1, s1.st_size); 29819813Sphk munmap(p2, s2.st_size); 29915702Sphk } 30015702Sphk} 30115702Sphk 30215702Sphkvoid 30315702SphkAdd(const char *dir1, const char *dir2, const char *name, struct dirent *de) 30415702Sphk{ 30515773Sphk change++; 30615702Sphk if (de->d_type == DT_DIR) { 30715702Sphk char *p = alloca(strlen(name)+strlen(de->d_name)+2); 30819813Sphk strcpy(p, name); strcat(p, de->d_name); strcat(p, "/"); 30919813Sphk name_stat("CTMDM", dir2, name, de); 31015702Sphk putchar('\n'); 31115702Sphk s_new_dirs++; 31219813Sphk DoDir(dir1, dir2, p); 31315702Sphk } else if (de->d_type == DT_REG) { 31415702Sphk char *buf2 = alloca(strlen(dir2) + strlen(name) + 31515702Sphk strlen(de->d_name) + 3); 31615702Sphk char *m2, md5_2[33]; 31715702Sphk u_char *p1; 31815702Sphk struct stat st; 31915702Sphk int fd1; 32015702Sphk 32119813Sphk strcpy(buf2, dir2); 32219813Sphk strcat(buf2, "/"); strcat(buf2, name); 32319813Sphk strcat(buf2, "/"); strcat(buf2, de->d_name); 32419813Sphk fd1 = open(buf2, O_RDONLY); 32529526Scharnier if (fd1 < 0) { err(3, "%s", buf2); } 32619813Sphk fstat(fd1, &st); 32719813Sphk p1=mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd1, 0); 32829526Scharnier if (p1 == (u_char *)MAP_FAILED) { err(3, "%s", buf2); } 32915702Sphk close(fd1); 33015702Sphk m2 = MD5Data(p1, st.st_size, md5_2); 33119813Sphk name_stat("CTMFM", dir2, name, de); 33219813Sphk printf(" %s %u\n", m2, (unsigned)st.st_size); 33319813Sphk fwrite(p1, 1, st.st_size, stdout); 33415702Sphk putchar('\n'); 33519813Sphk munmap(p1, st.st_size); 33615702Sphk s_new_files++; 33715702Sphk s_new_bytes += st.st_size; 33815702Sphk } 33915702Sphk} 34015702Sphk 34115702Sphkvoid 34215702SphkDel (const char *dir1, const char *dir2, const char *name, struct dirent *de) 34315702Sphk{ 34415773Sphk damage++; 34515773Sphk change++; 34615702Sphk if (de->d_type == DT_DIR) { 34715702Sphk char *p = alloca(strlen(name)+strlen(de->d_name)+2); 34819813Sphk strcpy(p, name); strcat(p, de->d_name); strcat(p, "/"); 34919813Sphk DoDir(dir1, dir2, p); 35019813Sphk printf("CTMDR %s%s\n", name, de->d_name); 35119813Sphk fprintf(logf, "CTMDR %s%s\n", name, de->d_name); 35219813Sphk if (verbose > 1) { 35319813Sphk fprintf(stderr, "CTMDR %s%s\n", name, de->d_name); 35419813Sphk } 35515702Sphk s_del_dirs++; 35615702Sphk } else if (de->d_type == DT_REG) { 35715702Sphk char *buf1 = alloca(strlen(dir1) + strlen(name) + 35815702Sphk strlen(de->d_name) + 3); 35915702Sphk char *m1, md5_1[33]; 36019813Sphk strcpy(buf1, dir1); 36119813Sphk strcat(buf1, "/"); strcat(buf1, name); 36219813Sphk strcat(buf1, "/"); strcat(buf1, de->d_name); 36315702Sphk m1 = MD5File(buf1, md5_1); 36419813Sphk printf("CTMFR %s%s %s\n", name, de->d_name, m1); 36519813Sphk fprintf(logf, "CTMFR %s%s %s\n", name, de->d_name, m1); 36619813Sphk if (verbose > 1) { 36719813Sphk fprintf(stderr, "CTMFR %s%s\n", name, de->d_name); 36819813Sphk } 36915702Sphk s_del_files++; 37015702Sphk s_del_bytes += StatFile(buf1)->st_size; 37115702Sphk } 37215702Sphk} 37315702Sphk 37415702Sphkvoid 37515702SphkGetNext(int *i, int *n, struct dirent **nl, const char *dir, const char *name, u_long *ignored, u_long *bogus, u_long *wrong) 37615702Sphk{ 37715702Sphk char buf[BUFSIZ]; 37819816Sphk char buf1[BUFSIZ]; 37915702Sphk 38015702Sphk for (;;) { 38115702Sphk for (;;) { 38215702Sphk (*i)++; 38315702Sphk if (*i >= *n) 38415702Sphk return; 38519816Sphk strcpy(buf1, name); 38619816Sphk if (buf1[strlen(buf1)-1] != '/') 38719816Sphk strcat(buf1, "/"); 38819816Sphk strcat(buf1, nl[*i]->d_name); 38915773Sphk if (flag_ignore && 39019816Sphk !regexec(®_ignore, buf1, 0, 0, 0)) { 39115702Sphk (*ignored)++; 39219816Sphk fprintf(logf, "Ignore %s\n", buf1); 39315773Sphk if (verbose > 2) { 39419816Sphk fprintf(stderr, "Ignore %s\n", buf1); 39515773Sphk } 39615773Sphk } else if (flag_bogus && 39719816Sphk !regexec(®_bogus, buf1, 0, 0, 0)) { 39815702Sphk (*bogus)++; 39919816Sphk fprintf(logf, "Bogus %s\n", buf1); 40019816Sphk fprintf(stderr, "Bogus %s\n", buf1); 40119813Sphk damage++; 40215773Sphk } else { 40319816Sphk *buf = 0; 40419816Sphk if (*dir != '/') 40519816Sphk strcat(buf, "/"); 40619816Sphk strcat(buf, dir); 40719816Sphk if (buf[strlen(buf)-1] != '/') 40819816Sphk strcat(buf, "/"); 40919816Sphk strcat(buf, buf1); 41015702Sphk break; 41115773Sphk } 41215702Sphk free(nl[*i]); nl[*i] = 0; 41315702Sphk } 41415702Sphk /* If the filesystem didn't tell us, find type */ 41515702Sphk if (nl[*i]->d_type == DT_UNKNOWN) 41615702Sphk nl[*i]->d_type = IFTODT(StatFile(buf)->st_mode); 41715702Sphk if (nl[*i]->d_type == DT_REG || nl[*i]->d_type == DT_DIR) 41815702Sphk break; 41915702Sphk (*wrong)++; 42015773Sphk if (verbose > 0) 42119813Sphk fprintf(stderr, "Wrong %s\n", buf); 42215702Sphk free(nl[*i]); nl[*i] = 0; 42315702Sphk } 42415702Sphk} 42515702Sphk 42615702Sphkvoid 42715702SphkDoDir(const char *dir1, const char *dir2, const char *name) 42815702Sphk{ 42919813Sphk int i1, i2, n1, n2, i; 43019813Sphk struct dirent **nl1, **nl2; 43115702Sphk char *buf1 = alloca(strlen(dir1) + strlen(name) + 4); 43215702Sphk char *buf2 = alloca(strlen(dir2) + strlen(name) + 4); 43315702Sphk 43419813Sphk strcpy(buf1, dir1); strcat(buf1, "/"); strcat(buf1, name); 43519813Sphk strcpy(buf2, dir2); strcat(buf2, "/"); strcat(buf2, name); 43615702Sphk n1 = scandir(buf1, &nl1, dirselect, alphasort); 43715702Sphk n2 = scandir(buf2, &nl2, dirselect, alphasort); 43815702Sphk i1 = i2 = -1; 43915702Sphk GetNext(&i1, &n1, nl1, dir1, name, &s1_ignored, &s1_bogus, &s1_wrong); 44015702Sphk GetNext(&i2, &n2, nl2, dir2, name, &s2_ignored, &s2_bogus, &s2_wrong); 44115702Sphk for (;i1 < n1 || i2 < n2;) { 44215702Sphk 44315773Sphk if (damage_limit && damage > damage_limit) 44415773Sphk break; 44515773Sphk 44615702Sphk /* Get next item from list 1 */ 44715702Sphk if (i1 < n1 && !nl1[i1]) 44815702Sphk GetNext(&i1, &n1, nl1, dir1, name, 44915702Sphk &s1_ignored, &s1_bogus, &s1_wrong); 45015702Sphk 45115702Sphk /* Get next item from list 2 */ 45215702Sphk if (i2 < n2 && !nl2[i2]) 45315702Sphk GetNext(&i2, &n2, nl2, dir2, name, 45415702Sphk &s2_ignored, &s2_bogus, &s2_wrong); 45515702Sphk 45615702Sphk if (i1 >= n1 && i2 >= n2) { 45715702Sphk /* Done */ 45815702Sphk break; 45915702Sphk } else if (i1 >= n1 && i2 < n2) { 46015702Sphk /* end of list 1, add anything left on list 2 */ 46119813Sphk Add(dir1, dir2, name, nl2[i2]); 46215702Sphk free(nl2[i2]); nl2[i2] = 0; 46315702Sphk } else if (i1 < n1 && i2 >= n2) { 46415702Sphk /* end of list 2, delete anything left on list 1 */ 46519813Sphk Del(dir1, dir2, name, nl1[i1]); 46615702Sphk free(nl1[i1]); nl1[i1] = 0; 46715702Sphk } else if (!(i = strcmp(nl1[i1]->d_name, nl2[i2]->d_name))) { 46815702Sphk /* Identical names */ 46915702Sphk if (nl1[i1]->d_type == nl2[i2]->d_type) { 47015702Sphk /* same type */ 47119813Sphk Equ(dir1, dir2, name, nl1[i1]); 47215702Sphk } else { 47315702Sphk /* different types */ 47419813Sphk Del(dir1, dir2, name, nl1[i1]); 47519813Sphk Add(dir1, dir2, name, nl2[i2]); 47615702Sphk } 47715702Sphk free(nl1[i1]); nl1[i1] = 0; 47815702Sphk free(nl2[i2]); nl2[i2] = 0; 47915702Sphk } else if (i < 0) { 48015702Sphk /* Something extra in list 1, delete it */ 48119813Sphk Del(dir1, dir2, name, nl1[i1]); 48215702Sphk free(nl1[i1]); nl1[i1] = 0; 48315702Sphk } else { 48415702Sphk /* Something extra in list 2, add it */ 48519813Sphk Add(dir1, dir2, name, nl2[i2]); 48615702Sphk free(nl2[i2]); nl2[i2] = 0; 48715702Sphk } 48815702Sphk } 48915702Sphk if (n1 >= 0) 49015702Sphk free(nl1); 49115702Sphk if (n2 >= 0) 49215702Sphk free(nl2); 49315702Sphk} 49415702Sphk 49515702Sphkint 49615702Sphkmain(int argc, char **argv) 49715702Sphk{ 49815702Sphk int i; 49915702Sphk 50015773Sphk setbuf(stderr, NULL); 50115773Sphk 50219813Sphk#if 0 50319813Sphk if (regcomp(®_bogus, DEFAULT_BOGUS, REG_EXTENDED | REG_NEWLINE)) 50415702Sphk /* XXX use regerror to explain it */ 50529526Scharnier errx(1, "default regular expression argument to -B is botched"); 50615702Sphk flag_bogus = 1; 50715702Sphk 50819813Sphk if (regcomp(®_ignore, DEFAULT_IGNORE, REG_EXTENDED | REG_NEWLINE)) 50915702Sphk /* XXX use regerror to explain it */ 51029526Scharnier errx(1, "default regular expression argument to -I is botched"); 51115702Sphk flag_ignore = 1; 51219813Sphk#endif 51315702Sphk 51424428Simp while ((i = getopt(argc, argv, "D:I:B:l:qv")) != -1) 51515702Sphk switch (i) { 51615773Sphk case 'D': 51719813Sphk damage_limit = strtol(optarg, 0, 0); 51815773Sphk if (damage_limit < 0) 51929526Scharnier errx(1, "damage limit must be positive"); 52015773Sphk break; 52115702Sphk case 'I': 52215702Sphk if (flag_ignore) 52315702Sphk regfree(®_ignore); 52415702Sphk flag_ignore = 0; 52515702Sphk if (!*optarg) 52615702Sphk break; 52719813Sphk if (regcomp(®_ignore, optarg, 52815702Sphk REG_EXTENDED | REG_NEWLINE)) 52915702Sphk /* XXX use regerror to explain it */ 53029526Scharnier errx(1, "regular expression argument to -I is botched"); 53115702Sphk flag_ignore = 1; 53215702Sphk break; 53315702Sphk case 'B': 53415702Sphk if (flag_bogus) 53515702Sphk regfree(®_bogus); 53615702Sphk flag_bogus = 0; 53715702Sphk if (!*optarg) 53815702Sphk break; 53919813Sphk if (regcomp(®_bogus, optarg, 54015702Sphk REG_EXTENDED | REG_NEWLINE)) 54115702Sphk /* XXX use regerror to explain it */ 54229526Scharnier errx(1, "regular expression argument to -B is botched"); 54315702Sphk flag_bogus = 1; 54415702Sphk break; 54519813Sphk case 'l': 54619813Sphk logf = fopen(optarg, "w"); 54719813Sphk if (!logf) 54829526Scharnier err(1, "%s", optarg); 549124993Smckay setlinebuf(logf); 55019813Sphk break; 55115773Sphk case 'q': 55215773Sphk verbose--; 55315773Sphk break; 55415773Sphk case 'v': 55515773Sphk verbose++; 55615773Sphk break; 55715702Sphk case '?': 55815702Sphk default: 55915773Sphk Usage(); 56015702Sphk return (1); 56115702Sphk } 56215702Sphk argc -= optind; 56315702Sphk argv += optind; 56415702Sphk 56519813Sphk if (!logf) 56669793Sobrien logf = fopen(_PATH_DEVNULL, "w"); 56715702Sphk 56819813Sphk setbuf(stdout, 0); 56919813Sphk 57015773Sphk if (argc != 6) { 57115773Sphk Usage(); 57215773Sphk return (1); 57315773Sphk } 57415773Sphk 57519813Sphk signal(SIGINFO, stat_info); 57615773Sphk 57719813Sphk fprintf(stderr, "CTM_BEGIN 2.0 %s %s %s %s\n", 57819813Sphk argv[0], argv[1], argv[2], argv[3]); 57919813Sphk fprintf(logf, "CTM_BEGIN 2.0 %s %s %s %s\n", 58019813Sphk argv[0], argv[1], argv[2], argv[3]); 58115773Sphk printf("CTM_BEGIN 2.0 %s %s %s %s\n", 58215773Sphk argv[0], argv[1], argv[2], argv[3]); 58319813Sphk DoDir(argv[4], argv[5], ""); 58415773Sphk if (damage_limit && damage > damage_limit) { 58519813Sphk print_stat(stderr, "DAMAGE: "); 58629526Scharnier errx(1, "damage of %d would exceed %d files", 58719813Sphk damage, damage_limit); 58819813Sphk } else if (change < 2) { 58929526Scharnier errx(4, "no changes"); 59015773Sphk } else { 59115773Sphk printf("CTM_END "); 59219813Sphk fprintf(logf, "CTM_END\n"); 59319813Sphk print_stat(stderr, "END: "); 59415773Sphk } 59515702Sphk exit(0); 59615702Sphk} 597