#!/usr/bin/lua -- Created by jiaqiang.ye@lnxall.com -- 2023/12/14 -- Firmware installation for CentOS7 local bit32 = require "bit32" local posix = require "posix" local invoker = require "invoker" local cfmt = string.format local G_BLKDEV = nil local function logmsg(msg) local kfd = posix.open("/dev/kmsg", bit32.bor(posix.O_WRONLY, posix.O_CLOEXEC)) if type(kfd) ~= "number" or kfd < 0 then io.stderr:write("Error, failed to open kmsg.\n") io.stderr:flush() return false end local mlen = string.len(msg) if mlen ~= posix.write(kfd, msg) then io.stdout:write("Error, kmsg write has failed.\n") io.stdout:write(msg); io.stdout:flush() end posix.close(kfd); kfd = -1 return true end local diskpart = function (pno) return cfmt("%s%d", G_BLKDEV, pno) end local function detect_harddisk(prefix) local okay, dfout = invoker.invoke(invoker.OUTPUT, "df", "-h") if okay ~= 0 or type(dfout) ~= "string" then logmsg("Error, `df -h has no output.\n") return false end local hiter = { "a", "b", "c", "d", "e", "f" } for _, hi in ipairs(hiter) do local disk = prefix .. hi local dst = posix.stat(disk) if type(dst) == "table" and not string.find(dfout, disk, 1, true) then G_BLKDEV = disk logmsg(cfmt("Will Install to harddisk: %s\n", disk)) return true end end local disk = '/dev/nvme0n1' local dst = posix.stat(disk) if type(dst) == "table" and not string.find(dfout, disk, 1, true) then G_BLKDEV = disk logmsg(cfmt("Will Install to harddisk: %s\n", disk)) diskpart = function (pno) return cfmt("%sp%d", G_BLKDEV, pno) end return true end return false end local function write_centos7(img) local ist = posix.stat(img) if type(ist) ~= "table" then logmsg(cfmt("Error, CentOS-7 disk image not found: %s\n", img)) return false end io.stdout:write(cfmt("Unpacking CentOS-7 image '%s' to '%s'\n", img, G_BLKDEV)) io.stdout:flush() local okay, output = invoker.invoke(invoker.OUTPUT, "/bin/sh", "-c", cfmt("xzcat -T 4 '%s' | dd of=%s bs=256k conv=fsync,notrunc", img, G_BLKDEV)) if not okay or okay ~= 0 then if type(okay) ~= "number" then okay = -1 end if type(output) ~= "string" then output = "unknown error" end logmsg(cfmt("Error, failed to unpack CentOS-7 image: %d => %s\n", okay, output)) return false end posix.sync() logmsg("\nCentOS-7 Image written successfully!\n") return true end local function remove_partition(which) local blkpart = diskpart(which) local okay, fout = invoker.invoke(invoker.OUTPUT, "fdisk", "-l", G_BLKDEV) if okay == 0 and type(fout) == "string" and not string.find(fout, blkpart, 1, true) then logmsg(cfmt("\nINFO: partition not found: %s\n", blkpart)) return false end local fhdk = io.popen(cfmt("fdisk %s", G_BLKDEV), "wb") if not fhdk then logmsg("\nError, failed to remove partition.\n") return false end local cmds = { "d\n", cfmt("%d\n", which), "w\n", "q\n" } for _, cmd in ipairs(cmds) do fhdk:write(cmd); fhdk:flush() invoker.msleep(999) end fhdk:close() fhdk = nil logmsg(cfmt("\nPartition %d deleted successfully.\n", which)) return true end local function convert_mbr_gpt() local fh = io.popen(cfmt("gdisk %s", G_BLKDEV), "wb") if not fh then logmsg("\nFailed to call gdisk.\n") return false end invoker.msleep(999) local cmds = { "1\n", "n\n", "\n", "34\n", "2047\n", "ef02\n", "w\n", "Y\n", "q\n" } for _, cmd in ipairs(cmds) do fh:write(cmd); fh:flush() invoker.msleep(999) end fh:close() logmsg("\nMBR partition converted to GPT!\n") return true end local function expand_rootfs() logmsg(cfmt("\nRefreshing kernel awareness of partition '%s'...\n", G_BLKDEV)) local okay = invoker.invoke(0, "partx", G_BLKDEV) if okay ~= 0 then logmsg("\nWarning, Refreshing has failed.\n") end logmsg(cfmt("\nDeleting partition %s...\n", diskpart(5))) remove_partition(7); remove_partition(6); remove_partition(5) -- invoker.invoke(invoker.NOSTDIO, "parted", G_BLKDEV, "rm", "3") local blk3 = diskpart(3) logmsg(cfmt("\nExpanding partition '%s'...\n", blk3)) okay = invoker.invoke(0, "parted", "-s", "-a", "opt", G_BLKDEV, "resizepart 3 100%") if okay ~= 0 then logmsg(cfmt("Error, failed to expand partition '%s'.\n", blk3)) return false end logmsg(cfmt("\nExpand logical Volume '%s'...\n", blk3)) okay = invoker.invoke(0, "pvresize", blk3) if okay ~= 0 then logmsg("Error, failed to expand logical Volume.\n") return false end local rootp = "/dev/mapper/cs-root" logmsg("\nExpanding centos-root sub-partition...\n") okay = invoker.invoke(0, "lvextend", "-l", "+100%FREE", rootp) if okay ~= 0 then logmsg("Error, failed to expand centos-root partition.\n") return false end invoker.invoke(invoker.NOSTDIO, "partx", G_BLKDEV) invoker.waitsec(2) logmsg("\nChecking centos-root/ext4 file system...\n") invoker.invoke(invoker.OUTPUT + invoker.NOSTDIO, "e2fsck", "-p", "-f", rootp) logmsg("\nExpanding ext4 file system for CentOS-8...\n") okay = invoker.invoke(0, "resize2fs", rootp) if okay ~= 0 then logmsg("Error, failed to expand ext4!\n") return false end posix.sync() -- mount rootfs local mdir = '/tmp/mount_dir' invoker.invoke(0, "mkdir", "-p", mdir) invoker.invoke(0, "mount", "-orw", "-t", "ext4", rootp, mdir) if posix.chdir(mdir .. '/var/lib/docker/overlay2') then local eval, output = invoker.invoke(invoker.OUTPUT + invoker.TRIMEND, "find", "./", "-type", "f", "-name", "inittab", "-print") if eval == 0 and type(output) == "string" and #output > 0 then for path in string.gmatch(output, "[^\r\n]+") do local fdat = invoker.readfile(path) if type(fdat) == "string" and string.find(fdat, "ttyS0::askfirst", 1, true) then logmsg(cfmt("Modifying %s...\n", path)) invoker.invoke(0, "sed", "-e", "/ttyS0::askfirst/d", "-i", path) end end else logmsg("INFO: inittab not found, ignored") end posix.chdir('/') end -- copy addon files, ignore errors invoker.invoke(invoker.NOSTDIO, "/bin/sh", "-c", cfmt("cd /root/addon && cp -v -f -r * %s/", mdir)) posix.sync() logmsg("Done!\n") return true end local function mainfunc() posix.chdir('/') posix.signal(posix.SIGPIPE, posix.SIG_IGN) local nowt = invoker.uptime() if nowt < 45 then invoker.waitsec(45 - nowt) end invoker.invoke(invoker.NOSTDIO, "/bin/sh", "-c", "echo '8 3 1 7' > /proc/sys/kernel/printk") invoker.invoke(invoker.NOSTDIO, "/bin/sh", "-c", "echo 'on' > /proc/sys/kernel/printk_devkmsg") if not detect_harddisk("/dev/sd") then return false end if not convert_mbr_gpt() then return false end return expand_rootfs() end if mainfunc() then logmsg(" :'#######::'##:::'##::::'###::::'##:::'##:\n") logmsg(" '##.... ##: ##::'##::::'## ##:::. ##:'##::\n") logmsg(" ##:::: ##: ##:'##::::'##:. ##:::. ####:::\n") logmsg(" ##:::: ##: #####::::'##:::. ##:::. ##::::\n") logmsg(" ##:::: ##: ##. ##::: #########:::: ##::::\n") logmsg(" ##:::: ##: ##:. ##:: ##.... ##:::: ##::::\n") logmsg(" . #######:: ##::. ##: ##:::: ##:::: ##::::\n") logmsg(" :.......:::..::::..::..:::::..:::::..:::::\n") else logmsg(" '########:'########::'########:::'#######::'########::\n") logmsg(" ##.....:: ##.... ##: ##.... ##:'##.... ##: ##.... ##:\n") logmsg(" ##::::::: ##:::: ##: ##:::: ##: ##:::: ##: ##:::: ##:\n") logmsg(" ######::: ########:: ########:: ##:::: ##: ########::\n") logmsg(" ##...:::: ##.. ##::: ##.. ##::: ##:::: ##: ##.. ##:::\n") logmsg(" ##::::::: ##::. ##:: ##::. ##:: ##:::: ##: ##::. ##::\n") logmsg(" ########: ##:::. ##: ##:::. ##:. #######:: ##:::. ##:\n") logmsg(" ........::..:::::..::..:::::..:::.......:::..:::::..::\n") end posix.sync() while true do invoker.waitsec(60) end