如何仅使用终端为 BIOS 创建具有持久性的实时 Ubuntu USB 驱动器?

Ell*_*iew 3 live-usb scripts persistence

我希望能够从实时 Ubuntu USB 记忆棒启动,然后在该 USB 记忆棒上永久使用 rsync 脚本,将我的主 Debian 系统的增量快照(备份)制作到第二个硬盘驱动器。

有人会认为制作一个持久的实时 Ubuntu USB 记忆棒会如此容易,但大多数实时 USB 制造商不允许持久性,而那些允许的,没有奏效。这包括 UNetBootin,即使在我本地编译和调试丢失的依赖项之后也是如此。所以我想要一个简单的终端解决方案,我可以在必要时理解和调试。

来自iso的简单dd,然后添加casper-rw文件方法存在分区工具被非标准efi分区映像混淆的问题。(参考

一些解决方案,如 UNetBootin 接近工作,但是当我尝试执行 sudo -s 以获取 root shell 时,它们会崩溃和转储,并破坏我的实时 USB 映像。

Ell*_*iew 5

大多数解决方案(如下)来自这篇很棒的文章,它接近于工作,但不完全是,因为它需要在一些地方进行一些更新。但我建议你看看它,因为它在解释步骤方面更完整。

这是我的基于 BIOS 的笔记本电脑。我猜这可能不适用于 EUFI 引导机器。

提示:

  • 不要像上面那篇文章建议的那样制作 grub 配置文件,而是像我下面展示的那样。

  • 一旦你最终让它在下面工作,你会发现随着时间的推移文件系统会意外地变满。我终于发现这是因为 Ubuntu 正在默默地做apt-get update,这将填满您的所有文件空间,然后您将收到一条警告消息。(我花了几年时间才弄清楚发生了什么。)

最初的修复是apt-get clean转储 apt 缓存,但这并不能真正解决根本问题。然后我尝试简单地禁用 Wi-Fi,这样它就无法进行自动更新。这对我很有用!现在我的手杖可以使用很长时间没有问题。


步骤仔细测试工作:

1.在此处下载Ubuntu 16.04 ISO 映像。

2.设置一些变量使用如下:

iso=/path/to/isoimage #e.g. iso=~/Downloads/ubuntu-16.04-desktop-amd64.iso

s=/mnt/isoimage   #Source mount point for ISO files (via loop file system)
t=/media/USBRoot  #Target mount point for USB files in partition #1
Run Code Online (Sandbox Code Playgroud)

!! 接下来,在下一步中要非常小心地正确指向 U 盘,而不是您的硬盘驱动器,因为您可能会不小心覆盖您的硬盘。(提示:查找并确认使用lsblk等)

dev=/dev/sd?  #set the "?" to your USB drive letter, e.g. /dev/sdb
Run Code Online (Sandbox Code Playgroud)

3. 插件和可选的擦除 如果分区失败,建议使用擦除。(在我将 iso 映像添加到 USB 设备之前,我必须先将其归零,然后才能使 fdisk 再次正常工作。)。

sudo dd if=/dev/zero of=$dev  #bs=2048 is optional and doesn't seem to matter
Run Code Online (Sandbox Code Playgroud)

完成后你会收到这样的消息:

dd: writing to ‘/dev/sdb’: No space left on device
30326785+0 records in
30326784+0 records out
15527313408 bytes (16 GB) copied, 4099.2 s, 3.8 MB/s
Run Code Online (Sandbox Code Playgroud)

擦除步骤是因为我发现有时快速格式化是行不通的。我不确定,但我怀疑分区映射的第二个副本或类似的东西正在被找到并且混淆了分区软件。因此,在我们开始之前将全零写入 USB 记忆棒似乎可以确保您重新开始。但是,是的,我知道,需要很长时间才能完成。

4. 做分区。使用分区工具在U盘上放一张msdos类型的分区图,如下分区为两个分区:

分区 1) VFAT32 分区,用于内核、ramdisk、grub 和通过 casper-rw 文件的持久性。为此,请使用所有剩余空间。

分区 2) linux iso 映像的可引导分区。使其大小约为 2G(因为这是 .iso 文件的大小)。

#2分区的大小需要大约2g,所以从驱动器的大小中减去这个,然后除以512得到#1分区的大小(以扇区为单位)。在我的情况下,这是 16gb - 2gb = 14gb / 512 = 大约 27343750 个扇区。

提示:如果设备已挂载,请立即卸载,否则在完成 fdisk 后会出现错误。不要使用图形卸载按钮,因为它似乎使设备无法找到(直到拔出 USB 驱动器然后重新插入),而是使用终端命令,如下所示:

? 问:我不知道为什么这些分区不能交换,以引导分区作为第一个分区。但是对于它的价值,我尝试过,但无法使其正常工作。

sudo umount ${dev}1
sudo umount ${dev}2
Run Code Online (Sandbox Code Playgroud)

方法如下:您可以使用 fdisk、parted、gparted 或 cfdisk,但我喜欢 fdisk。

sudo fdisk $dev
o                             [create partition map], and then

n (p) (1) (2048) 27343750     [new partition #1] 
t c                           [change partition type to type c, or W95 FAT32], and

n (p) (2) (default) (default) [new partition #2]
t 2 83                        [type 83 or linux], then
a (2)                         [set [toggle] the bootable flag], and

p                             [check new table], and finally 
Run Code Online (Sandbox Code Playgroud)

它应该是这样的:

Disk /dev/sdb: 14.5 GiB, 15527313408 bytes, 30326784 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xa42995f9

Device     Boot   Start      End  Sectors  Size Id Type
/dev/sdb1           2048 27343750 27341703   13G  c W95 FAT32 (LBA)
/dev/sdb2  *    27344896 30326783  2981888  1.4G 83 Linux
Run Code Online (Sandbox Code Playgroud)

然后这样做:

w                         [write the partition table to the usb drive]
Run Code Online (Sandbox Code Playgroud)

你应该得到这样的回应:

The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
Run Code Online (Sandbox Code Playgroud)

或者如果你忘记先卸载它,那么你会得到这个:

The partition table has been altered.
Calling ioctl() to re-read partition table.
Re-reading the partition table failed.: Device or resource busy

The kernel still uses the old table. The new table will be used at the next reboot or after you run partprobe(8) or kpartx(8).
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您只需返回,如上所述卸载它,然后再次运行 fdisk 并且只点击w,您就完成了。

5. 将iso镜像写入第二个分区。 我为是否在这里包含块大小参数而苦苦挣扎(例如 bs=2048),最后它似乎无关紧要或影响很小。另请注意,此分区不需要格式化,因为 ISO 在直接复制到该分区时会对其进行有效格式化。

sudo dd if=$iso of=${dev}2
Run Code Online (Sandbox Code Playgroud)

6. 格式化第一个分区。 请注意,他使用 VFAT32(即 FAT32 的长文件名版本)对其进行格式化。我猜这是为了便于在任何机器上读取该分区(即便携性)。[我计划看看 ext3 是否也可以工作,并将在稍后使用该测试进行更新]。

sudo mkfs.vfat -F 32 -c ${dev}1   # for vFAT32 file system
Run Code Online (Sandbox Code Playgroud)

7. 挂载分区 #1以便能够将文件安装到其中。

sudo mkdir -p      $t
sudo mount ${dev}1 $t
Run Code Online (Sandbox Code Playgroud)

8. 将 grub 安装到 U 盘的第一个扇区和分区 #1 的根目录中。

sudo grub-install --no-floppy --root-directory=$t $dev
Run Code Online (Sandbox Code Playgroud)

9. 复制内核和ram 磁盘文件。 (注意,这是从文章中修订的。内核现在是 *.efi 版本,(但它仍然只是一个内核),并且 initrd(包含所有包的 ram 磁盘)现在用 lz 而不是 gz 压缩)。首先,我们挂载映像文件(作为循环设备),我们将从以下位置获取这两个文件:

sudo mkdir -p           $s
sudo mount -o loop $iso $s
sudo cp                 $s/casper/{vmlinuz.efi,initrd.lz} $t/boot/
Run Code Online (Sandbox Code Playgroud)

10. 创建一个文件来保存持久文件系统。如果需要,调整大小。这被设置为 1024x1mb=1gb。请注意,在 casper-rw 文件中,它是一个 ext3 文件系统。casper-rw 这个名字很神奇,所以不要改变它。

sudo dd if=/dev/zero of=$t/casper-rw bs=1M count=1024  
sudo mkfs.ext3 -F       $t/casper-rw     #takes a long time
Run Code Online (Sandbox Code Playgroud)

11. 创建一个简单的 grub 配置文件。一定要给它一个(可能是更新的?) cfg 而不是 conf 文件扩展名,以便 grub 可以找到它(ref)。使用您喜欢的编辑器,或使用:

sudo nano $t/boot/grub/grub.cfg
Run Code Online (Sandbox Code Playgroud)

12. 粘贴以下 grub 命令。

*注意:如有必要,您可以使用 echo 并阅读此处进行更多调试。此外,“ro”、“splash”和“quiet”是可选的(但建议的)内核选项,其行为大多不言自明。如有必要,请参阅这篇关于如何使用 GRUB> 提示的非常有用的帖子。我猜他有一个.conf 文件,因为这可能是针对 GRUB 1.0 而不是 GRUB 2.0,这也可能解释了他没有工作的命令。另请注意,根是分区 1(即 msdos1)。

echo LOADING USB DRIVE
echo 
echo To continue press any key
echo To abort press ^-alt-delete
echo
read
echo Proceeding...

set default=0
set timeout=10
set title="Ubuntu (Live)"
set root=(hd0,msdos1)

linux /boot/vmlinuz.efi boot=casper file=/preseed/ubuntu.seed persistent ro splash quiet
echo vmlinuz.efi loaded

initrd /boot/initrd.lz
echo initrd.lz loaded
echo
echo Grub done. Booting...
boot
Run Code Online (Sandbox Code Playgroud)

13.同步(推荐)和清理(可选):

sync

sudo umount $s;  sudo rmdir  $s
sudo umount $t;  sudo rmdir  $t
Run Code Online (Sandbox Code Playgroud)

14. 备份您的新 USB 驱动器。

dd if=$dev of=/your/backup/location #需要很长时间

要稍后恢复它,请使用相反的方法:

dd if=/your/backup/location of=$dev #需要很长时间

15. 重新启动并按下一个键来启动 Ubuntu U 盘。

16. 将您的备份脚本添加到其中。这是我处理两台笔记本电脑的增量脚本。首先仔细检查您的系统并根据需要进行调整。将其命名为 mybackup并将myrestore硬链接到它 ( ln mybackup myrestore)。使用 设置执行权限chmod u+x my{backup,restore}。运行它./mybackup

#!/bin/bash

#Usage:
#
# mybackup                               - show list of current backups
# myrestore                              - ''
#
# mybackup  <machine> <BackupFolderName> - machine: love2d or sharon-pc
# myrestore <machine> <BackupFolderName> - by convention name is 'nn-descriptiveName' (so it sorts by date)


#################################################################
#################################################################

### PARTITIONS ######################
#Partition labels (also used for mount point folder names):
#  Note: use labels rather than UUID as they might be more controllable.
BackupDrive='Linux backup'              # USB backup drive (I removed space from 'name' & it removed it from 'label')
 BackupBase="$BackupDrive/Backups"      # Backup base folder directory & name
     SubDir="files"


### PARTITIONS LABEL HELP:
#lsblk -o +label        gives  (note older method was blkid, but this suggests we use lsblk):
#NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT                              LABEL
#sda      8:0    0 465.8G  0 disk
#??sda1   8:1    0   199M  0 part                                         SYSTEM
#??sda2   8:2    0 288.1G  0 part
#??sda3   8:3    0     1K  0 part
#??sda4   8:4    0  29.3G  0 part                                         Shared
#??sda5   8:5    0  23.3G  0 part                                         d8root
#??sda6   8:6    0 119.5G  0 part                                         d8home
#??sda7   8:7    0   5.4G  0 part [SWAP]

#sdc      8:32   0   3.7T  0 disk
#??sdc1   8:33   0   128M  0 part
#??sdc2   8:34   0   2.7T  0 part /media/ubuntu/Seagate Backup Plus Drive Seagate Backup Plus Drive
#??sdc3   8:35   0 976.6G  0 part                                         Linux backup



### MOUNTING 1of2 ######################
 sudo umount "/mnt/$BackupDrive">& /dev/null    # --- cleanup from prior failed attempt:
 sudo mkdir  "/mnt/$BackupDrive">& /dev/null; sudo mount -L "$BackupDrive"      "/mnt/$BackupDrive" -o defaults,suid >& /dev/null #Allow to set user owner of files




########################################################################
### FUNCTIONS #################################################################

####################
function usage          { echo; echo "Usage: ${0##*/} [machine name: Love2d|Sharon-pc] [BackupFolderName]";echo;}

####################

####################
#If parameter just show dirs for that machine, else show for both
function myls {
 echo -n "'$1' existing backups:"
 if [ -d "$2" ]; then echo; ls -lFgG "$2" |grep -v ^total |grep ' [0-9][0-9]-' |sed 's/..................//'; else echo ' (none)'; fi;
}

##################
function currentbackups {
 if [ "$1" ]; then
        myls "$1"               "/mnt/$BackupBase/$1/$SubDir"
 else
        myls 'Love2d'           "/mnt/$BackupBase/Love2d/$SubDir"
        echo
        myls 'Sharon-pc'        "/mnt/$BackupBase/Sharon-pc/$SubDir"
        echo
 fi
}

###################
function badmachine     { echo "Machine type '$1' is invalid.";}

###################
function cleanup        {
 # echo "--- cleaning up --------------------------------------"
 sudo umount "/mnt/$BackupDrive"
}

########################################################################
########################################################################


### CHECK INPUTS #######################################################
#Check if backup name paramter exists:
if [ $# = 0 ]; then usage;                                                                                                              cleanup; exit;     fi

if [ $# = 1 ]; then if [ "$1" != "Love2d" -a "$1" != "Sharon-pc" ]; then badmachine "$1"; usage; else usage; currentbackups "$1"; fi;                       cleanup; exit;     fi

if [ $# = 2 ]; then if [ "$1" != "Love2d" -a "$1" != "Sharon-pc" ]; then badmachine "$1"; usage;                                         cleanup; exit; fi; fi


### MOUNTING 2of2 ######################
if [ "$1" = 'Love2d' ]; then
    MyHome='d8home'             # Love2 Debian /home      partition name
    MyRoot='d8root'             # Love2 Debian /   (root) partition name
  MyShared='Shared'             # Love2 Debian Shared     partition name

 sudo umount "/mnt/$MyRoot"     >& /dev/null    # --- cleanup from prior failed attempt:
 sudo umount "/mnt/$MyHome"     >& /dev/null    #
 sudo umount "/mnt/$MyShared"   >& /dev/null    #

 sudo mkdir  "/mnt/$MyRoot"     >& /dev/null; sudo mount -L "$MyRoot"           "/mnt/$MyRoot"                          >& /dev/null
 sudo mkdir  "/mnt/$MyHome"     >& /dev/null; sudo mount -L "$MyHome"           "/mnt/$MyHome"                          >& /dev/null
 sudo mkdir  "/mnt/$MyShared"   >& /dev/null; sudo mount -L "$MyShared"         "/mnt/$MyShared"                        >& /dev/null

else
#    MyHome='uhome'             # Love2 Ubuntu /home      partition name
#    MyRoot='uroot'             # Love2 Ubuntu /   (root) partition name

    MyHome='a41eaa3e-bd31-4ebc-86d4-cf8ed5f3e779'               # Love2 Ubuntu /home      partition name
    MyRoot='f3b7424c-0144-42a6-8488-62fbee94d245'               # Love2 Ubuntu /   (root) partition name


 sudo umount "/mnt/$MyRoot"     >& /dev/null    # --- cleanup from prior failed attempt:
 sudo umount "/mnt/$MyHome"     >& /dev/null    #

#sudo mkdir  "/mnt/$MyRoot"     >& /dev/null; sudo mount -L "$MyRoot"           "/mnt/$MyRoot"                          >& /dev/null
#sudo mkdir  "/mnt/$MyHome"     >& /dev/null; sudo mount -L "$MyHome"           "/mnt/$MyHome"                          >& /dev/null

 sudo mkdir  "/mnt/$MyRoot"     >& /dev/null; sudo mount -U "$MyRoot"           "/mnt/$MyRoot"                          >& /dev/null
 sudo mkdir  "/mnt/$MyHome"     >& /dev/null; sudo mount -U "$MyHome"           "/mnt/$MyHome"                          >& /dev/null
fi


#=================================================================
BackupDir="$BackupBase/$1/$SubDir/$2"   # /dir/BackupFolderName


#rSync stuff:
MyRsync="sudo rsync -aAXv --delete"
RootExclude=" --exclude={\"/dev/*\",\"/lost+found\",\"/media/*\",\"/mnt/*\",\"/proc/*\",\"/run/*\",\"/sys/*\",\"/tmp/*\"}"
HomeExclude=" --exclude='*cache*'"      #this does not work

if [ "${0##*/}" = "mybackup" ]; then
echo backing up...
        sudo mkdir -p "/mnt/$BackupDir/root"    # Making directories to save backup to
        sudo mkdir -p "/mnt/$BackupDir/home"

        echo "--- Backing up:  / -----------------------------------"
        $MyRsync $RootExclude   "/mnt/$MyRoot/"                 "/mnt/$BackupDir/root/"
        echo "--- Backing up:  /home -------------------------------"

        $MyRsync $HomeExclude   "/mnt/$MyHome/"                 "/mnt/$BackupDir/home/"

   if [ "$MyShared" ]; then             #no shared partion on Sharon's machine
        sudo mkdir -p "/mnt/$BackupDir/shared"
        echo "--- Backing up:  Shared ------------------------------"
        $MyRsync                "/mnt/$MyShared/"               "/mnt/$BackupDir/shared/"
   fi

else

        # Confirm
        read -p "YOU ARE ABOUT TO OVERWRITE YOUR PARTITIONS - CONFIRM (y/N)?" -n 1 -r; echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then echo "Aborting.";exit; fi
        echo;
        read -p "DANGER!  Really overwrite your hard disk partitions? (y/N)?" -n 1 -r; echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then echo "Aborting.";exit; fi

        echo "--- Restoring:   / -----------------------------------"
        $MyRsync                "/mnt/$BackupDir/root/"         "/mnt/$MyRoot"
        echo "--- Restoring:   /home -------------------------------"
        $MyRsync                "/mnt/$BackupDir/home/"         "/mnt/$MyHome"

   if [ "$MyShared" ]; then             #no shared partion on Sharon's machine
        echo "--- Restoring:   Shared ------------------------------"
        $MyRsync                "/mnt/$BackupDir/shared/"       "/mnt/$MyShared"
   fi

fi

cleanup
 sudo umount "/mnt/$MyRoot"     ;sudo rmdir "/mnt/$MyRoot"
 sudo umount "/mnt/$MyHome"     ;sudo rmdir "/mnt/$MyHome"

if [ "$MyShared" ]; then                #no shared partion on Sharon's machine
 sudo umount "/mnt/$MyShared"   ;sudo rmdir "/mnt/$MyShared"
fi

 echo "=== DONE. ============================================"

exit 0
Run Code Online (Sandbox Code Playgroud)