📄 synctree.c
字号:
arg0, Spath); because(); return; } printf("Special file %s created\n", Spath); break;#ifdef S_IFLNK case S_IFLNK: if (interact && !update) { printf("Install %s -> %s", Spath, Slnkpth); if (!ask('n')) { order(CANCEL); return; } } if (symlink(Slnkpth, Spath) < 0) { fprintf(stderr, "%s: Can't create symlink %s", arg0, Spath); because(); return; } printf("%s %s -> %s\n", forced_update ? "Updated: " : "Installed:", Spath, Slnkpth); break;#endif case S_IFREG: if (interact && !update) { printf("Install %s", Spath); if (!ask('n')) { order(CANCEL); return; } } order(CAT); if (answer() != DATA) return; busy= 1; if ((f= creat(Spath, backup ? 0644 : Sst.st_mode&07777)) < 0) { busy= 0; fprintf(stderr, "%s: Can't create %s", arg0, Spath); because(); } while ((n= receive(buf, sizeof(buf)))>0) { if (f >= 0 && write(f, buf, n) != n) { fprintf(stderr, "%s: Write error on %s", arg0, Spath); because(); close(f); f= -1; } } if (n < 0) { fprintf(stderr, "%s: Slave read err on %s\n", arg0, Spath); } if (f >= 0) close(f); if (n < 0 || f < 0) { makeold(); busy= 0; return; } busy= 0; printf("%s %s\n", forced_update ? Sst.st_mtime < st.st_mtime ? "Restored: " : "Updated: " : "Installed:", Spath ); break; default: fprintf(stderr, "%s: Won't add file with strange mode %05o: %s\n", arg0, Sst.st_mode, Spath); order(CANCEL); return; } setmodes(1);}static int delete(update) int update;/* Delete path. */{ int forced_update= force && update; if (S_ISDIR(st.st_mode)) { if (install) return 0; if (!force) { printf("Delete dir %s", path); if (!ask('n')) return 0; } if (!removedir(path)) { ex= 1; return 0; } if (!forced_update) printf("Directory %s deleted.\n", path); return 1; } if (install && !update) return 0; if (!force) { printf("Delete %s", path); if (!ask((interact && !update) ? 'n' : 'y')) return 0; } if (unlink(path)<0) { fprintf(stderr, "Can't delete %s", path); because(); return 0; } cancellink(); if (!forced_update) printf("Deleted: %s\n", path); return 1;}static int different()/* Return true iff path and Spath are different. */{ if (! ( (linkpath == nil && Slinkpath == nil) || (linkpath != nil && Slinkpath != nil && strcmp(linkpath, Slinkpath) == 0) )) { linkpath= Slinkpath; return 1; } if ((st.st_mode & S_IFMT) != (Sst.st_mode & S_IFMT)) return 1; switch (st.st_mode & S_IFMT) { case S_IFDIR: return 0; case S_IFBLK: case S_IFCHR: return st.st_rdev != Sst.st_rdev; case S_IFREG: if (install) return Sst.st_mtime > st.st_mtime; return st.st_size != Sst.st_size || st.st_mtime != Sst.st_mtime; case S_IFIFO: return 0;#ifdef S_IFLNK case S_IFLNK: return strcmp(lnkpth, Slnkpth) != 0;#endif default: return 1; }}static void compare()/* See if path and Spath are same. */{ if (different()) { if (!force) { printf("%sing %s (delete + add)\n", Sst.st_mtime < st.st_mtime ? "Restor" : "Updat", path); } if (delete(1)) add(1); } else { if (!install) setmodes(0); if (S_ISDIR(st.st_mode)) { order(ENTER); enter(); } }}static int done= 0, Sdone= 0;static enum action { ADD, COMPARE, DELETE } action()/* Look at path's of master and slave, compare them alphabetically to see * who is ahead of who, then tell what is to be done. */{ int c; char *Sp, *p; if (done) return ADD; /* Slave still has names. */ if (Sdone) return DELETE; /* Master has too many names. */ /* Compare paths. Let "a/a" come before "a.a". */ Sp= Spath; p= path; while (*Sp == *p && *Sp != 0) { Sp++; p++; } if (*Sp == '/') return ADD; if (*p == '/') return DELETE; return (c= strcmp(Sp, p)) == 0 ? COMPARE : c < 0 ? ADD : DELETE;}static void master()/* Synchronise file tree to that of its slave. */{ enum action a= COMPARE; /* Trick first advances. */ umask(backup ? 0022 : 0000); signal(SIGPIPE, SIG_IGN); signal(SIGHUP, bail_out); signal(SIGINT, bail_out); signal(SIGTERM, bail_out); while (!done || !Sdone) { if (!Sdone && (a == ADD || a == COMPARE)) { /* Slave advances. */ order(ADVANCE); switch (answer()) { case PATH: Slinkpath= nil; receive(Spath, sizeof(Spath)); recstat(&Sst); break; case LINK: receive(Slnkpth, sizeof(Slnkpth)); Slinkpath= Slnkpth; receive(Spath, sizeof(Spath)); recstat(&Sst); break; case SYMLINK: Slinkpath= nil; receive(Slnkpth, sizeof(Slnkpth)); receive(Spath, sizeof(Spath)); recstat(&Sst); break; case DONE: Sdone= 1; break; default: fprintf(stderr, "%s: Strange answer from slave.\n", arg0); exit(1); } } if (!done && (a == COMPARE || a == DELETE)) { /* Master advances. */ if (!advance()) done= 1; } if (done && Sdone) break; switch (a= action()) { case ADD: /* Spath exists, path doesn't, add? */ add(0); break; case COMPARE: /* They both exist, are they the same? */ compare(); break; case DELETE: /* path exists, Spath doesn't, delete? */ delete(0); } fflush(stdout); /* Don't keep user in suspense. */ } order(ex == 0 ? DIE : DIE_BAD);}static void mediator()/* Sits at the local machine and passes orders from master to slave, both * on remote machines. Only diagnostics and questions are handled. */{ enum orders req; for (;;) { switch (req= request()) { case DIE_BAD: ex= 1; /*FALL THROUGH*/ case DIE: order(DIE); return; case POSITIVE: order(ask('y') ? PASS_YES : PASS_NO); break; case NEGATIVE: order(ask('n') ? PASS_YES : PASS_NO); break; default: order(req); } }}#define P_EXIT 1 /* Make sure process doesn't return. */#define P_SHADOW 2 /* Always use exec on 68000. */static void startprocess(proc, machine, path, p_flags) void (*proc)(); char *machine, *path; int p_flags;{ char *argv[10], **argp= argv; char flags[10], *pfl= flags; if (machine != nil) { char *u= machine, *m; *argp++ = "rsh"; if ((m= strchr(machine, '@')) != nil) { *m++ = 0; *argp++ = "-l"; *argp++ = u; machine= m; } *argp++ = machine; } else /* Without this check it would run like a pig on an non MMU 68000: */ if (!(USE_SHADOWING && p_flags & P_SHADOW)) { if (chdir(path) < 0) { if (proc != master || errno != ENOENT || mkdir(path, 0700) < 0) perrx(path); if (chdir(path) < 0) perrx(path); printf("Destination directory %s created\n", path); } isvisible(path); isbackup(proc == slave); (*proc)(); if (p_flags & P_EXIT) exit(ex); return; } *argp++ = SYNCNAME; *pfl++ = '-'; if (interact) *pfl++ = 'i'; if (install) *pfl++ = 'u'; if (force) *pfl++ = 'f'; *pfl= 0; *argp++ = flags; *argp++ = proc == slave ? SLAVENAME : MASTERNAME; *argp++ = path; *argp++ = nil;#ifdef DEBUG fprintf(stderr, "execlp("); for (argp= argv; *argp != nil; argp++) fprintf(stderr, "%s, ", *argp); fprintf(stderr, "nil);\n");#endif execvp(argv[0], argv); perrx(argv[0]);}void splitcolon(path, amach, adir) char *path, **amach, **adir;{ char *dir= path; for (;;) { if (*dir == ':') { *dir++ = 0; *amach= path; *adir= dir; break; } if (*dir == 0 || *dir == '/') { *amach= nil; *adir= path; break; } dir++; }}static void Usage(){ fprintf(stderr, "Usage: %s [-iuf] [[user@]machine:]dir1 [[user@]machine:]dir2\n", arg0); exit(1);}main(argc, argv) int argc; char **argv;{ char *s_mach, *s_dir; char *m_mach, *m_dir; int m2s[2], s2m[2], m2m[2]; int s_pid= 0, m_pid= 0; int r; if ((arg0= strrchr(argv[0], '/')) == nil) arg0= argv[0]; else arg0++; while (argc>1 && argv[1][0] == '-') { char *f= argv[1]+1; while (*f != 0) { switch (*f++) { case 'i': interact= 1; break; case 'u': install= 1; break; case 'f': force= 1; break; default: Usage(); } } argc--; argv++; } if (argc != 3) Usage(); if (strcmp(argv[1], SLAVENAME) == 0) { arg0= "Slave"; splitcolon(argv[2], &s_mach, &s_dir); startprocess(slave, s_mach, s_dir, P_EXIT); } else if (strcmp(argv[1], MASTERNAME) == 0) { arg0= "Master"; splitcolon(argv[2], &m_mach, &m_dir); startprocess(master, m_mach, m_dir, P_EXIT); } splitcolon(argv[1], &s_mach, &s_dir); splitcolon(argv[2], &m_mach, &m_dir); /* How difficult can plumbing be? */ if (pipe(m2s) < 0 || pipe(s2m) < 0) perrx("pipe()"); if (m_mach == nil) { /* synctree [machine:]dir1 dir2 */ switch (s_pid= fork()) { case -1: perrx("fork()"); case 0: dup2(m2s[0], 0); close(m2s[0]); close(m2s[1]); dup2(s2m[1], 1); close(s2m[0]); close(s2m[1]); arg0= "Slave"; startprocess(slave, s_mach, s_dir, P_EXIT|P_SHADOW); } chan[0]= s2m[0]; close(s2m[1]); chan[1]= m2s[1]; close(m2s[0]); startprocess(master, m_mach, m_dir, 0); } else if (s_mach == nil) { /* synctree dir1 machine:dir2 */ switch (m_pid= fork()) { case -1: perrx("fork()"); case 0: dup2(s2m[0], 0); close(s2m[0]); close(s2m[1]); dup2(m2s[1], 1); close(m2s[0]); close(m2s[1]); arg0= "Master"; startprocess(master, m_mach, m_dir, P_EXIT|P_SHADOW); } chan[0]= m2s[0]; close(m2s[1]); chan[1]= s2m[1]; close(s2m[0]); startprocess(slave, s_mach, s_dir, 0); } else { /* synctree machine1:dir1 machine2:dir2 */ if (pipe(m2m) < 0) perrx(pipe); switch (s_pid= fork()) { case -1: perrx("fork()"); case 0: dup2(m2s[0], 0); close(m2s[0]); close(m2s[1]); dup2(s2m[1], 1); close(s2m[0]); close(s2m[1]); close(m2m[0]); close(m2m[1]); arg0= "Slave"; startprocess(slave, s_mach, s_dir, P_EXIT|P_SHADOW); } switch (m_pid= fork()) { case -1: perrx("fork()"); case 0: dup2(s2m[0], 0); close(s2m[0]); close(s2m[1]); close(m2s[0]); close(m2s[1]); dup2(m2m[1], 1); close(m2m[0]); close(m2m[1]); arg0= "Master"; startprocess(master, m_mach, m_dir, P_EXIT|P_SHADOW); } close(s2m[0]); close(s2m[1]); chan[0]= m2m[0]; close(m2m[1]); chan[1]= m2s[1]; close(m2s[0]); mediator(); } close(chan[0]); close(chan[1]); alarm(15); /* Don't wait(2) forever. */ while (s_pid != 0 || m_pid != 0) { if ((r= wait((int *) nil)) < 0) perrx("wait()"); if (r == s_pid) s_pid= 0; if (r == m_pid) m_pid= 0; } exit(ex);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -