Linux web-conference.aiou.edu.pk 5.4.0-204-generic #224-Ubuntu SMP Thu Dec 5 13:38:28 UTC 2024 x86_64
Apache/2.4.41 (Ubuntu)
: 172.16.50.247 | : 3.142.195.139
Cant Read [ /etc/named.conf ]
7.4.3-4ubuntu2.28
appadmin
www.github.com/MadExploits
Terminal
AUTO ROOT
Adminer
Backdoor Destroyer
Linux Exploit
Lock Shell
Lock File
Create User
CREATE RDP
PHP Mailer
BACKCONNECT
UNLOCK SHELL
HASH IDENTIFIER
CPANEL RESET
CREATE WP USER
BLACK DEFEND!
README
+ Create Folder
+ Create File
/
etc /
grub.d /
[ HOME SHELL ]
Name
Size
Permission
Action
00_header
10.38
KB
-rwxr-xr-x
05_debian_theme
6.11
KB
-rwxr-xr-x
10_linux
17.8
KB
-rwxr-xr-x
10_linux_zfs
41.37
KB
-rwxr-xr-x
20_linux_xen
12.79
KB
-rwxr-xr-x
30_os-prober
11.78
KB
-rwxr-xr-x
30_uefi-firmware
1.39
KB
-rwxr-xr-x
35_fwupd
700
B
-rwxr-xr-x
40_custom
214
B
-rwxr-xr-x
41_custom
216
B
-rwxr-xr-x
README
483
B
-rw-r--r--
Delete
Unzip
Zip
${this.title}
Close
Code Editor : 10_linux_zfs
#! /bin/sh set -e # grub-mkconfig helper script. # Copyright (C) 2019 Canonical Ltd. # # GRUB is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # GRUB is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GRUB. If not, see <http://www.gnu.org/licenses/>. prefix="/usr" datarootdir="/usr/share" ubuntu_recovery="1" quiet_boot="1" quick_boot="1" gfxpayload_dynamic="1" vt_handoff="1" . "${pkgdatadir}/grub-mkconfig_lib" export TEXTDOMAIN=grub export TEXTDOMAINDIR="${datarootdir}/locale" set -u ## Skip early if zfs utils isn't installed (instead of failing on first zpool list) if ! `which zfs >/dev/null 2>&1`; then exit 0 fi imported_pools="" MNTDIR="$(mktemp -d ${TMPDIR:-/tmp}/zfsmnt.XXXXXX)" ZFSTMP="$(mktemp -d ${TMPDIR:-/tmp}/zfstmp.XXXXXX)" machine="$(uname -m)" case "${machine}" in i?86) GENKERNEL_ARCH="x86" ;; mips|mips64) GENKERNEL_ARCH="mips" ;; mipsel|mips64el) GENKERNEL_ARCH="mipsel" ;; arm*) GENKERNEL_ARCH="arm" ;; *) GENKERNEL_ARCH="${machine}" ;; esac RC=0 on_exit() { # Restore initial zpool import state for pool in ${imported_pools}; do zpool export "${pool}" done mountpoint -q "${MNTDIR}" && umount "${MNTDIR}" || true rmdir "${MNTDIR}" rm -rf "${ZFSTMP}" exit "${RC}" } trap on_exit EXIT INT QUIT ABRT PIPE TERM # List ONLINE and DEGRADED pools import_pools() { # We have to ignore zpool import output, as potentially multiple / will be available, # and we need to autodetect all zpools this way with their real mountpoints. local initial_pools="$(zpool list | awk '{if (NR>1) print $1}')" local all_pools="" local imported_pools="" local err="" set +e err="$(zpool import -f -a -o cachefile=none -o readonly=on -N 2>&1)" # Only print stderr if the command returned an error # (it can echo "No zpool to import" with success, which we don't want) if [ $? -ne 0 ]; then echo "Some pools couldn't be imported and will be ignored:\n${err}" >&2 fi set -e all_pools="$(zpool list | awk '{if (NR>1) print $1}')" for pool in ${all_pools}; do if echo "${initial_pools}" | grep -wq "${pool}"; then continue fi imported_pools="${imported_pools} ${pool}" done echo "${imported_pools}" } # List all the dataset with a root mountpoint get_root_datasets() { local pools="$(zpool list | awk '{if (NR>1) print $1}')" for p in ${pools}; do local rel_pool_root=$(zpool get -H altroot ${p} | awk '{print $3}') if [ "${rel_pool_root}" = "-" ]; then rel_pool_root="/" fi zfs list -H -o name,canmount,mountpoint -t filesystem | grep -E '^'"${p}"'(\s|/[[:print:]]*\s)(on|noauto)\s'"${rel_pool_root}"'$' | awk '{print $1}' done } # find if given datasets can be mounted for directory and return its path (snapshot or real path) # $1 is our current dataset name # $2 directory path we look for (cannot contains /) # $3 is the temporary mount directory to use # $4 is the optional snapshot name # return path for directory (which can be a mountpoint) validate_system_dataset() { local dataset="$1" local directory="$2" local mntdir="$3" local snapshot_name="$4" local mount_path="${mntdir}/${directory}" if ! zfs list "${dataset}" >/dev/null 2>&1; then return fi if ! mount -o noatime,zfsutil -t zfs "${dataset}" "${mount_path}"; then grub_warn "Failed to find a valid directory '${directory}' for dataset '${dataset}@${snapshot_name}'. Ignoring" return fi local candidate_path="${mount_path}" if [ -n "${snapshot_name}" ]; then # WORKAROUND a bug https://github.com/zfsonlinux/zfs/issues/9958 # Reading the content of a snapshot fails if it is not the first mount # for a given dataset first_mntdir=$(awk '{if ($1 == "'${dataset}'") {print $2; exit;}}' /proc/mounts) if [ "${first_mntdir}" = "/" ]; then # prevents // on candidate_path first_mntdir="" fi candidate_path="${first_mntdir}/.zfs/snapshot/${snapshot_name}" fi if [ -n "$(ls ${candidate_path} 2>/dev/null)" ]; then echo "${candidate_path}" return else mountpoint -q "${mount_path}" && umount "${mount_path}" || true fi } # Detect system directory relevant to the other, trying to find the ones associated on the current dataset or snapshot/ # System directory should be at most a direct child dataset of main datasets (no recursivity) # We can fallback trying other zfs pools if no match has been found. # $1 is our current dataset name (which can have @snapshot name) # $2 directory path we look for (cannot contains /) # $3 restrict_to_same_pool (true|false) force looking for dataset with the same basename in the current dataset pool only # $4 is the temporary mount directory to use # $5 is the optional etc directory (if not $2 is not etc itself) # return path for directory (which can be a mountpoint) get_system_directory() { local dataset_path="$1" local directory="$2" local restrict_to_same_pool="$3" local mntdir="$4" local etc_dir="$5" if [ -z "${etc_dir}" ]; then etc_dir="${mntdir}/etc" fi local candidate_path="${mntdir}/${directory}" # 1. Look for /etc/fstab first (which will mount even on top of non empty $directory) local mounted_fstab_entry="false" if [ -f "${etc_dir}/fstab" ]; then mount_args=$(awk '/^[^#].*[ \t]\/'"${directory}"'[ \t]/ {print "-t", $3, $1}' "${etc_dir}/fstab") if [ -n "${mount_args}" ]; then mounted_fstab_entry="true" mount -o noatime ${mount_args} "${candidate_path}" || mounted_fstab_entry="false" fi fi # If directory isn't empty. Only count if coming from /etc/fstab. Will be # handled below otherwise as we are interested in potential snapshots. if [ "${mounted_fstab_entry}" = "true" -a -n "$(ls ${candidate_path} 2>/dev/null)" ]; then echo "${candidate_path}" return fi # 2. Handle zfs case, which can be a snapshots. local base_dataset_path="${dataset_path}" local snapshot_name="" # For snapshots we extract the parent dataset if echo "${dataset_path}" | grep -q '@'; then base_dataset_path=$(echo "${dataset_path}" | cut -d '@' -f1) snapshot_name=$(echo "${dataset_path}" | cut -d '@' -f2) fi base_dataset_name="${base_dataset_path##*/}" base_pool="$(echo "${base_dataset_path}" | cut -d'/' -f1)" # 2.a) Look for child dataset included in base dataset, which needs to hold same snapshot if any candidate_path=$(validate_system_dataset "${base_dataset_path}/${directory}" "${directory}" "${mntdir}" "${snapshot_name}") if [ -n "${candidate_path}" ]; then echo "${candidate_path}" return fi # 2.b) Look for current dataset (which is already mounted as /) candidate_path="${mntdir}/${directory}" if [ -n "${snapshot_name}" ]; then # WORKAROUND a bug https://github.com/zfsonlinux/zfs/issues/9958 # Reading the content of a snapshot fails if it is not the first mount # for a given dataset first_mntdir=$(awk '{if ($1 == "'${base_dataset_path}'") {print $2; exit;}}' /proc/mounts) if [ "${first_mntdir}" = "/" ]; then # prevents // on candidate_path first_mntdir="" fi candidate_path="${first_mntdir}/.zfs/snapshot/${snapshot_name}/${directory}" fi if [ -n "$(ls ${candidate_path} 2>/dev/null)" ]; then echo "${candidate_path}" return fi # 2.c) Look for every datasets in every pool which isn't the current dataset which holds: # - the same dataset name (last section) than our base_dataset_name # - mountpoint=directory # - canmount!=off all_same_base_dataset_name="$(zfs list -H -t filesystem -o name,canmount | awk '/^[^ ]+\/'"${base_dataset_name}"'[ \t](on|noauto)/ {print $1}') " # order by local pool datasets first current_pool_same_base_datasets="" other_pools_same_base_datasets="" root_pool=$(echo "${dataset_path%%/*}") for d in ${all_same_base_dataset_name}; do cur_dataset_pool=$(echo "${d%%/*}") if echo "${cur_dataset_pool}" | grep -wq "${root_pool}" 2>/dev/null ; then current_pool_same_base_datasets="${current_pool_same_base_datasets} ${d}" else other_pools_same_base_datasets="${other_pools_same_base_datasets} ${d}" fi done ordered_same_base_datasets="${current_pool_same_base_datasets} ${other_pools_same_base_datasets}" if [ "${restrict_to_same_pool}" = "true" ]; then ordered_same_base_datasets="${current_pool_same_base_datasets}" fi # now, loop over them for d in ${ordered_same_base_datasets}; do cur_dataset_pool=$(echo "${d%%/*}") rel_pool_root=$(zpool get -H altroot ${cur_dataset_pool} | awk '{print $3}') if [ "${rel_pool_root}" = "-" ]; then rel_pool_root="" fi # check mountpoint match candidate_dataset=$(zfs get -H mountpoint ${d} | grep -E "mountpoint\s${rel_pool_root}/${directory}\s" | awk '{print $1}') if [ -z "${candidate_dataset}" ]; then continue fi candidate_path=$(validate_system_dataset "${candidate_dataset}" "${directory}" "${mntdir}" "${snapshot_name}") if [ -n "${candidate_path}" ]; then echo "${candidate_path}" return fi done # 2.d) If we didn't find anything yet: check for persistent datasets corresponding to our mountpoint, with canmount=on without any snapshot associated: # Note: we go over previous datasets as well, but this is ok, as we didn't include them before. all_mountable_datasets="$(zfs list -t filesystem -o name,canmount | awk '/^[^ ]+[ \t]+on/ {print $1}')" # order by local pool datasets first current_pool_datasets="" other_pools_datasets="" root_pool=$(echo "${dataset_path%%/*}") for d in ${all_mountable_datasets}; do cur_dataset_pool=$(echo "${d%%/*}") if echo "${cur_dataset_pool}" | grep -wq "${root_pool}" 2>/dev/null ; then current_pool_datasets="${current_pool_datasets} ${d}" else other_pools_datasets="${other_pools_datasets} ${d}" fi done ordered_datasets="${current_pool_datasets} ${other_pools_datasets}" if [ "${restrict_to_same_pool}" = "true" ]; then ordered_datasets="${current_pool_datasets}" fi for d in ${ordered_datasets}; do cur_dataset_pool=$(echo "${d%%/*}") rel_pool_root=$(zpool get -H altroot ${cur_dataset_pool} | awk '{print $3}') if [ "${rel_pool_root}" = "-" ]; then rel_pool_root="" fi # check mountpoint match candidate_dataset=$(zfs get -H mountpoint ${d} | grep -E "mountpoint\s${rel_pool_root}/${directory}\s" | awk '{print $1}') if [ -z "${candidate_dataset}" ]; then continue fi candidate_path=$(validate_system_dataset "${d}" "${directory}" "${mntdir}" "") if [ -n "${candidate_path}" ]; then echo "${candidate_path}" return fi done grub_warn "Failed to find a valid directory '${directory}' for dataset '${dataset_path}'. Ignoring" return } # Try our default layout bpool as a prefered layout (fast path) # This is get_system_directory for boot optimized for our default installation layout # $1 is our current dataset name (which can have @snapshot name) # $2 is the temporary mount directory to use # return path for directory (which can be a mountpoint) if found try_default_layout_bpool() { local root_dataset_path="$1" local mntdir="$2" dataset_basename="${root_dataset_path##*/}" candidate_dataset="bpool/BOOT/${dataset_basename}" dataset_properties="$(zfs get -H mountpoint,canmount ${candidate_dataset} | cut -f3 | paste -sd ' ')" if [ -z "${dataset_properties}" ]; then return fi rel_pool_root=$(zpool get -H altroot bpool | awk '{print $3}') if [ "${rel_pool_root}" = "-" ]; then rel_pool_root="" fi snapshot_name="${dataset_basename##*@}" [ "${snapshot_name}" = "${dataset_basename}" ] && snapshot_name="" if [ -z "${snapshot_name}" ]; then if ! echo "${dataset_properties}" | grep -Eq "${rel_pool_root}/boot (on|noauto)"; then return fi else candidate_dataset=$(echo "${candidate_dataset}" | cut -d '@' -f1) fi validate_system_dataset "${candidate_dataset}" "boot" "${mntdir}" "${snapshot_name}" } # Return if secure boot is enabled on that system is_secure_boot_enabled() { if LANG=C mokutil --sb-state 2>/dev/null | grep -qi enabled; then echo "true" return fi echo "false" return } # Given a filesystem or snapshot dataset, returns dataset|machine id|pretty name|last used # $1 is dataset we want information from # $2 is the temporary mount directory to use get_dataset_info() { local dataset="$1" local mntdir="$2" local base_dataset="${dataset}" local etc_dir="${mntdir}/etc" local is_snapshot="false" # For snapshot we extract the parent dataset if echo "${dataset}" | grep -q '@'; then base_dataset=$(echo "${dataset}" | cut -d '@' -f1) is_snapshot="true" fi mount -o noatime,zfsutil -t zfs "${base_dataset}" "${mntdir}" # read machine-id/os-release from /etc etc_dir=$(get_system_directory "${dataset}" "etc" "true" "${mntdir}" "") if [ -z "${etc_dir}" ]; then grub_warn "Ignoring ${dataset}" mountpoint -q "${mntdir}/etc" && umount "${mntdir}/etc" || true umount "${mntdir}" return fi machine_id="" if [ -f "${etc_dir}/machine-id" ]; then machine_id=$(cat "${etc_dir}/machine-id") fi # We have to use a random temporary id if we don't have any machine-id file or if this one is empty # (mostly the case of new installations before first boot). # Let's use the dataset name directly for this. # Consequence is that all datasets are then separated. if [ -z "${machine_id}" ]; then machine_id="${dataset}" fi pretty_name=$(. "${etc_dir}/os-release" && echo "${PRETTY_NAME}") mountpoint -q "${mntdir}/etc" && umount "${mntdir}/etc" || true # read available kernels from /boot boot_dir="$(try_default_layout_bpool "${dataset}" "${mntdir}")" if [ -z "${boot_dir}" ]; then boot_dir=$(get_system_directory "${dataset}" "boot" "false" "${mntdir}" "${etc_dir}") fi if [ -z "${boot_dir}" ]; then grub_warn "Ignoring ${dataset}" mountpoint -q "${mntdir}/boot" && umount "${mntdir}/boot" || true umount "${mntdir}" return fi initrd_list="" kernel_list="" list=$(find "${boot_dir}" -maxdepth 1 -type f -regex '.*/\(vmlinuz\|vmlinux\|kernel\)-.*') while [ "x$list" != "x" ] ; do linux=`version_find_latest $list` list=`echo $list | tr ' ' '\n' | fgrep -vx "$linux" | tr '\n' ' '` if ! grub_file_is_not_garbage "${linux}" ; then continue fi # Filters entry if efi/non efi. # Note that for now we allow kernel without .efi.signed as those are signed kernel # on ubuntu, loaded by the shim. case "${linux}" in *.efi.signed) if [ "$(is_secure_boot_enabled)" = "false" ]; then continue fi ;; esac linux_basename=$(basename "${linux}") linux_dirname=$(dirname "${linux}") version=$(echo "${linux_basename}" | sed -e "s,^[^0-9]*-,,g") alt_version=$(echo "${version}" | sed -e "s,\.old$,,g") gettext_printf "Found linux image: %s in %s\n" "${linux_basename}" "${dataset}" >&2 initrd="" for i in "initrd.img-${version}" "initrd-${version}.img" "initrd-${version}.gz" \ "initrd-${version}" "initramfs-${version}.img" \ "initrd.img-${alt_version}" "initrd-${alt_version}.img" \ "initrd-${alt_version}" "initramfs-${alt_version}.img" \ "initramfs-genkernel-${version}" \ "initramfs-genkernel-${alt_version}" \ "initramfs-genkernel-${GENKERNEL_ARCH}-${version}" \ "initramfs-genkernel-${GENKERNEL_ARCH}-${alt_version}"; do if test -e "${linux_dirname}/${i}" ; then initrd="$i" break fi done if test -z "${initrd}" ; then grub_warn "Couldn't find any valid initrd for dataset ${dataset}." continue fi gettext_printf "Found initrd image: %s in %s\n" "${initrd}" "${dataset}" >&2 rel_linux_dirname=$(make_system_path_relative_to_its_root "${linux_dirname}") initrd_list="${initrd_list}|${rel_linux_dirname}/${initrd}" kernel_list="${kernel_list}|${rel_linux_dirname}/${linux_basename}" done initrd_list="${initrd_list#|}" kernel_list="${kernel_list#|}" initrd_device=$(${grub_probe} --target=device "${boot_dir}" | head -1) mountpoint -q "${mntdir}/boot" && umount "${mntdir}/boot" || true # We needed to look in / for snapshots on root dataset, umount there before zfs lazily unmount it case "${boot_dir}" in /boot/.zfs/snapshot/*) umount "${boot_dir}" || true ;; esac # for zsys snapshots: we want to know which kernel we successful last booted with last_booted_kernel=$(zfs get -H com.ubuntu.zsys:last-booted-kernel "${dataset}" | awk '{print $3}') # snapshot: last_used is dataset creation time if [ "${is_snapshot}" = "true" ]; then last_used="$(zfs get -pH creation "${dataset}" | awk -F '\t' '{print $3}')" # otherwise, last_used is manually marked at boot/shutdown on a root dataset for zsys else # if current system, take current time if zfs mount | awk '/[ \t]+\/$/ {print $1}' | grep -q ${dataset}; then last_used=$(date +%s) else last_used=$(zfs get -H com.ubuntu.zsys:last-used "${dataset}" | awk '{print $3}') # case of non zsys, or zsys without annotation, take /etc/machine-id stat (as we mounted with noatime). # However, as systems can be relatime, if system is current mounted one, set current time (case of clone + reboot # within the same d). if [ "${last_used}" = "-" ]; then last_used=$(stat --printf="%X" "${mntdir}/etc/os-release") if [ -f "${mntdir}/etc/machine-id" ]; then last_used=$(stat --printf="%X" "${mntdir}/etc/machine-id") fi fi fi fi is_zsys=$(zfs get -H com.ubuntu.zsys:bootfs "${base_dataset}" | awk '{print $3}') if [ -n "${initrd_list}" -a -n "${kernel_list}" ]; then echo "${dataset}\t${is_zsys}\t${machine_id}\t${pretty_name}\t${last_used}\t${initrd_device}\t${initrd_list}\t${kernel_list}\t${last_booted_kernel}" else grub_warn "didn't find any valid initrd or kernel." fi umount "${mntdir}" || true # We needed to look in / for snapshots on root dataset, umount the snapshot for etc before zfs lazily unmount it case "${etc_dir}" in /.zfs/snapshot/*/etc) snapshot_path="$(findmnt -n -o TARGET -T ${etc_dir})" umount "${snapshot_path}" || true ;; esac } # Scan available boot options and returns in a formatted list # $1 is the temporary mount directory to use bootlist() { local mntdir="$1" local boot_list="" for dataset in $(get_root_datasets); do # get information from current root dataset boot_list="${boot_list}$(get_dataset_info ${dataset} ${mntdir})\n" # get information from snapshots of this root dataset for snapshot_dataset in $(zfs list -H -o name -t snapshot "${dataset}"); do boot_list="${boot_list}$(get_dataset_info ${snapshot_dataset} ${mntdir})\n" done done echo "${boot_list}" } # Order machine ids by last_used from their main entry get_machines_sorted() { local bootlist="$1" local machineids="$(echo "${bootlist}" | awk '{print $3}' | sort -u)" for machineid in ${machineids}; do echo "${bootlist}" | awk 'BEGIN{FS="\t"} $1 !~ /.*@.*/ {print $5, $3}' | sort -nr | grep -E "[^^]\b${machineid}\b" | head -1 done | sort -nr | awk '{print $2}' } # Sort entries by last_used for a given machineid sort_entries_for_machineid() { local bootlist="$1" local machineid="$2" tab="$(printf '\t')" echo "${bootlist}" | grep -E "[^^]\b${machineid}\b" | sort -k5,5r -k1,1 -t "${tab}" } # Return main entry index get_main_entry() { local entries="$1" echo "${entries}" | awk 'BEGIN{FS="\t"} $1 !~ /.*@.*/ {print}' | head -1 } # Return specific field at index from entry get_field_from_entry() { local entry="$1" local index="$2" echo "${entry}" | awk "BEGIN{FS=\"\t\"} {print \$$index}" } # Get the main entry metadata main_entry_meta() { local main_entry="$1" initrd=$(get_field_from_entry "${main_entry}" 7 | cut -d'|' -f1) kernel=$(get_field_from_entry "${main_entry}" 8 | cut -d'|' -f1) # Take first element (most recent entry) which is not a snapshot echo "${main_entry}" | awk "BEGIN{ FS=\"\t\"; OFS=\"\t\"} {print \$3, \$2, \"main\", \$4, \$1, \$6, \"$initrd\", \"$kernel\"}" } # Get advanced entries metadata advanced_entries_meta() { local main_entry="$1" last_used_kernel="$(get_field_from_entry "${main_entry}" 9 )" # We must align initrds with kernels. # Adds initrds to the stack then pop them 1 by 1 as we process the kernels set -- $(get_field_from_entry "${main_entry}" 7 | tr "|" " ") for kernel in $(get_field_from_entry "${main_entry}" 8 | tr "|" " "); do # get initrd and pop to the next one initrd="$1"; shift was_last_used_kernel="false" kernel_basename=$(basename "${kernel}") if [ "${kernel_basename}" = "${last_used_kernel}" ]; then was_last_used_kernel="true" fi echo "${main_entry}" | awk "BEGIN{ FS=\"\t\"; OFS=\"\t\"} {print \$3, \$2, \"advanced\", \$4, \$1, \$6, \"$initrd\", \"$kernel\", \"$was_last_used_kernel\"}" done } # Get history metadata history_entries_meta() { local entries="$1" local main_dataset_name="$2" local main_dataset_releasename="$3" if [ -z "${entries}" ]; then return fi # Traverse snapshots and clones echo "${entries}" | while read entry; do name="" # Compute snapshot/filesystem dataset name snap_dataset_name="$(get_field_from_entry "${entry}" 1)" snapname="${snap_dataset_name##*@}" # If, this is a clone, take what is after main_dataset_name if [ "${snapname}" = "${snap_dataset_name}" ]; then snapname="${snap_dataset_name##${main_dataset_name}_}" # Handle manual user clone (not prefixed by "main_dataset_name") snapname="${snapname##*/}" fi # We keep the snapname only if it is not only a zsys auto snapshot if echo "${snapname}" | grep -q "^autozsys_"; then snapname="" fi # We store the release only if it different from main dataset release (snapshot before a release upgrade) releasename=$(get_field_from_entry "${entry}" 4) if [ "${releasename}" = "${main_dataset_releasename}" ]; then releasename="" fi # Snapshot date foo="$(get_field_from_entry "${entry}" 5)" snapdate="$(date -d @$(get_field_from_entry "${entry}" 5) "+%x @ %H:%M")" # For snapshots/clones the name can have the following formats: # <DATE>: autozsys, same release # <OLD_RELEASE> on <DATE>: autozsys, different release # <SNAPNAME> on <DATE>: Manual snapshot, same release # <SNAPNAME>, <OLD_RELEASE> on <DATE>: Manual snapshot, different release if [ "${snapname}" = "" -a "${releasename}" = "" ]; then name="${snapdate}" elif [ "${snapname}" = "" -a "${releasename}" != "" ]; then name=$(gettext_printf "%s on %s" "${releasename}" "${snapdate}") elif [ "${snapname}" != "" -a "${releasename}" = "" ]; then name=$(gettext_printf "%s on %s" "${snapname}" "${snapdate}") else # snapname != "" && releasename != "" name=$(gettext_printf "%s, %s on %s" "${snapname}" "${releasename}" "${snapdate}") fi # Choose kernel and initrd if the snapshot was booted successfully on a specific kernel before # Take latest by default if no match initrd=$(get_field_from_entry "${entry}" 7 | cut -d'|' -f1) kernel=$(get_field_from_entry "${entry}" 8 | cut -d'|' -f1) last_used_kernel="$(get_field_from_entry "${entry}" 9)" # We must align initrds with kernels. # Adds initrds to the stack then pop them 1 by 1 as we process the kernels set -- $(get_field_from_entry "${entry}" 7 | tr "|" " ") for k in $(get_field_from_entry "${entry}" 8|tr "|" " "); do # get initrd and pop to the next one candidate_initrd="$1"; shift kernel_basename=$(basename "${k}") if [ "${kernel_basename}" = "${last_used_kernel}" ]; then kernel="${k}" initrd="${candidate_initrd}" break fi done echo "${entry}" | awk "BEGIN{ FS=\"\t\"; OFS=\"\t\"} {print \$3, \$2, \"history\", \"$name\", \$1, \$6, \"$initrd\", \"$kernel\"}" done } # Generate metadata from a BOOTLIST that will subsequently used to generate # the final grub menu entries generate_grub_menu_metadata() { local bootlist="$1" # Sort machineids by last_used from their main entry for machineid in $(get_machines_sorted "${bootlist}"); do entries="$(sort_entries_for_machineid "${bootlist}" ${machineid})" main_entry="$(get_main_entry "${entries}")" if [ -z "$main_entry" ]; then continue fi main_entry_meta "${main_entry}" advanced_entries_meta "${main_entry}" main_dataset_name="$(get_field_from_entry "${main_entry}" 1)" main_dataset_releasename="$(get_field_from_entry "${main_entry}" 4)" # grep -v errcode != 0 if there is no match. || true to not fail with -e other_entries="$(echo "${entries}" | grep -v "${main_entry}" || true)" history_entries_meta "${other_entries}" "${main_dataset_name}" "${main_dataset_releasename}" done } # Print the configuration part common to all sections # Note: # If 10_linux runs these part will be defined twice in grub configuration print_menu_prologue() { cat << 'EOF' function gfxmode { set gfxpayload="${1}" EOF if [ "${vt_handoff}" = 1 ]; then cat << 'EOF' if [ "${1}" = "keep" ]; then set vt_handoff=vt.handoff=1 else set vt_handoff= fi EOF fi cat << EOF } EOF # Use ELILO's generic "efifb" when it's known to be available. # FIXME: We need an interface to select vesafb in case efifb can't be used. GRUB_GFXPAYLOAD_LINUX="${GRUB_GFXPAYLOAD_LINUX:-}" if [ "${GRUB_GFXPAYLOAD_LINUX}" != "" ] || [ "${gfxpayload_dynamic}" = 0 ]; then echo "set linux_gfx_mode=${GRUB_GFXPAYLOAD_LINUX}" else cat << EOF if [ "\${recordfail}" != 1 ]; then if [ -e \${prefix}/gfxblacklist.txt ]; then if hwmatch \${prefix}/gfxblacklist.txt 3; then if [ \${match} = 0 ]; then set linux_gfx_mode=keep else set linux_gfx_mode=text fi else set linux_gfx_mode=text fi else set linux_gfx_mode=keep fi else set linux_gfx_mode=text fi EOF fi cat << EOF export linux_gfx_mode EOF } # Cache for prepare_grub_to_access_device call # $1: boot_device # $2: submenu_level prepare_grub_to_access_device_cached() { local boot_device="$1" local submenu_level="$2" local boot_device_idx="$(echo ${boot_device} | tr '/' '_')" cache_file="${ZFSTMP}/$(echo boot_device${boot_device_idx})" if [ ! -f "${cache_file}" ]; then set +u echo "$(prepare_grub_to_access_device "${boot_device}")" > "${cache_file}" set -u for i in 0 1 2; do submenu_indentation="$(printf %${i}s | tr " " "${grub_tab}")" sed "s/^/${submenu_indentation} /" "${cache_file}" > "${cache_file}--${i}" done fi cat "${cache_file}--${submenu_level}" } # Print a grub menu entry zfs_linux_entry () { submenu_level="$1" title="$2" type="$3" dataset="$4" boot_device="$5" initrd="$6" kernel="$7" kernel_version="$8" kernel_additional_args="${9:-}" boot_devices="${10:-}" submenu_indentation="$(printf %${submenu_level}s | tr " " "${grub_tab}")" echo "${submenu_indentation}menuentry '$(echo "${title}" | grub_quote)' ${CLASS} \${menuentry_id_option} 'gnulinux-${dataset}-${kernel_version}' {" if [ "${quick_boot}" = 1 ]; then echo "${submenu_indentation} recordfail" fi if [ "${type}" != "recovery" ] ; then GRUB_SAVEDEFAULT=${GRUB_SAVEDEFAULT:-} default_entry="$(save_default_entry)" if [ -n "${default_entry}" ]; then echo "${submenu_indentation} ${default_entry}" fi fi # Use ELILO's generic "efifb" when it's known to be available. # FIXME: We need an interface to select vesafb in case efifb can't be used. if [ "${GRUB_GFXPAYLOAD_LINUX}" = "" ]; then echo "${submenu_indentation} load_video" else if [ "${GRUB_GFXPAYLOAD_LINUX}" != "text" ]; then echo "${submenu_indentation} load_video" fi fi if ([ "${ubuntu_recovery}" = 0 ] || [ "${type}" != "recovery" ]) && \ ([ "${GRUB_GFXPAYLOAD_LINUX}" != "" ] || [ "${gfxpayload_dynamic}" = 1 ]); then echo "${submenu_indentation} gfxmode \${linux_gfx_mode}" fi echo "${submenu_indentation} insmod gzio" echo "${submenu_indentation} if [ \"\${grub_platform}\" = xen ]; then insmod xzio; insmod lzopio; fi" if [ -n "$boot_devices" ]; then for device in ${boot_devices}; do echo "${submenu_indentation} if [ "${boot_device}" = "${device}" ]; then" echo "$(prepare_grub_to_access_device_cached "${device}" $(( submenu_level +1 )) )" echo "${submenu_indentation} fi" done else echo "$(prepare_grub_to_access_device_cached "${boot_device}" "${submenu_level}")" fi if [ "${quiet_boot}" = 0 ] || [ "${type}" != simple ]; then echo "${submenu_indentation} echo $(gettext_printf "Loading Linux %s ..." ${kernel_version} | grub_quote)" fi linux_default_args="${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" if [ ${type} = "recovery" ]; then linux_default_args="${GRUB_CMDLINE_LINUX_RECOVERY} ${GRUB_CMDLINE_LINUX}" fi echo "${submenu_indentation} linux ${kernel} root=ZFS=${dataset} ro ${linux_default_args} ${kernel_additional_args}" if [ "${quiet_boot}" = 0 ] || [ "${type}" != simple ]; then echo "${submenu_indentation} echo '$(gettext_printf "Loading initial ramdisk ..." | grub_quote)'" fi echo "${submenu_indentation} initrd ${initrd}" echo "${submenu_indentation}}" } # Generate a GRUB Menu from menu meta data # $1 menu metadata generate_grub_menu() { local menu_metadata="$1" local last_section="" local main_dataset_name="" local main_dataset="" local have_zsys="" if [ -z "${menu_metadata}" ]; then return fi CLASS="--class gnu-linux --class gnu --class os" if [ "${GRUB_DISTRIBUTOR}" = "" ] ; then OS=GNU/Linux else case ${GRUB_DISTRIBUTOR} in Ubuntu|Kubuntu) OS="${GRUB_DISTRIBUTOR}" ;; *) OS="${GRUB_DISTRIBUTOR} GNU/Linux" ;; esac CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1 | LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}" fi if [ -x /lib/recovery-mode/recovery-menu ]; then GRUB_CMDLINE_LINUX_RECOVERY=recovery else GRUB_CMDLINE_LINUX_RECOVERY=single fi if [ "${ubuntu_recovery}" = 1 ]; then GRUB_CMDLINE_LINUX_RECOVERY="${GRUB_CMDLINE_LINUX_RECOVERY} nomodeset" fi case "$GENKERNEL_ARCH" in x86*) GRUB_CMDLINE_LINUX_RECOVERY="$GRUB_CMDLINE_LINUX_RECOVERY dis_ucode_ldr";; esac if [ "${vt_handoff}" = 1 ]; then for word in ${GRUB_CMDLINE_LINUX_DEFAULT}; do if [ "${word}" = splash ]; then GRUB_CMDLINE_LINUX_DEFAULT="${GRUB_CMDLINE_LINUX_DEFAULT} \${vt_handoff}" fi done fi print_menu_prologue cat<<'EOF' function zsyshistorymenu { # $1: root dataset (eg rpool/ROOT/ubuntu_2zhm07@autozsys_k56fr6) # $2: boot device id (eg 411f29ce1557bfed) # $3: initrd (eg /BOOT/ubuntu_2zhm07@autozsys_k56fr6/initrd.img-5.4.0-21-generic) # $4: kernel (eg /BOOT/ubuntu_2zhm07@autozsys_k56fr6/vmlinuz-5.4.0-21-generic) # $5: kernel_version (eg 5.4.0-21-generic) set root_dataset="${1}" set boot_device="${2}" set initrd="${3}" set kernel="${4}" set kversion="${5}" EOF boot_devices=$(echo "${menu_metadata}" | cut -d"$(printf '\t')" -f6 | sort -u) title=$(gettext_printf "Revert system only") zfs_linux_entry 1 "${title}" "simple" '${root_dataset}' '${boot_device}' '${initrd}' '${kernel}' '${kversion}' '' "${boot_devices}" title="$(gettext_printf "Revert system and user data")" zfs_linux_entry 1 "${title}" "simple" '${root_dataset}' '${boot_device}' '${initrd}' '${kernel}' '${kversion}' 'zsys-revert=userdata' "${boot_devices}" GRUB_DISABLE_RECOVERY="${GRUB_DISABLE_RECOVERY:-}" if [ "${GRUB_DISABLE_RECOVERY}" != "true" ]; then title="$(gettext_printf "Revert system only (%s)" "$(gettext "${GRUB_RECOVERY_TITLE}")")" zfs_linux_entry 1 "${title}" "recovery" '${root_dataset}' '${boot_device}' '${initrd}' '${kernel}' '${kversion}' '' "${boot_devices}" title="$(gettext_printf "Revert system and user data (%s)" "$(gettext "${GRUB_RECOVERY_TITLE}")")" zfs_linux_entry 1 "${title}" "recovery" '${root_dataset}' '${boot_device}' '${initrd}' '${kernel}' '${kversion}' 'zsys-revert=userdata' "${boot_devices}" fi echo "}" echo # IFS is set to TAB (ASCII 0x09) echo "${menu_metadata}" | { at_least_one_entry=0 have_zsys="$(which zsysd || true)" while IFS="$(printf '\t')" read -r machineid iszsys section name dataset device initrd kernel opt; do # Disable history for non zsys system or if systems is a zsys one and zsys isn't installed. # In pure zfs systems, we identified multiple issues due to the mount generator # in upstream zfs which makes it incompatible. Don't show history for now. if [ "${section}" = "history" ]; then if [ "${iszsys}" != "yes" ] || [ "${iszsys}" = "yes" -a -z "${have_zsys}" ]; then continue fi fi if [ "${last_section}" != "${section}" -a -n "${last_section}" ]; then # Close previous section wrapper if [ "${last_section}" != "main" ]; then echo "}" # Add grub_tabs at_least_one_entry=0 fi fi case "${section}" in main) title="${name}" main_dataset_name="${name}" main_dataset="${dataset}" kernel_version=$(basename "${kernel}" | sed -e "s,^[^0-9]*-,,g") zfs_linux_entry 0 "${title}" "simple" "${dataset}" "${device}" "${initrd}" "${kernel}" "${kernel_version}" at_least_one_entry=1 ;; advanced) # normal and recovery entries for a given kernel if [ "${last_section}" != "${section}" ]; then echo "submenu '$(gettext_printf "Advanced options for %s" "${main_dataset_name}" | grub_quote)' \${menuentry_id_option} 'gnulinux-advanced-${main_dataset}' {" fi last_booted_kernel_marker="" if [ "${opt}" = "true" ]; then last_booted_kernel_marker="* " fi kernel_version=$(basename "${kernel}" | sed -e "s,^[^0-9]*-,,g") title="$(gettext_printf "%s%s, with Linux %s" "${last_booted_kernel_marker}" "${name}" "${kernel_version}")" zfs_linux_entry 1 "${title}" "advanced" "${dataset}" "${device}" "${initrd}" "${kernel}" "${kernel_version}" GRUB_DISABLE_RECOVERY=${GRUB_DISABLE_RECOVERY:-} if [ "${GRUB_DISABLE_RECOVERY}" != "true" ]; then title="$(gettext_printf "%s%s, with Linux %s (%s)" "${last_booted_kernel_marker}" "${name}" "${kernel_version}" "$(gettext "${GRUB_RECOVERY_TITLE}")")" zfs_linux_entry 1 "${title}" "recovery" "${dataset}" "${device}" "${initrd}" "${kernel}" "${kernel_version}" fi at_least_one_entry=1 ;; history) # Revert to a snapshot # revert system, revert system and user data and associated recovery entries if [ "${last_section}" != "${section}" ]; then echo "submenu '$(gettext_printf "History for %s" "${main_dataset_name}" | grub_quote)' \${menuentry_id_option} 'gnulinux-history-${main_dataset}' {" fi if [ "${iszsys}" = "yes" ]; then title="$(gettext_printf "Revert to %s" "${name}" | grub_quote)" else title="$(gettext_printf "Boot on %s" "${name}" | grub_quote)" fi echo " submenu '${title}' \${menuentry_id_option} 'gnulinux-history-${dataset}' {" kernel_version=$(basename "${kernel}" | sed -e "s,^[^0-9]*-,,g") # Zsys only: let revert system without destroying snapshots if [ "${iszsys}" = "yes" ]; then echo "${grub_tab}${grub_tab}zsyshistorymenu" \"${dataset}\" \"${device}\" \"${initrd}\" \"${kernel}\" \"${kernel_version}\" # Non-zsys: boot temporarly on snapshots or rollback (destroying intermediate snapshots) else title="$(gettext_printf "One time boot")" zfs_linux_entry 2 "${title}" "simple" "${dataset}" "${device}" "${initrd}" "${kernel}" "${kernel_version}" GRUB_DISABLE_RECOVERY="${GRUB_DISABLE_RECOVERY:-}" if [ "${GRUB_DISABLE_RECOVERY}" != "true" ]; then title="$(gettext_printf "One time boot (%s)" "$(gettext "${GRUB_RECOVERY_TITLE}")")" zfs_linux_entry 2 "${title}" "recovery" "${dataset}" "${device}" "${initrd}" "${kernel}" "${kernel_version}" fi title="$(gettext_printf "Revert system (all intermediate snapshots will be destroyed)")" zfs_linux_entry 2 "${title}" "simple" "${dataset}" "${device}" "${initrd}" "${kernel}" "${kernel_version}" "rollback=yes" fi echo " }" at_least_one_entry=1 ;; *) grub_warn "unknown section: ${section}. Ignoring entry ${name} for ${dataset}" ;; esac last_section="${section}" done if [ "${at_least_one_entry}" -eq 1 ]; then echo "}" fi } } # don't add trailing newline of variable is empty # $1: content to write # $2: destination file trailing_newline_if_not_empty() { content="$1" dest="$2" if [ -z "${content}" ]; then rm -f "${dest}" touch "${dest}" return fi echo "${content}" > "${dest}" } GRUB_LINUX_ZFS_TEST="${GRUB_LINUX_ZFS_TEST:-}" case "${GRUB_LINUX_ZFS_TEST}" in bootlist) # Import all available pools on the system and return imported list imported_pools=$(import_pools) boot_list="$(bootlist ${MNTDIR})" trailing_newline_if_not_empty "${boot_list}" "${GRUB_LINUX_ZFS_TEST_OUTPUT}" break ;; metamenu) boot_list="$(cat ${GRUB_LINUX_ZFS_TEST_INPUT})" menu_metadata="$(generate_grub_menu_metadata "${boot_list}")" trailing_newline_if_not_empty "${menu_metadata}" "${GRUB_LINUX_ZFS_TEST_OUTPUT}" break ;; grubmenu) menu_metadata="$(cat ${GRUB_LINUX_ZFS_TEST_INPUT})" grub_menu=$(generate_grub_menu "${menu_metadata}") trailing_newline_if_not_empty "${grub_menu}" "${GRUB_LINUX_ZFS_TEST_OUTPUT}" break ;; *) # Import all available pools on the system and return imported list imported_pools=$(import_pools) # Generate the complete list of boot entries boot_list="$(bootlist ${MNTDIR})" # Create boot menu meta data from the list of boot entries menu_metadata="$(generate_grub_menu_metadata "${boot_list}")" # Create boot menu meta data from the list of boot entries grub_menu="$(generate_grub_menu "${menu_metadata}")" if [ -n "${grub_menu}" ]; then # We want the trailing newline as a marker will be added echo "${grub_menu}" fi ;; esac
Close