169793Sobrien/* $FreeBSD$ */ 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$ 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); 221124994Smckay u_char *ob = malloc(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 } 295124994Smckay free(ob); 29615702Sphk } 29715702Sphk finish: 29819813Sphk munmap(p1, s1.st_size); 29919813Sphk munmap(p2, s2.st_size); 30015702Sphk } 30115702Sphk} 30215702Sphk 30315702Sphkvoid 30415702SphkAdd(const char *dir1, const char *dir2, const char *name, struct dirent *de) 30515702Sphk{ 30615773Sphk change++; 30715702Sphk if (de->d_type == DT_DIR) { 30815702Sphk char *p = alloca(strlen(name)+strlen(de->d_name)+2); 30919813Sphk strcpy(p, name); strcat(p, de->d_name); strcat(p, "/"); 31019813Sphk name_stat("CTMDM", dir2, name, de); 31115702Sphk putchar('\n'); 31215702Sphk s_new_dirs++; 31319813Sphk DoDir(dir1, dir2, p); 31415702Sphk } else if (de->d_type == DT_REG) { 31515702Sphk char *buf2 = alloca(strlen(dir2) + strlen(name) + 31615702Sphk strlen(de->d_name) + 3); 31715702Sphk char *m2, md5_2[33]; 31815702Sphk u_char *p1; 31915702Sphk struct stat st; 32015702Sphk int fd1; 32115702Sphk 32219813Sphk strcpy(buf2, dir2); 32319813Sphk strcat(buf2, "/"); strcat(buf2, name); 32419813Sphk strcat(buf2, "/"); strcat(buf2, de->d_name); 32519813Sphk fd1 = open(buf2, O_RDONLY); 32629526Scharnier if (fd1 < 0) { err(3, "%s", buf2); } 32719813Sphk fstat(fd1, &st); 32819813Sphk p1=mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd1, 0); 32929526Scharnier if (p1 == (u_char *)MAP_FAILED) { err(3, "%s", buf2); } 33015702Sphk close(fd1); 33115702Sphk m2 = MD5Data(p1, st.st_size, md5_2); 33219813Sphk name_stat("CTMFM", dir2, name, de); 33319813Sphk printf(" %s %u\n", m2, (unsigned)st.st_size); 33419813Sphk fwrite(p1, 1, st.st_size, stdout); 33515702Sphk putchar('\n'); 33619813Sphk munmap(p1, st.st_size); 33715702Sphk s_new_files++; 33815702Sphk s_new_bytes += st.st_size; 33915702Sphk } 34015702Sphk} 34115702Sphk 34215702Sphkvoid 34315702SphkDel (const char *dir1, const char *dir2, const char *name, struct dirent *de) 34415702Sphk{ 34515773Sphk damage++; 34615773Sphk change++; 34715702Sphk if (de->d_type == DT_DIR) { 34815702Sphk char *p = alloca(strlen(name)+strlen(de->d_name)+2); 34919813Sphk strcpy(p, name); strcat(p, de->d_name); strcat(p, "/"); 35019813Sphk DoDir(dir1, dir2, p); 35119813Sphk printf("CTMDR %s%s\n", name, de->d_name); 35219813Sphk fprintf(logf, "CTMDR %s%s\n", name, de->d_name); 35319813Sphk if (verbose > 1) { 35419813Sphk fprintf(stderr, "CTMDR %s%s\n", name, de->d_name); 35519813Sphk } 35615702Sphk s_del_dirs++; 35715702Sphk } else if (de->d_type == DT_REG) { 35815702Sphk char *buf1 = alloca(strlen(dir1) + strlen(name) + 35915702Sphk strlen(de->d_name) + 3); 36015702Sphk char *m1, md5_1[33]; 36119813Sphk strcpy(buf1, dir1); 36219813Sphk strcat(buf1, "/"); strcat(buf1, name); 36319813Sphk strcat(buf1, "/"); strcat(buf1, de->d_name); 36415702Sphk m1 = MD5File(buf1, md5_1); 36519813Sphk printf("CTMFR %s%s %s\n", name, de->d_name, m1); 36619813Sphk fprintf(logf, "CTMFR %s%s %s\n", name, de->d_name, m1); 36719813Sphk if (verbose > 1) { 36819813Sphk fprintf(stderr, "CTMFR %s%s\n", name, de->d_name); 36919813Sphk } 37015702Sphk s_del_files++; 37115702Sphk s_del_bytes += StatFile(buf1)->st_size; 37215702Sphk } 37315702Sphk} 37415702Sphk 37515702Sphkvoid 37615702SphkGetNext(int *i, int *n, struct dirent **nl, const char *dir, const char *name, u_long *ignored, u_long *bogus, u_long *wrong) 37715702Sphk{ 37815702Sphk char buf[BUFSIZ]; 37919816Sphk char buf1[BUFSIZ]; 38015702Sphk 38115702Sphk for (;;) { 38215702Sphk for (;;) { 38315702Sphk (*i)++; 38415702Sphk if (*i >= *n) 38515702Sphk return; 38619816Sphk strcpy(buf1, name); 38719816Sphk if (buf1[strlen(buf1)-1] != '/') 38819816Sphk strcat(buf1, "/"); 38919816Sphk strcat(buf1, nl[*i]->d_name); 39015773Sphk if (flag_ignore && 39119816Sphk !regexec(®_ignore, buf1, 0, 0, 0)) { 39215702Sphk (*ignored)++; 39319816Sphk fprintf(logf, "Ignore %s\n", buf1); 39415773Sphk if (verbose > 2) { 39519816Sphk fprintf(stderr, "Ignore %s\n", buf1); 39615773Sphk } 39715773Sphk } else if (flag_bogus && 39819816Sphk !regexec(®_bogus, buf1, 0, 0, 0)) { 39915702Sphk (*bogus)++; 40019816Sphk fprintf(logf, "Bogus %s\n", buf1); 40119816Sphk fprintf(stderr, "Bogus %s\n", buf1); 40219813Sphk damage++; 40315773Sphk } else { 40419816Sphk *buf = 0; 40519816Sphk if (*dir != '/') 40619816Sphk strcat(buf, "/"); 40719816Sphk strcat(buf, dir); 40819816Sphk if (buf[strlen(buf)-1] != '/') 40919816Sphk strcat(buf, "/"); 41019816Sphk strcat(buf, buf1); 41115702Sphk break; 41215773Sphk } 41315702Sphk free(nl[*i]); nl[*i] = 0; 41415702Sphk } 41515702Sphk /* If the filesystem didn't tell us, find type */ 41615702Sphk if (nl[*i]->d_type == DT_UNKNOWN) 41715702Sphk nl[*i]->d_type = IFTODT(StatFile(buf)->st_mode); 41815702Sphk if (nl[*i]->d_type == DT_REG || nl[*i]->d_type == DT_DIR) 41915702Sphk break; 42015702Sphk (*wrong)++; 42115773Sphk if (verbose > 0) 42219813Sphk fprintf(stderr, "Wrong %s\n", buf); 42315702Sphk free(nl[*i]); nl[*i] = 0; 42415702Sphk } 42515702Sphk} 42615702Sphk 42715702Sphkvoid 42815702SphkDoDir(const char *dir1, const char *dir2, const char *name) 42915702Sphk{ 43019813Sphk int i1, i2, n1, n2, i; 43119813Sphk struct dirent **nl1, **nl2; 43215702Sphk char *buf1 = alloca(strlen(dir1) + strlen(name) + 4); 43315702Sphk char *buf2 = alloca(strlen(dir2) + strlen(name) + 4); 43415702Sphk 43519813Sphk strcpy(buf1, dir1); strcat(buf1, "/"); strcat(buf1, name); 43619813Sphk strcpy(buf2, dir2); strcat(buf2, "/"); strcat(buf2, name); 43715702Sphk n1 = scandir(buf1, &nl1, dirselect, alphasort); 43815702Sphk n2 = scandir(buf2, &nl2, dirselect, alphasort); 43915702Sphk i1 = i2 = -1; 44015702Sphk GetNext(&i1, &n1, nl1, dir1, name, &s1_ignored, &s1_bogus, &s1_wrong); 44115702Sphk GetNext(&i2, &n2, nl2, dir2, name, &s2_ignored, &s2_bogus, &s2_wrong); 44215702Sphk for (;i1 < n1 || i2 < n2;) { 44315702Sphk 44415773Sphk if (damage_limit && damage > damage_limit) 44515773Sphk break; 44615773Sphk 44715702Sphk /* Get next item from list 1 */ 44815702Sphk if (i1 < n1 && !nl1[i1]) 44915702Sphk GetNext(&i1, &n1, nl1, dir1, name, 45015702Sphk &s1_ignored, &s1_bogus, &s1_wrong); 45115702Sphk 45215702Sphk /* Get next item from list 2 */ 45315702Sphk if (i2 < n2 && !nl2[i2]) 45415702Sphk GetNext(&i2, &n2, nl2, dir2, name, 45515702Sphk &s2_ignored, &s2_bogus, &s2_wrong); 45615702Sphk 45715702Sphk if (i1 >= n1 && i2 >= n2) { 45815702Sphk /* Done */ 45915702Sphk break; 46015702Sphk } else if (i1 >= n1 && i2 < n2) { 46115702Sphk /* end of list 1, add anything left on list 2 */ 46219813Sphk Add(dir1, dir2, name, nl2[i2]); 46315702Sphk free(nl2[i2]); nl2[i2] = 0; 46415702Sphk } else if (i1 < n1 && i2 >= n2) { 46515702Sphk /* end of list 2, delete anything left on list 1 */ 46619813Sphk Del(dir1, dir2, name, nl1[i1]); 46715702Sphk free(nl1[i1]); nl1[i1] = 0; 46815702Sphk } else if (!(i = strcmp(nl1[i1]->d_name, nl2[i2]->d_name))) { 46915702Sphk /* Identical names */ 47015702Sphk if (nl1[i1]->d_type == nl2[i2]->d_type) { 47115702Sphk /* same type */ 47219813Sphk Equ(dir1, dir2, name, nl1[i1]); 47315702Sphk } else { 47415702Sphk /* different types */ 47519813Sphk Del(dir1, dir2, name, nl1[i1]); 47619813Sphk Add(dir1, dir2, name, nl2[i2]); 47715702Sphk } 47815702Sphk free(nl1[i1]); nl1[i1] = 0; 47915702Sphk free(nl2[i2]); nl2[i2] = 0; 48015702Sphk } else if (i < 0) { 48115702Sphk /* Something extra in list 1, delete it */ 48219813Sphk Del(dir1, dir2, name, nl1[i1]); 48315702Sphk free(nl1[i1]); nl1[i1] = 0; 48415702Sphk } else { 48515702Sphk /* Something extra in list 2, add it */ 48619813Sphk Add(dir1, dir2, name, nl2[i2]); 48715702Sphk free(nl2[i2]); nl2[i2] = 0; 48815702Sphk } 48915702Sphk } 49015702Sphk if (n1 >= 0) 49115702Sphk free(nl1); 49215702Sphk if (n2 >= 0) 49315702Sphk free(nl2); 49415702Sphk} 49515702Sphk 49615702Sphkint 49715702Sphkmain(int argc, char **argv) 49815702Sphk{ 49915702Sphk int i; 50015702Sphk 50115773Sphk setbuf(stderr, NULL); 50215773Sphk 50319813Sphk#if 0 50419813Sphk if (regcomp(®_bogus, DEFAULT_BOGUS, REG_EXTENDED | REG_NEWLINE)) 50515702Sphk /* XXX use regerror to explain it */ 50629526Scharnier errx(1, "default regular expression argument to -B is botched"); 50715702Sphk flag_bogus = 1; 50815702Sphk 50919813Sphk if (regcomp(®_ignore, DEFAULT_IGNORE, REG_EXTENDED | REG_NEWLINE)) 51015702Sphk /* XXX use regerror to explain it */ 51129526Scharnier errx(1, "default regular expression argument to -I is botched"); 51215702Sphk flag_ignore = 1; 51319813Sphk#endif 51415702Sphk 51524428Simp while ((i = getopt(argc, argv, "D:I:B:l:qv")) != -1) 51615702Sphk switch (i) { 51715773Sphk case 'D': 51819813Sphk damage_limit = strtol(optarg, 0, 0); 51915773Sphk if (damage_limit < 0) 52029526Scharnier errx(1, "damage limit must be positive"); 52115773Sphk break; 52215702Sphk case 'I': 52315702Sphk if (flag_ignore) 52415702Sphk regfree(®_ignore); 52515702Sphk flag_ignore = 0; 52615702Sphk if (!*optarg) 52715702Sphk break; 52819813Sphk if (regcomp(®_ignore, optarg, 52915702Sphk REG_EXTENDED | REG_NEWLINE)) 53015702Sphk /* XXX use regerror to explain it */ 53129526Scharnier errx(1, "regular expression argument to -I is botched"); 53215702Sphk flag_ignore = 1; 53315702Sphk break; 53415702Sphk case 'B': 53515702Sphk if (flag_bogus) 53615702Sphk regfree(®_bogus); 53715702Sphk flag_bogus = 0; 53815702Sphk if (!*optarg) 53915702Sphk break; 54019813Sphk if (regcomp(®_bogus, optarg, 54115702Sphk REG_EXTENDED | REG_NEWLINE)) 54215702Sphk /* XXX use regerror to explain it */ 54329526Scharnier errx(1, "regular expression argument to -B is botched"); 54415702Sphk flag_bogus = 1; 54515702Sphk break; 54619813Sphk case 'l': 54719813Sphk logf = fopen(optarg, "w"); 54819813Sphk if (!logf) 54929526Scharnier err(1, "%s", optarg); 550124993Smckay setlinebuf(logf); 55119813Sphk break; 55215773Sphk case 'q': 55315773Sphk verbose--; 55415773Sphk break; 55515773Sphk case 'v': 55615773Sphk verbose++; 55715773Sphk break; 55815702Sphk case '?': 55915702Sphk default: 56015773Sphk Usage(); 56115702Sphk return (1); 56215702Sphk } 56315702Sphk argc -= optind; 56415702Sphk argv += optind; 56515702Sphk 56619813Sphk if (!logf) 56769793Sobrien logf = fopen(_PATH_DEVNULL, "w"); 56815702Sphk 56919813Sphk setbuf(stdout, 0); 57019813Sphk 57115773Sphk if (argc != 6) { 57215773Sphk Usage(); 57315773Sphk return (1); 57415773Sphk } 57515773Sphk 57619813Sphk signal(SIGINFO, stat_info); 57715773Sphk 57819813Sphk fprintf(stderr, "CTM_BEGIN 2.0 %s %s %s %s\n", 57919813Sphk argv[0], argv[1], argv[2], argv[3]); 58019813Sphk fprintf(logf, "CTM_BEGIN 2.0 %s %s %s %s\n", 58119813Sphk argv[0], argv[1], argv[2], argv[3]); 58215773Sphk printf("CTM_BEGIN 2.0 %s %s %s %s\n", 58315773Sphk argv[0], argv[1], argv[2], argv[3]); 58419813Sphk DoDir(argv[4], argv[5], ""); 58515773Sphk if (damage_limit && damage > damage_limit) { 58619813Sphk print_stat(stderr, "DAMAGE: "); 58729526Scharnier errx(1, "damage of %d would exceed %d files", 58819813Sphk damage, damage_limit); 58919813Sphk } else if (change < 2) { 59029526Scharnier errx(4, "no changes"); 59115773Sphk } else { 59215773Sphk printf("CTM_END "); 59319813Sphk fprintf(logf, "CTM_END\n"); 59419813Sphk print_stat(stderr, "END: "); 59515773Sphk } 59615702Sphk exit(0); 59715702Sphk} 598