230 lines
6.4 KiB
Ruby
Executable File
230 lines
6.4 KiB
Ruby
Executable File
#!/usr/bin/env ruby
|
|
|
|
require 'pathname'
|
|
$: << Pathname.new($0).expand_path.dirname+'lib'
|
|
require 'base'
|
|
require 'active_support/all'
|
|
|
|
Sector = Sectors = 512
|
|
|
|
class Armbian2LVM_XFS < Base
|
|
def initialize
|
|
super
|
|
chs = [?a..?z, ?A..?Z].map(&:to_a).flatten
|
|
@vgname = "armbian_#{5.times.map{chs[rand(chs.length)]}.join}"
|
|
d "Destination image «#{dest.image}» in use!", dest.kpartxed?
|
|
end
|
|
|
|
# read from input, write to output
|
|
# input|output can be:
|
|
# Pathname: opens file and use it as IO
|
|
# String: reads from/writes to like an IO (->StringIO)
|
|
# IO: use it directly
|
|
# obs|ibs|bs: blocksizes (if ibs|obs not given, bs will be used, else 512)
|
|
# from: set input-block-position to from
|
|
# skip: skip next X blocks from current position
|
|
# at: set output-block-position to to
|
|
# seek: seek to next X blocks from current position
|
|
def dd input, output, from: nil, skip: nil, at: nil, seek: nil, bs: nil, ibs: nil, obs: nil
|
|
case input
|
|
when Pathname
|
|
input.open 'r' do |f|
|
|
return __method__( f, output, pos: pos, seek: seek)
|
|
end
|
|
when String
|
|
StringIO.open input do |f|
|
|
return __method__( f, output, pos: pos, seek: seek)
|
|
end
|
|
when IO
|
|
|
|
case output
|
|
when Pathname
|
|
output.open 'w' do |f|
|
|
return __method__( input, f, pos: pos, seek: seek)
|
|
end
|
|
when String
|
|
StringIO.open output, 'w' do |f|
|
|
return __method__( input, f, pos: pos, seek: seek)
|
|
end
|
|
when IO
|
|
|
|
ibs ||= bs || 512
|
|
obs ||= bs || 512
|
|
input.pos = from*ibs if from
|
|
input.pos += skip*ibs if skip
|
|
output.pos = at*obs if at
|
|
output.pos += seek*obs if seek
|
|
output.write input.read( count ? count*ibs : nil)
|
|
|
|
end
|
|
|
|
else
|
|
raise ArgumentError, "input for dd must be a String, IO or Pathname"
|
|
end
|
|
end
|
|
|
|
def run
|
|
mkmppaths
|
|
|
|
d "Base image does not exist", base.image.exist?
|
|
base_parts = base.kpartx
|
|
d "two (root-)partition in base expected, got: #{base_parts.inspect}", 1 == base_parts.length
|
|
|
|
mount base_parts[0], base.root, -:oro
|
|
|
|
msg 'prepare image', dest.image
|
|
dest.image.open 'w' do |f|
|
|
f.truncate 0
|
|
f.pos = 0
|
|
f.write 0.chr*4.megabytes
|
|
f.pos = 1.5.gigabytes+128.megabytes+4.megabytes-1
|
|
f.putc 0.chr
|
|
end
|
|
# partitions for: /boot (128MiBi), LVM
|
|
sh.parted dest.image, '--',
|
|
*%w[mklabel msdos],
|
|
*%w[mkpart primary ext2 4MB 132MB],
|
|
*%w[mkpart primary ext2 132MB -4MB],
|
|
*%w[set 1 boot on],
|
|
*%w[set 2 LVM on],
|
|
*%w[print]
|
|
|
|
ubootdir = base.root + 'usr' + 'lib' + 'linux-u-boot-dev-odroidxu4_5.34.171103_armhf'
|
|
if false
|
|
sh.bash -:ec, <<-EOF.gsub( /^\t{4}/, '').sub( /\n$/m, '')
|
|
echo "hallo welt"
|
|
BRANCH=dev
|
|
source ./build/config/sources/odroidxu4.conf
|
|
dd() {
|
|
echo dd "$*" >&2
|
|
command dd "$@"
|
|
}
|
|
write_uboot_platform #{ubootdir.to_s.shellescape} #{dest.image.to_s.shellescape}
|
|
EOF
|
|
else
|
|
msg 'install u-boot', dest.image, ubootdir
|
|
dest.image.open 'r+' do |f|
|
|
msg ' apply', ubootdir+'bl1.bin.hardkernel'
|
|
f.pos = 1*Sector
|
|
b = (ubootdir+'bl1.bin.hardkernel').read
|
|
f.write b
|
|
msg ' apply', ubootdir+'bl2.bin.hardkernel.720k_uboot'
|
|
f.pos = 31*Sectors
|
|
f.write (ubootdir+'bl2.bin.hardkernel.720k_uboot').read
|
|
msg ' apply', ubootdir+'u-boot-dtb.bin'
|
|
f.pos = 63*Sectors
|
|
f.write (ubootdir+'u-boot-dtb.bin').read
|
|
msg ' apply', ubootdir+'tzsw.bin.hardkernel'
|
|
f.pos = 1503*Sectors
|
|
f.write (ubootdir+'tzsw.bin.hardkernel').read
|
|
msg ' clear', 'u-boot env'
|
|
f.pos = 2015*Sectors
|
|
f.write 0.chr*32*Sectors
|
|
end
|
|
end
|
|
|
|
dest_parts = dest.kpartx
|
|
d "two partitions in destination expected", 2 == dest_parts.length
|
|
|
|
#root = MP.new self, dest_parts[1], dest.root
|
|
#home = MP.new self, nil, dest.root+'home'
|
|
#boot = MP.new self, dest_parts[0], dest.root+'boot'
|
|
|
|
vgpath = Pathname.new( '/dev') + vgname
|
|
root = MP.new self, vgpath + 'root', dest.root
|
|
#home = MP.new self, vgpath + 'home', dest.root+'home'
|
|
boot = MP.new self, dest_parts[0], dest.root+'boot'
|
|
#swap = MP.new self, vgpath + 'swap', 'none'
|
|
|
|
sh.pvcreate dest_parts[1]
|
|
sh.vgcreate vgname, dest_parts[1]
|
|
sh.lvcreate -:nroot, '-L1.5G', vgname
|
|
#sh.lvcreate -:nhome, '-L120M', vgname
|
|
#sh.lvcreate -:nswap, '-L10M', vgname
|
|
activate_vg vgname
|
|
sh.mkext4fs boot.dev
|
|
sh.mkxfs root.dev
|
|
#sh.mkxfs home.dev
|
|
#sh.mkswap swap.dev
|
|
|
|
root.mount
|
|
#home.mp.mkdir
|
|
#home.mount
|
|
boot.mp.mkdir
|
|
boot.mount
|
|
|
|
exclude = %w[boot/dtb-*
|
|
boot/uInitrd-* boot/vmlinuz-* boot/initrd.img-*
|
|
boot/config-* boot/System.map-*
|
|
etc/systemd/system/basic.target.wants/resize2fs.service
|
|
etc/systemd/system/sysinit.target.wants/log2ram.service
|
|
etc/rc?.d/*resize2fs
|
|
root/.not_logged_in_yet etc/profile.d/check_first_login.sh
|
|
].flat_map {|e| ['--exclude', e] } #"#{base.root}#{e}"] }
|
|
|
|
sh.rsync_all *exclude, "#{base.root}/", root.mp
|
|
|
|
msg 'create symlink', boot.mp+'boot', '->', '.'
|
|
(boot.mp+'boot').make_symlink '.'
|
|
manipulate_file boot.mp+'boot.ini' do |file, &push|
|
|
file.each_line do |l|
|
|
case l.chomp!
|
|
when /^ *setenv +rootdev +/
|
|
push.call "setenv rootdev \"UUID=#{root.uuid}\""
|
|
when /^ *setenv +rootfstype +/
|
|
push.call "setenv rootfstype \"#{root.fstype}\""
|
|
else
|
|
push.call l
|
|
end
|
|
end
|
|
end
|
|
|
|
manipulate_file root.mp+'etc'+'initramfs-tools'+'initramfs.conf' do |file, &push|
|
|
file.each_line do |l|
|
|
case l.chomp!
|
|
when /^COMPRESS=/
|
|
push.call 'COMPRESS=xz'
|
|
when /^# *COMPRESS=/
|
|
push.call l, 'COMPRESS=xz'
|
|
else
|
|
push.call l
|
|
end
|
|
end
|
|
end
|
|
|
|
manipulate_file root.mp+'etc'+'fstab' do |file, &push|
|
|
file.each_line do |l|
|
|
case l.chomp!
|
|
when /^ *#/
|
|
push.call l
|
|
when /^\s*(\S+)\s+\/\s+()/
|
|
push.call "UUID=#{root.uuid} / #{root.fstype} defaults,noatime,nodiratime,errors=remount-ro 0 1"
|
|
when /^\s*\/var\/swap\s+/
|
|
# skip
|
|
else
|
|
push.call l
|
|
end
|
|
end
|
|
#push.call "UUID=#{swap.uuid} none #{swap.fstype} sw 0 0"
|
|
push.call "UUID=#{boot.uuid} /boot #{boot.fstype} defaults 0 0"
|
|
#push.call "UUID=#{home.uuid} /home #{home.fstype} defaults,errors=remount-ro 0 0"
|
|
end
|
|
|
|
sh.tar -:C, root.mp, -:xf, 'files.tar' if File.exists? 'files.tar'
|
|
|
|
rescue ProgrammError
|
|
err $!
|
|
raise
|
|
ensure
|
|
STDERR.puts "="*80
|
|
umount_all ignore_exceptions: true
|
|
deactivate_all_vgs ignore_exceptions: true
|
|
capsulated_rescue { sh.sync }
|
|
capsulated_rescue { dest.departx }
|
|
capsulated_rescue { base.departx }
|
|
capsulated_rescue { sh.sync }
|
|
end
|
|
end
|
|
|
|
Armbian2LVM_XFS.new.run
|