Skip to content.

www.linux-os.ru

Sections
Personal tools
You are here: Home » Members » raorn's Home » rsync-over-CDRW

rsync-over-CDRW

Как синхронизировать Сизиф при помощи CDRW дисков

Для чего это нужно

Есть два места (назовём их "дом" и "работа"). "На работе" есть быстрый канал и зеркало Сизифа, "дома" только зеркало, принесённое с "работы" некоторое время назад. Хочется периодически синхронизировать "домашнее" и "рабочее" зеркала. Можно таскать жёсткий диск с "работы" "домой" раз в неделю (месяц, пол года), но это быстро надоедает. Поэтому будем копировать только изменения. Единственное условие - "дома" и "на работе" зеркала должны находиться по одному пути (например /var/ftp/Sisyphus)

"Дома"

"Дома" надо понять, что именно у нас есть. Самый простой способ - пройтись по всему синхронизируемому дереву и посчитать md5 суммы файлов. Так как в самом Сизифе находится некоторое (довольно большое) количество символических ссылок, надо отслеживать и их. Для этого нарисуем простенький скрипт и назовём его 'lmd5sum':

  #!/bin/sh

  while [ -n "$1" ]; do
      if [ -L "$1" ]; then
          echo "`readlink "$1" | md5sum | cut -b 1-33` $1"
      else
          md5sum "$1"
      fi
      shift
  done
  exit $?

Далее помещаем lmd5sum куда-нибудь в $PATH и создаём "снимок" нашего зеркала:

  find "/var/ftp/Sisyphus" \( -type f -or -type l \) -print0 | xargs -0 lmd5sum | sort -k 2 > `date +%Y%m%d`.list

С этим списком и скриптом lmd5sum благополучно едем "на работу"

"На работе"

У нас есть текущее зеркало Сизифа и "домашний" "снимок" старого репозитария. Аналогичным образом создаём "рабочий" "снимок":

  find "/var/ftp/Sisyphus" \( -type f -or -type l \) -print0 | xargs -0 lmd5sum | sort -k 2 > `date +%Y%m%d`.list

И смотрим изменения:

  diff -U0 домашний_снимок рабочий_снимок > difference.list

Далее надо пройтись по difference.list, для всех "удалённых" строк удалить файлы, а для "добавленных" поместить в архив. Сделаем это сразу, создав скрипт, который удалит "старые" файлы и распакует архив с "новыми". Сам архив "приклеим" к скрипту обновления:

  cat difference.list | perl -e '
  open UPSH, '>', "update.sh" or die;
  print UPSH "#!/bin/sh\n";
  print UPSH "echo -e \"\\nMaking update to $ENV{cdate}\\n\"\n";
  $l = 7;
  while(<>) {
      chomp;
      ($w, $f) = ($_ =~ /(.)[0-9a-f]{32}.\s*(\S+)/);
      next if $w !~ /[+-]/;
      if ($w =~ /-/) {
          print UPSH "rm -f \"".$f."\" && echo \"- ".$f."\"\n";
          $l++;
      } else {
          print $f."\000";
      }
  }

  print UPSH "\n";
  print UPSH "tail +$l \"\$0\" | tar xPvf - | xargs -i echo \"+ {}\"\n";
  print UPSH "apt-get update\n";
  print UPSH "exit \$?;\n";
  close UPSH;
  ' > newfiles

  tar cPf - --null -T newfiles >> update.sh

У нас получился большой файл update.sh, который можно записывать на CDRW и относить "домой".

Снова "дома"

Дальше всё просто - sh /path/to/update.sh и наблюдаем за процессом. Сначала удалятся "старые" файлы, потом распакуются "новые". Сделано это по той причине, что может измениться файл с постоянным именем (например хэши apt). Если сначала распаковать "новое", а потом удалить "старое", такие файлы будут удалены.

Пишем скрипт

Так как "юниксоиды - народ ленивый, им проще потратить два часа на написание скрипта, который за две минуты сделает получасовую работу" (народная мудрость), напишем скрипт, который всё сделает за нас. Назовём его 'makeupdate':

  #!/bin/sh

  Usage() {
      cat <<EOF
  Usage: ${0##*/} {--list | DATE} DIR
  EOF
      exit $1
  }

  Exit() {
      local rc=$?
      trap '' EXIT
      rm -f -- $tmpfile
      exit $rc
  }

  if [ ! $# -eq 2 ]; then
      Usage 1 1>&2
  fi

  file=""
  dir=""
  what=""

  export cdate=`date +%Y%m%d`

  tmpfile=`mktemp -t makeupdate.XXXXXXXXXX`
  trap 'Exit ' EXIT HUP INT PIPE TERM QUIT

  sdate="$1"
  dir="$2"

  find "$dir" \( -type f -or -type l \) -print0 | xargs -0 lmd5sum |
  sort -k 2 |
  (if [ "$sdate" = "--list" ]; then
      cat > $cdate.list
  else
      tee $cdate.list |
      diff -U0 $sdate.list - |
      perl -e '
  open UPSH, ">update.sh" or die;
  print UPSH "#!/bin/sh\n";
  print UPSH "echo -e \"\\nMaking update to $ENV{cdate}\\n\"\n";
  $l = 7;
  while(<>) {
      chomp;
      ($w, $f) = ($_ =~ /(.)[0-9a-f]{32}.\s*(\S+)/);
      next if $w !~ /[+-]/;
      if ($w =~ /-/) {
          print UPSH "rm -f \"".$f."\" && echo \"- ".$f."\"\n";
          $l++;
      } else {
          print $f."\000";
      }
  }

  print UPSH "\n";
  print UPSH "tail +$l \"\$0\" | tar xPvf - | xargs -i echo \"+ {}\"\n";
  print UPSH "apt-get update\n";
  print UPSH "exit \$?;\n";
  close UPSH;
  ' > $tmpfile
      tar cPf - --null -T $tmpfile >> update.sh
  fi )
  rm -f $tmpfile
  trap '' EXIT
  exit 0

Есть два варианта запуска скрипта. "Дома":

  makeupdate --list /path

Создаёт в текущем каталоге файл $curdate.list, который можно относить "на работу". "На работе":

  makeupdate дата /path

Ищет в текущем каталоге файл дата.list, создаёт текуший "снимок" $curdate.list и скрипт с обновлением update.sh

Далее makeupdate можно запускать только "на работе".

Created by raorn
Last modified 2 11:23
 

резка гранита , ASTERROID with CallWeaver v 1.3. Дешевые звонки