├── README.md ├── content ├── plitc_debian8_luks_lvm_boot_btrfs_nested_subvol.jpg └── plitc_debian8_luks_lvm_boot_btrfs_subvol.jpg └── subvolboot2.sh /README.md: -------------------------------------------------------------------------------- 1 | 2 | Background 3 | ========== 4 | * based on boot_btrfs_subvol (prototype 0.8) 5 | 6 | * create very simple and fast btrfs subvolume snapshot boot environments 7 | 8 | Benefits of Goal Setting 9 | ======================== 10 | * contrary to the linear rw snapshots under zfs (zfs clone), btrfs can create/delete nested snapshots (subvolume snapshots) 11 | 12 | WARNING 13 | ======= 14 | * dependents on the kernel version, btrfs-tools version, bugfixes and the use of serious functions such as balance, raid5, compression, etc. can delete the complex structures under some circumstances lead to data loss 15 | 16 | Dependencies 17 | ============ 18 | * Linux (Debian) 19 | * machine with btrfs 20 | * (create manually a /ROOT subvolume with "btrfs subvolume create /ROOT") 21 | 22 | * dialog 23 | 24 | Features 25 | ======== 26 | * create root subvolume snapshot and grub entry 27 | 28 | * create nested subvolume snapshot environments 29 | * current support: 2 layer = 1 (ROOT/subvolume) + 1 (ROOT/subvolume/SUBROOT/subvolume) 30 | 31 | Platform 32 | ======== 33 | * Linux (Debian 7/Wheezy) 34 | * ! it is strongly recommended to use kernel 3.16 from wheezy-backports ! 35 | 36 | * Linux (Debian 8/Jessie) 37 | * recommended 38 | 39 | * Linux (Debian 9/Stretch/Testing) 40 | * recommended 41 | 42 | Usage 43 | ===== 44 | ``` 45 | WARNING: subvolboot2 is highly experimental and its not ready for production. Do it at your own risk. 46 | Current Support: 2 layer (1 ROOT/subvolume + 1 ROOT/subvolume/SUBROOT/subvolume) 47 | 48 | # usage: ./subvolboot2.sh { create | delete | clean-up | create-nested } 49 | ``` 50 | 51 | Diagram 52 | ======= 53 | * boot_btrfs_subvol (prototype 0.8) 54 | ![plitc_debian8_luks_lvm_boot_btrfs_subvol](/content/plitc_debian8_luks_lvm_boot_btrfs_subvol.jpg) 55 | 56 | * boot_btrfs_nested_subvol (prototype > 0.8) 57 | ![plitc_debian8_luks_lvm_boot_btrfs_nested_subvol](/content/plitc_debian8_luks_lvm_boot_btrfs_nested_subvol.jpg) 58 | 59 | Screencast 60 | ========== 61 | * btrfs / luks / lvm setup 62 | 63 | [![plitc deb8 btrfs luks lvm setup](https://img.youtube.com/vi/uRvd0H_m7pY/0.jpg)](https://www.youtube.com/watch?v=uRvd0H_m7pY) 64 | 65 | Errata 66 | ====== 67 | * 14.02.2015 - !!! - can't delete SUBROOT subvolumes reasonable 68 | * 14.02.2015 - !!! - under certain circumstances can't parse all custom grub entries 69 | * 12.02.2015 - !!! - "delete" function for nested-subvolume works in parent dataset environments only 70 | * 12.02.2015 - need lvm (logical volume) name "-system" (FIXED) 71 | * 11.02.2015 - parsing error after minute swap (FIXED) 72 | 73 | -------------------------------------------------------------------------------- /content/plitc_debian8_luks_lvm_boot_btrfs_nested_subvol.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plitc/boot_btrfs_nested_subvol/398f1aa2036aacb1fb436794c7d9c7069a18f1e0/content/plitc_debian8_luks_lvm_boot_btrfs_nested_subvol.jpg -------------------------------------------------------------------------------- /content/plitc_debian8_luks_lvm_boot_btrfs_subvol.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plitc/boot_btrfs_nested_subvol/398f1aa2036aacb1fb436794c7d9c7069a18f1e0/content/plitc_debian8_luks_lvm_boot_btrfs_subvol.jpg -------------------------------------------------------------------------------- /subvolboot2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ### LICENSE // ### 4 | # 5 | # Copyright (c) 2015, Daniel Plominski (Plominski IT Consulting) 6 | # All rights reserved. 7 | # 8 | # Redistribution and use in source and binary forms, with or without modification, 9 | # are permitted provided that the following conditions are met: 10 | # 11 | # * Redistributions of source code must retain the above copyright notice, this 12 | # list of conditions and the following disclaimer. 13 | # 14 | # * Redistributions in binary form must reproduce the above copyright notice, this 15 | # list of conditions and the following disclaimer in the documentation and/or 16 | # other materials provided with the distribution. 17 | # 18 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 22 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | # 29 | ### // LICENSE ### 30 | 31 | ### ### ### PLITC // ### ### ### 32 | 33 | 34 | ### stage0 // ### 35 | DEBIAN=$(grep "ID" /etc/os-release | egrep -v "VERSION" | sed 's/ID=//g') 36 | DEBVERSION=$(grep "VERSION_ID" /etc/os-release | sed 's/VERSION_ID=//g' | sed 's/"//g') 37 | if [ -z "$DEBVERSION" ]; then 38 | DEBVERSION9=$(grep -c "stretch" /etc/os-release | sed 's/1/9/g') 39 | fi 40 | MYNAME=$(whoami) 41 | ### // stage0 ### 42 | 43 | case "$1" in 44 | 'create') 45 | ### stage1 // ### 46 | case $DEBIAN in 47 | debian) 48 | ### stage2 // ### 49 | 50 | date +%Y%m%d-%H%M > /tmp/boot_btrfs_nested_subvol_date.txt 51 | DATE=$(cat /tmp/boot_btrfs_nested_subvol_date.txt) 52 | DIALOG=$(/usr/bin/which dialog) 53 | 54 | ### // stage2 ### 55 | # 56 | ### stage3 // ### 57 | if [ "$MYNAME" = "root" ]; then 58 | : # dummy 59 | else 60 | echo "" # dummy 61 | echo "" # dummy 62 | echo "[Error] You must be root to run this script" 63 | exit 1 64 | fi 65 | if [ "$DEBVERSION" = "7" ]; then 66 | : # dummy 67 | else 68 | if [ "$DEBVERSION" = "8" ]; then 69 | : # dummy 70 | else 71 | if [ "$DEBVERSION" = "9" ]; then 72 | : # dummy 73 | else 74 | if [ "$DEBVERSION9" = "9" ]; then 75 | : # dummy 76 | else 77 | echo "" # dummy 78 | echo "" # dummy 79 | echo "[Error] You need Debian 7 (Wheezy) or 8 (Jessie) or 9 (Stretch) Version" 80 | exit 1 81 | fi 82 | fi 83 | fi 84 | fi 85 | if [ -z "$DIALOG" ]; then 86 | echo "<--- --- --->" 87 | echo "need dialog" 88 | echo "<--- --- --->" 89 | apt-get update 90 | apt-get install dialog 91 | echo "<--- --- --->" 92 | fi 93 | # 94 | ### stage4 // ### 95 | # 96 | ## check btrfs rootfilesystem 97 | BTRFSROOT=$(mount | grep "on / type" | awk '{print $5}') 98 | if [ "$BTRFSROOT" = "btrfs" ]; then 99 | : # dummy 100 | else 101 | echo "[Error] can't find btrfs rootfilesystem" 102 | exit 1 103 | fi 104 | ## check default subvolume 105 | BTRFSVOL1=$(btrfs subvolume list '/' | grep -c "level") 106 | if [ "$BTRFSVOL1" -ge "1" ]; then 107 | : # dummy 108 | else 109 | echo "[Error] won't create new subvolume snapshots inside other subvolume snapshots" 110 | exit 1 111 | fi 112 | ## check default subvolume 2 113 | BTRFSVOL2=$(btrfs subvolume show '/' | grep -c "root") 114 | if [ "$BTRFSVOL2" = "0" ]; then 115 | : # dummy 116 | else 117 | echo "[Error] won't create new subvolume snapshots inside other subvolume snapshots" 118 | exit 1 119 | fi 120 | ## check ROOT subvolume 121 | BTRFSSUBVOL=$(btrfs subvolume list '/ROOT' | grep -c "ROOT") 122 | if [ "$BTRFSSUBVOL" = "1" ]; then 123 | : # dummy 124 | else 125 | echo "create ROOT subvolume" 126 | btrfs subvolume create /ROOT 127 | fi 128 | # 129 | ### ### ### ### ### ### ### ### ### 130 | # 131 | ## create subvolume snapshot 132 | btrfs subvolume snapshot / /ROOT/system-"$DATE" 133 | if [ "$?" != "0" ]; then 134 | echo "" # dummy 135 | echo "[Error] subvolume snapshot exists!" 1>&2 136 | exit 1 137 | fi 138 | # 139 | # snapshot description 140 | SNAPDESC1="/tmp/boot_btrfs_nested_subvol_desc1.txt" 141 | SNAPDESC2="/tmp/boot_btrfs_nested_subvol_desc2.txt" 142 | /bin/echo "test" > "$SNAPDESC1" 143 | dialog --title "Snapshot Description" --backtitle "Snapshot Description" --inputbox "Enter a short snapshot description: (for example: test)" 8 60 "$(cat $SNAPDESC1)" 2>$SNAPDESC2 144 | snapdesc1=$? 145 | case $snapdesc1 in 146 | 0) 147 | SNAPDESC3=$(sed 's/#//g' "$SNAPDESC2" | sed 's/%//g' | sed 's/ //g') 148 | # 149 | ## modify subvol fstab 150 | sed -i '/\/ *btrfs/s/defaults/defaults,subvol=ROOT\/system-'$DATE'/' /ROOT/system-"$DATE"/etc/fstab 151 | # 152 | ## modify grub 153 | cp /etc/grub.d/40_custom /etc/grub.d/.40_custom_bk_pre_system-"$DATE" 154 | awk "/menuentry 'Debian GNU\/Linux'/,/}/" /boot/grub/grub.cfg > /etc/grub.d/.40_custom_mod1_system-"$DATE" 155 | # 156 | sed -i '/menuentry/s/Linux/Linux -- snapshot '$DATE' -- '$SNAPDESC3'/' /etc/grub.d/.40_custom_mod1_system-"$DATE" 157 | # 158 | sed -i '/vmlinuz/s/$/ rootflags=subvol=ROOT\/system-'$DATE'/' /etc/grub.d/.40_custom_mod1_system-"$DATE" 159 | sed -i '1i\### -- snapshot '$DATE'' /etc/grub.d/.40_custom_mod1_system-"$DATE" 160 | sed -i 's/quiet//g' /etc/grub.d/.40_custom_mod1_system-"$DATE" 161 | # 162 | ### (merge grub) 163 | cat /etc/grub.d/.40_custom_mod1_system-"$DATE" >> /etc/grub.d/40_custom 164 | cp -f /etc/grub.d/40_custom /ROOT/system-"$DATE"/etc/grub.d/40_custom 165 | # 166 | ### grub update 167 | echo "" # dummy 168 | sleep 2 169 | grub-mkconfig 170 | echo "" # dummy 171 | sleep 2 172 | update-grub 173 | if [ "$?" != "0" ]; then 174 | echo "" # dummy 175 | echo "[Error] something goes wrong let's restore the old configuration!" 1>&2 176 | cp -f /etc/grub.d/.40_custom_bk_pre_system-"$DATE" /etc/grub.d/40_custom 177 | echo "" # dummy 178 | sleep 2 179 | grub-mkconfig 180 | echo "" # dummy 181 | sleep 2 182 | update-grub 183 | exit 1 184 | fi 185 | # 186 | ;; 187 | 1) 188 | /bin/echo "" # dummy 189 | /bin/echo "" # dummy 190 | btrfs subvolume delete /ROOT/system-"$DATE" 191 | /bin/echo "" # dummy 192 | /bin/echo "[Error] abort." 193 | #/ /bin/echo "ERROR:" 194 | exit 0 195 | ;; 196 | 255) 197 | /bin/echo "" # dummy 198 | /bin/echo "" # dummy 199 | btrfs subvolume delete /ROOT/system-"$DATE" 200 | /bin/echo "" # dummy 201 | /bin/echo "[ESC] key pressed." 202 | exit 0 203 | ;; 204 | esac 205 | # 206 | # clean up 207 | rm -f /tmp/boot_btrfs_nested_subvol_desc* 208 | # 209 | ### ### ### ### ### ### ### ### ### 210 | # 211 | ### // stage4 ### 212 | # 213 | ### // stage3 ### 214 | # 215 | ### // stage2 ### 216 | ;; 217 | *) 218 | # error 1 219 | echo "" # dummy 220 | echo "" # dummy 221 | echo "[Error] Plattform = unknown" 222 | exit 1 223 | ;; 224 | esac 225 | # 226 | ### // stage1 ### 227 | ;; 228 | 'delete') 229 | ### stage1 // ### 230 | case $DEBIAN in 231 | debian) 232 | ### stage2 // ### 233 | 234 | DIALOG=$(/usr/bin/which dialog) 235 | 236 | ### // stage2 ### 237 | # 238 | ### stage3 // ### 239 | if [ "$MYNAME" = "root" ]; then 240 | : # dummy 241 | else 242 | echo "" # dummy 243 | echo "" # dummy 244 | echo "[Error] You must be root to run this script" 245 | exit 1 246 | fi 247 | if [ "$DEBVERSION" = "7" ]; then 248 | : # dummy 249 | else 250 | if [ "$DEBVERSION" = "8" ]; then 251 | : # dummy 252 | else 253 | if [ "$DEBVERSION" = "9" ]; then 254 | : # dummy 255 | else 256 | if [ "$DEBVERSION9" = "9" ]; then 257 | : # dummy 258 | else 259 | echo "" # dummy 260 | echo "" # dummy 261 | echo "[Error] You need Debian 7 (Wheezy) or 8 (Jessie) or 9 (Stretch) Version" 262 | exit 1 263 | fi 264 | fi 265 | fi 266 | fi 267 | if [ -z "$DIALOG" ]; then 268 | echo "" # dummy 269 | echo "need dialog" 270 | echo "<--- --- --->" 271 | apt-get update 272 | apt-get install dialog 273 | echo "<--- --- --->" 274 | fi 275 | # 276 | ### stage4 // ### 277 | # 278 | ## check btrfs rootfilesystem 279 | BTRFSROOT=$(mount | grep "on / type" | awk '{print $5}') 280 | if [ "$BTRFSROOT" = "btrfs" ]; then 281 | : # dummy 282 | else 283 | echo "[Error] can't find btrfs rootfilesystem" 284 | exit 1 285 | fi 286 | ## check default subvolume 287 | BTRFSVOL1=$(btrfs subvolume list '/' | grep -c "level") 288 | if [ "$BTRFSVOL1" -ge "1" ]; then 289 | : # dummy 290 | else 291 | echo "[Error] won't delete the current subvolume snapshot inside another one" 292 | exit 1 293 | fi 294 | ## check default subvolume 2 295 | BTRFSVOL2=$(btrfs subvolume show '/' | grep -c "root") 296 | if [ "$BTRFSVOL2" = "0" ]; then 297 | : # dummy 298 | else 299 | echo "[Error] won't delete the current subvolume snapshot inside another one" 300 | exit 1 301 | fi 302 | ## check ROOT subvolume 303 | BTRFSSUBVOL=$(btrfs subvolume list '/ROOT' | grep -c "ROOT") 304 | if [ "$BTRFSSUBVOL" = "1" ]; then 305 | : # dummy 306 | else 307 | echo "create ROOT subvolume" 308 | btrfs subvolume create /ROOT 309 | fi 310 | # 311 | ### ### ### ### ### ### ### ### ### 312 | 313 | LISTSNAPFILE1="/tmp/boot_btrfs_nested_subvol_del1.txt" 314 | LISTSNAPFILE2="/tmp/boot_btrfs_nested_subvol_del2.txt" 315 | LISTSNAPFILE3="/tmp/boot_btrfs_nested_subvol_del3.txt" 316 | 317 | btrfs subvolume list '/' | grep "ROOT/system-" | awk '{print $9}' > $LISTSNAPFILE1 318 | nl $LISTSNAPFILE1 | sed 's/ //g' > $LISTSNAPFILE2 319 | /bin/sed 's/$/ off/' $LISTSNAPFILE2 > $LISTSNAPFILE3 320 | 321 | LISTSNAPFILE5="/tmp/boot_btrfs_nested_subvol_del5.txt" 322 | dialog --radiolist "Choose one subvolume to delete:" 45 80 60 --file "$LISTSNAPFILE3" 2>$LISTSNAPFILE5 323 | snapdel1=$? 324 | case $snapdel1 in 325 | 0) 326 | LISTSNAPFILE5CHECK=$(cat /tmp/boot_btrfs_nested_subvol_del5.txt) 327 | if [ -z "$LISTSNAPFILE5CHECK" ]; then 328 | /bin/echo "" # dummy 329 | /bin/echo "" # dummy 330 | /bin/echo "[Error] nothing selected" 331 | exit 1 332 | fi 333 | LISTSNAPFILE6="/tmp/boot_btrfs_nested_subvol_del6.txt" 334 | awk 'NR==FNR {h[$1] = $2; next} {print $1,$2,h[$1]}' "$LISTSNAPFILE3" "$LISTSNAPFILE5" | awk '{print $2}' | sed 's/"//g' > "$LISTSNAPFILE6" 335 | ### ### ### 336 | # 337 | SNAPDEL=$(sed 's/ROOT//g' "$LISTSNAPFILE6" | sed 's/^.//') 338 | SNAPDELFULL=$(cat "$LISTSNAPFILE6") 339 | # 340 | # grub restore 341 | cp -f /etc/grub.d/.40_custom_bk_pre_"$SNAPDEL" /etc/grub.d/40_custom 342 | if [ "$?" != "0" ]; then 343 | echo "" # dummy 344 | btrfs subvolume delete /"$SNAPDELFULL" 345 | echo "" # dummy 346 | echo "[Error] backup config disappeared!" 1>&2 347 | exit 1 348 | fi 349 | # 350 | # grub update 351 | echo "" # dummy 352 | echo "" # dummy 353 | sleep 2 354 | grub-mkconfig 355 | echo "" # dummy 356 | sleep 2 357 | update-grub 358 | sleep 2 359 | # 360 | # subvolume snapshot delete 361 | echo "" # dummy 362 | btrfs subvolume delete /"$SNAPDELFULL" 363 | # 364 | # clean up 365 | rm -f /tmp/boot_btrfs_nested_subvol_del* 366 | ### ### ### 367 | ;; 368 | 1) 369 | /bin/echo "" # dummy 370 | /bin/echo "" # dummy 371 | #/ /bin/echo "ERROR:" 372 | exit 0 373 | ;; 374 | 255) 375 | /bin/echo "" # dummy 376 | /bin/echo "" # dummy 377 | /bin/echo "[ESC] key pressed. (or no subvolume snapshots for deleting are available)" 378 | exit 0 379 | ;; 380 | esac 381 | 382 | ### ### ### ### ### ### ### ### ### 383 | # 384 | ### // stage4 ### 385 | # 386 | ### // stage3 ### 387 | # 388 | ### // stage2 ### 389 | ;; 390 | *) 391 | # error 1 392 | echo "" # dummy 393 | echo "" # dummy 394 | echo "[Error] Plattform = unknown" 395 | exit 1 396 | ;; 397 | esac 398 | # 399 | ### // stage1 ### 400 | ;; 401 | 'clean-up') 402 | ### stage1 // ### 403 | case $DEBIAN in 404 | debian) 405 | ### stage2 // ### 406 | 407 | ### // stage2 ### 408 | # 409 | ### stage3 // ### 410 | if [ "$MYNAME" = "root" ]; then 411 | : # dummy 412 | else 413 | echo "" # dummy 414 | echo "" # dummy 415 | echo "[Error] You must be root to run this script" 416 | exit 1 417 | fi 418 | if [ "$DEBVERSION" = "7" ]; then 419 | : # dummy 420 | else 421 | if [ "$DEBVERSION" = "8" ]; then 422 | : # dummy 423 | else 424 | if [ "$DEBVERSION" = "9" ]; then 425 | : # dummy 426 | else 427 | if [ "$DEBVERSION9" = "9" ]; then 428 | : # dummy 429 | else 430 | echo "" # dummy 431 | echo "" # dummy 432 | echo "[Error] You need Debian 7 (Wheezy) or 8 (Jessie) or 9 (Stretch) Version" 433 | exit 1 434 | fi 435 | fi 436 | fi 437 | fi 438 | # 439 | ### stage4 // ### 440 | # 441 | ## check btrfs rootfilesystem 442 | BTRFSROOT=$(mount | grep "on / type" | awk '{print $5}') 443 | if [ "$BTRFSROOT" = "btrfs" ]; then 444 | : # dummy 445 | else 446 | echo "[Error] can't find btrfs rootfilesystem" 447 | exit 1 448 | fi 449 | ### ### ### ### ### ### ### ### ### 450 | ROOTSNAPEXIST=$(btrfs subvolume list '/' | grep "ROOT/system-" | awk '{print $9}' | sed 's/ROOT//g' | sed 's/^.//g' | sed 's/\/SUB//g' | sed 's/\// /g' | awk '{print $1}' | sort | uniq) 451 | SUBROOTSNAPEXIST=$(btrfs subvolume list '/' | grep "ROOT/system-" | awk '{print $9}' | sed 's/ROOT//g' | sed 's/^.//g' | sed 's/\/SUB//g' | sed 's/\// /g' | awk '{print $2}' | sed '/^\s*$/d' | sort | uniq) 452 | 453 | find /etc/grub.d/ -name ".40_custom_*" | egrep -v "$ROOTSNAPEXIST|$SUBROOTSNAPEXIST" | xargs -L1 rm -fv 454 | 455 | if [ -z "$ROOTSNAPEXIST" ]; then 456 | if [ -z "$SUBROOTSNAPEXIST" ]; then 457 | rm -fv /etc/grub.d/.40_custom_* 458 | fi 459 | fi 460 | 461 | ### ### ### ### ### ### ### ### ### 462 | # 463 | ### // stage4 ### 464 | # 465 | ### // stage3 ### 466 | # 467 | ### // stage2 ### 468 | ;; 469 | *) 470 | # error 1 471 | echo "" # dummy 472 | echo "" # dummy 473 | echo "[Error] Plattform = unknown" 474 | exit 1 475 | ;; 476 | esac 477 | # 478 | ### // stage1 ### 479 | ;; 480 | 'create-nested') 481 | ### stage1 // ### 482 | case $DEBIAN in 483 | debian) 484 | ### stage2 // ### 485 | 486 | date +%Y%m%d-%H%M > /tmp/boot_btrfs_nested_subvol_date.txt 487 | DATE=$(cat /tmp/boot_btrfs_nested_subvol_date.txt) 488 | DIALOG=$(/usr/bin/which dialog) 489 | 490 | ### // stage2 ### 491 | # 492 | ### stage3 // ### 493 | if [ "$MYNAME" = "root" ]; then 494 | : # dummy 495 | else 496 | echo "" # dummy 497 | echo "" # dummy 498 | echo "[Error] You must be root to run this script" 499 | exit 1 500 | fi 501 | if [ "$DEBVERSION" = "7" ]; then 502 | : # dummy 503 | else 504 | if [ "$DEBVERSION" = "8" ]; then 505 | : # dummy 506 | else 507 | if [ "$DEBVERSION" = "9" ]; then 508 | : # dummy 509 | else 510 | if [ "$DEBVERSION9" = "9" ]; then 511 | : # dummy 512 | else 513 | echo "" # dummy 514 | echo "" # dummy 515 | echo "[Error] You need Debian 7 (Wheezy) or 8 (Jessie) or 9 (Stretch) Version" 516 | exit 1 517 | fi 518 | fi 519 | fi 520 | fi 521 | if [ -z "$DIALOG" ]; then 522 | echo "<--- --- --->" 523 | echo "need dialog" 524 | echo "<--- --- --->" 525 | apt-get update 526 | apt-get install dialog 527 | echo "<--- --- --->" 528 | fi 529 | # 530 | ### stage4 // ### 531 | # 532 | ## check btrfs rootfilesystem 533 | BTRFSROOT=$(mount | grep "on / type" | awk '{print $5}') 534 | if [ "$BTRFSROOT" = "btrfs" ]; then 535 | : # dummy 536 | else 537 | echo "[Error] can't find btrfs rootfilesystem" 538 | exit 1 539 | fi 540 | ## check default subvolume 541 | BTRFSVOL1=$(btrfs subvolume list '/' | grep -c "level") 542 | if [ "$BTRFSVOL1" -ge "1" ]; then 543 | : # dummy 544 | else 545 | echo "[Error] won't create new subvolume snapshots on top of the ROOT subvolume, please use the 'create' command" 546 | exit 1 547 | fi 548 | ## check default subvolume 2 549 | BTRFSVOL2=$(btrfs subvolume show '/' | grep -c "root") 550 | if [ "$BTRFSVOL2" = "1" ]; then 551 | echo "[Error] won't create new subvolume snapshots on top of the ROOT subvolume, please use the 'create' command" 552 | exit 1 553 | else 554 | : # dummy 555 | fi 556 | ## check SUBROOT subvolume 557 | BTRFSSUBVOL=$(btrfs subvolume list '/SUBROOT' | grep -c "SUBROOT") 558 | if [ "$BTRFSSUBVOL" = "1" ]; then 559 | : # dummy 560 | else 561 | echo "create SUBROOT subvolume" 562 | btrfs subvolume create /SUBROOT 563 | fi 564 | # 565 | ### ### ### ### ### ### ### ### ### 566 | # 567 | ## create subvolume snapshot 568 | btrfs subvolume snapshot / /SUBROOT/system-"$DATE" 569 | if [ "$?" != "0" ]; then 570 | echo "" # dummy 571 | echo "[Error] subvolume snapshot exists!" 1>&2 572 | exit 1 573 | fi 574 | # 575 | CURRDEEP=$(btrfs subvolume show '/' | grep "Name" | awk '{print $2}') 576 | # 577 | # snapshot description 578 | SNAPDESC1="/tmp/boot_btrfs_nested_subvol_desc1.txt" 579 | SNAPDESC2="/tmp/boot_btrfs_nested_subvol_desc2.txt" 580 | /bin/echo "test" > "$SNAPDESC1" 581 | dialog --title "Snapshot Description" --backtitle "Snapshot Description" --inputbox "Enter a short snapshot description: (for example: test)" 8 60 "$(cat $SNAPDESC1)" 2>$SNAPDESC2 582 | snapdesc1=$? 583 | case $snapdesc1 in 584 | 0) 585 | SNAPDESC3=$(sed 's/#//g' "$SNAPDESC2" | sed 's/%//g' | sed 's/ //g') 586 | # 587 | ## modify subvol fstab 588 | sed -i '/\/ *btrfs/s/defaults,subvol=ROOT\/'$CURRDEEP'/defaults,subvol=ROOT\/'$CURRDEEP'\/SUBROOT\/system-'$DATE'/' /SUBROOT/system-"$DATE"/etc/fstab 589 | # 590 | ## modify grub 591 | cp /etc/grub.d/40_custom /etc/grub.d/.40_custom_bk_pre_subroot_system-"$DATE" 592 | awk "/menuentry 'Debian GNU\/Linux'/,/}/" /boot/grub/grub.cfg > /etc/grub.d/.40_custom_mod1_subroot_system-"$DATE" 593 | # 594 | sed -i '/menuentry/s/Linux/Linux -- snapshot '$CURRDEEP' SUBROOT '$DATE' -- '$SNAPDESC3'/' /etc/grub.d/.40_custom_mod1_subroot_system-"$DATE" 595 | # 596 | sed -i '/vmlinuz/s/$/ rootflags=subvol=ROOT\/'$CURRDEEP'\/SUBROOT\/system-'$DATE'/' /etc/grub.d/.40_custom_mod1_subroot_system-"$DATE" 597 | sed -i '1i\### -- snapshot '$DATE'' /etc/grub.d/.40_custom_mod1_subroot_system-"$DATE" 598 | sed -i 's/quiet//g' /etc/grub.d/.40_custom_mod1_subroot_system-"$DATE" 599 | # 600 | ### (merge grub) 601 | cat /etc/grub.d/.40_custom_mod1_subroot_system-"$DATE" >> /etc/grub.d/40_custom 602 | cp -f /etc/grub.d/40_custom /SUBROOT/system-"$DATE"/etc/grub.d/40_custom 603 | # 604 | ### grub update 605 | echo "" # dummy 606 | sleep 2 607 | grub-mkconfig 608 | echo "" # dummy 609 | sleep 2 610 | update-grub 611 | if [ "$?" != "0" ]; then 612 | echo "" # dummy 613 | echo "[Error] something goes wrong let's restore the old configuration!" 1>&2 614 | cp -f /etc/grub.d/.40_custom_bk_pre_subroot_system-"$DATE" cp /etc/grub.d/40_custom 615 | echo "" # dummy 616 | sleep 2 617 | grub-mkconfig 618 | echo "" # dummy 619 | sleep 2 620 | update-grub 621 | exit 1 622 | fi 623 | # 624 | ;; 625 | 1) 626 | /bin/echo "" # dummy 627 | /bin/echo "" # dummy 628 | btrfs subvolume delete /SUBROOT/system-"$DATE" 629 | /bin/echo "" # dummy 630 | /bin/echo "[Error] abort." 631 | #/ /bin/echo "ERROR:" 632 | exit 0 633 | ;; 634 | 255) 635 | /bin/echo "" # dummy 636 | /bin/echo "" # dummy 637 | btrfs subvolume delete /SUBROOT/system-"$DATE" 638 | /bin/echo "" # dummy 639 | /bin/echo "[ESC] key pressed." 640 | exit 0 641 | ;; 642 | esac 643 | # 644 | # clean up 645 | rm -f /tmp/boot_btrfs_nested_subvol_desc* 646 | # 647 | ### ### ### ### ### ### ### ### ### 648 | # 649 | ### // stage4 ### 650 | # 651 | ### // stage3 ### 652 | # 653 | ### // stage2 ### 654 | ;; 655 | *) 656 | # error 1 657 | echo "" # dummy 658 | echo "" # dummy 659 | echo "[Error] Plattform = unknown" 660 | exit 1 661 | ;; 662 | esac 663 | # 664 | ### // stage1 ### 665 | ;; 666 | *) 667 | echo "" 668 | echo "WARNING: subvolboot2 is highly experimental and its not ready for production. Do it at your own risk." 669 | echo "Current Support: 2 layer (1 ROOT/subvolume + 1 ROOT/subvolume/SUBROOT/subvolume)" 670 | echo "" 671 | echo "usage: $0 { create | delete | clean-up | create-nested }" 672 | ;; 673 | esac 674 | exit 0 675 | 676 | 677 | ### ### ### // PLITC ### ### ### 678 | # EOF 679 | --------------------------------------------------------------------------------