backup-script.sh 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. #!/usr/bin/env bash
  2. # Copyright © 2018 Anton Tsyganenko
  3. #
  4. # Permission is hereby granted, free of charge, to any person obtaining
  5. # a copy of this software and associated documentation files (the
  6. # "Software"), to deal in the Software without restriction, including
  7. # without limitation the rights to use, copy, modify, merge, publish,
  8. # distribute, sublicense, and/or sell copies of the Software, and to
  9. # permit persons to whom the Software is furnished to do so, subject to
  10. # the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be
  13. # included in all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  18. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  19. # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  20. # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  21. # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. # ВАЖНО: файлы в бэкапах не предназначены для изменения. Изменяя один
  23. # файл, вы изменяете этот файл во всех бэкапах, где он был таким-же. Это
  24. # же жесткие ссылки. Если хотите изменять -- создавайте копию
  25. # (где-нибудь подальше от бэкапов).
  26. # Скрипт-документация написан Антоном Цыганенко 2018-03-26, с
  27. # использованием идей из
  28. # https://earlruby.org/2013/05/creating-differential-backups-with-hard-links-and-rsync/
  29. # "LATEST_BACKUP" - имя файла, в котором хранится имя папки с последним
  30. # успешно созданным бэкапом. Если этот файл удалить, бэкап будет
  31. # создаваться чистый, без жестких ссылок.
  32. # Осбождение диска можно производить удалением папок со старыми бэкапами
  33. # вручную, при этом освободится столько места, сколько занимали inode и
  34. # файлы, отсутствующие в новых бэкапах. Имеет смысл удалять старые бэкапы
  35. # или такие бэкапы, файлы из которых отсутствуют в других. Если удаляется
  36. # последняя жесткая ссылка на файл, это место освобождается.
  37. # rsync по умолчанию определяет изменения по размеру и дате модификации.
  38. # Если они не изменились, файл может быть не добавлен в новый бэкап,
  39. # хотя такой вариант не слишком вероятен. Можно защититься, сравнивая
  40. # хеши (опция -c), но это может быть дольше.
  41. # коды возврата скрипта:
  42. # 1 -- Бэкап $NEW уже существует
  43. # 2 -- rsync вернул не 0 или 24
  44. # 0 -- иное (обычно успешно созданный бэкап)
  45. # Рекомендуется хранить копию этого файла с прописанными настройками в BACKUP_DIR
  46. ######################################################
  47. ### НАСТРОЙКИ ###
  48. # тут можно изменять как надо
  49. # кроме этого стоит обратить внимание на ключи rsync ниже,
  50. # например, чтобы исключить ненужное из бэкапов или не писать логи
  51. # определяем папку, куда складываем бэкапы
  52. BACKUP_DIR=/run/media/tsyg/f31eb047-4a69-497f-a09f-26a2029b248d/tsyg-pc_bkps
  53. # папка, которую нужно копировать
  54. # Если ставить / в конце, то содержимое будет прямо в папке бэкапов, иначе
  55. # внутри каждого бэкапа будет папка с названием как SOURCE
  56. # /bkps/2018-01-01/... vs /bkps/2018-01-01/tsyg/...
  57. SOURCE=/home/tsyg
  58. # устанавливаем название папки для нового бэкапа.
  59. # экранирование теперь вроде учтено.
  60. ## нормальные варианты:
  61. #NEW=`date --iso-8601` # 2018-03-27
  62. #NEW=`date --iso-8601=seconds` # 2018-03-27T21:05:54+03:00
  63. NEW=`date +%Y-%m-%d_%H-%M` # 2018-03-27_17-30
  64. #NEW=`date +%Y%m%d%H%M%S` # 20180327173032
  65. #NEW=`uuidgen` # d5baa846-f916-43da-9fb0-820e2e680c49
  66. ######################################################
  67. ### СОЗДАНИЕ БЭКАПА ###
  68. echo "Бэкапим $SOURCE в $BACKUP_DIR, бэкап: $NEW"
  69. # Проверяем, были ли бэкапы, в процессе создания которых произошли сбои rsync.
  70. # их можно переименовать, это будет быстрее, чем копировать жесткими ссылками.
  71. if [ -f "$BACKUP_DIR/BAD_BACKUP" ]; then
  72. BAD=$(cat $BACKUP_DIR/BAD_BACKUP)
  73. mv "$BACKUP_DIR/$BAD" "$BACKUP_DIR/$NEW"
  74. mv "$BACKUP_DIR/rsync-logs/$BAD.log" "$BACKUP_DIR/rsync-logs/$NEW.log"
  75. rm "$BACKUP_DIR/BAD_BACKUP"
  76. # если начатых бэкапов нет, проверяем, на основе какого можно сделать
  77. elif [ -f "$BACKUP_DIR/LATEST_BACKUP" ]; then
  78. LATEST=$(cat $BACKUP_DIR/LATEST_BACKUP)
  79. # надо проверить, что такого бэкапа еще нет, иначе они засрутся и
  80. # потом придется разгребать
  81. if [ $NEW != $LATEST ]; then
  82. # копируем поледний бэкап с сохранением всех атрибутов и
  83. # использованием жестких ссылок
  84. cp -al "$BACKUP_DIR/$LATEST" "$BACKUP_DIR/$NEW"
  85. else
  86. echo "Ошибка! Бэкап $NEW уже существует."
  87. exit 1
  88. fi
  89. fi
  90. # готовим папку для логов, на случай, если ее еще нет
  91. mkdir -p "$BACKUP_DIR/rsync-logs/"
  92. # создаем бэкап. Если rsync видит, что старый и новый файлы отличаются
  93. # -- создает копию не изменяя содержимое старого бэкапа, иначе -- не
  94. # трогает. Файлы, удаленные в бэкапируемой бапке, удаляются из бэкапа.
  95. rsync -a --delete --info=PROGRESS2 \
  96. --log-file="$BACKUP_DIR/rsync-logs/$NEW.log" \
  97. "$SOURCE" "$BACKUP_DIR/$NEW"
  98. # Ключи добавлять перед строчкой "$SOURCE" "$BACKUP_DIR/$NEW"
  99. # --exclude "BAD/trash_dir"\ # можно исключить ненужные папки
  100. # --exclude "*.zip"\ # и/или все файлы по шаблону
  101. # --delete-excluded\ # и удалять их из создаваемых бэкапов,
  102. # а иначе они останутся как были до исключения
  103. rsync_exit_code=$?
  104. # если бэкап создан успешно (или в момент его создания какие-то файлы
  105. # пропали -- код 24), прописываем его в файл LATEST_BACKUP
  106. if [ $rsync_exit_code -eq 0 ] || [ $rsync_exit_code -eq 24 ]; then
  107. echo $NEW > "$BACKUP_DIR/LATEST_BACKUP"
  108. else
  109. echo $NEW > "$BACKUP_DIR/BAD_BACKUP"
  110. echo "Ошибка: бэкап создан некорректно и будет перезаписан при следующем запуске"
  111. echo "Если вы хотите его оставить, удалите файл BAD_BACKUP"
  112. exit 2
  113. fi
  114. # Создание заготовки для следующего бэкапа, можно отключить флагом --fast
  115. if [[ $* != *--fast* ]]
  116. then
  117. echo "Бэкап создан. Создаем основу для следующего."
  118. cp -al "$BACKUP_DIR/$NEW" "$BACKUP_DIR/COPY"
  119. echo "COPY" > "$BACKUP_DIR/BAD_BACKUP"
  120. fi