mirror of
https://github.com/NiklasGollenstede/nixos-installer.git
synced 2024-11-21 23:43:14 +01:00
fix gptfdisk, integrate some bash aliases
This commit is contained in:
parent
a4ae2ab551
commit
e3b5b17620
BIN
flake.lock
BIN
flake.lock
Binary file not shown.
@ -9,18 +9,19 @@ Just to provide an example of what a host configuration using this set of librar
|
||||
|
||||
To prepare a virtual machine disk, as `sudo` user with `nix` installed, run in `..`:
|
||||
```bash
|
||||
nix run '.#example' -- sudo install-system /home/$(id -un)/vm/disks/example.img && sudo chown $(id -un): /home/$(id -un)/vm/disks/example.img
|
||||
nix run '.#example-raidz' -- sudo install-system /tmp/nixos-main.img:raidz1=/tmp/nixos-rz1.img:raidz2=/tmp/nixos-rz2.img:raidz3=/tmp/nixos-rz3.img
|
||||
nix run '.#example' -- sudo install-system /home/$(id -un)/vm/disks/example/
|
||||
( sudo chown $(id -un): /home/$(id -un)/vm/disks/example/* )
|
||||
nix run '.#example-raidz' -- sudo install-system /tmp/nixos-example-raidz/
|
||||
```
|
||||
Then to boot the system in a qemu VM with KVM:
|
||||
```bash
|
||||
nix run '.#example' -- sudo run-qemu /home/$(id -un)/vm/disks/example.img
|
||||
nix run '.#example' -- sudo run-qemu /home/$(id -un)/vm/disks/example/
|
||||
```
|
||||
Or as user with vBox access, run this and use the UI or the printed commands:
|
||||
```bash
|
||||
nix run '.#example' -- register-vbox /home/$(id -un)/vm/disks/example.img
|
||||
nix run '.#example' -- register-vbox /home/$(id -un)/vm/disks/example/primary.img
|
||||
```
|
||||
Alternative to running directly as `root` (esp. if `nix` is not installed for root), the above commands can also be run with `sudo` as additional argument before the `--`.
|
||||
Alternative to running with `sudo` (if `nix` is installed for root), the above commands can also be run as `root` without the `sudo` argument.
|
||||
|
||||
|
||||
## Implementation
|
||||
@ -31,7 +32,7 @@ dirname: inputs: { config, pkgs, lib, name, ... }: let inherit (inputs.self) lib
|
||||
#suffix = builtins.head (builtins.match ''example-(.*)'' name); # make differences in config based on this when using »wip.preface.instances«
|
||||
hash = builtins.substring 0 8 (builtins.hashString "sha256" config.networking.hostName);
|
||||
in { imports = [ ({ ## Hardware
|
||||
wip.preface.instances = [ "example-explicit" "example" "example-minimal" "example-raidz" ];
|
||||
wip.preface.instances = [ "example-explicit" "example" "example-minimal" "example-raidz" "test-zfs-hibernate" ];
|
||||
|
||||
wip.preface.hardware = "x86_64"; system.stateVersion = "22.05";
|
||||
|
||||
@ -60,7 +61,7 @@ in { imports = [ ({ ## Hardware
|
||||
fileSystems."/nix/store" = { options = ["bind,ro"]; device = "/system/nix/store"; neededForBoot = true; };
|
||||
|
||||
|
||||
}) (lib.mkIf (name == "example") { ## More complex but automatic FS setup
|
||||
}) (lib.mkIf (name == "example" || name == "test-zfs-hibernate") { ## More complex but automatic FS setup
|
||||
|
||||
#wip.fs.disks.devices.primary.size = "16G"; # (default)
|
||||
wip.fs.boot.enable = true; wip.fs.boot.size = "512M";
|
||||
@ -68,6 +69,10 @@ in { imports = [ ({ ## Hardware
|
||||
wip.fs.keystore.enable = true;
|
||||
wip.fs.temproot.enable = true;
|
||||
|
||||
wip.fs.temproot.swap.size = "2G";
|
||||
wip.fs.temproot.swap.asPartition = true;
|
||||
wip.fs.temproot.swap.encrypted = true;
|
||||
|
||||
wip.fs.temproot.temp.type = "tmpfs";
|
||||
|
||||
wip.fs.temproot.local.type = "bind";
|
||||
@ -143,4 +148,28 @@ in { imports = [ ({ ## Hardware
|
||||
|
||||
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
|
||||
|
||||
|
||||
}) (lib.mkIf (name == "test-zfs-hibernate") {
|
||||
# This was an attempt to reliably get ZFS to corrupt when importing a ZFS pool before resuming from hibernation in initrd. It isn't reproducible, though: https://github.com/NixOS/nixpkgs/pull/208037#issuecomment-1368240321
|
||||
|
||||
wip.fs.temproot.temp.type = lib.mkForce "zfs";
|
||||
wip.fs.temproot.local.type = lib.mkForce "zfs";
|
||||
wip.fs.keystore.keys."luks/rpool-${hash}/0" = lib.mkForce null;
|
||||
|
||||
wip.fs.disks.devices.mirror.size = "16G";
|
||||
wip.fs.disks.partitions."mirror-${hash}" = { type = "bf00"; disk = "mirror"; };
|
||||
environment.systemPackages = [ (pkgs.writeShellScriptBin "test-zfs-hibernate" ''
|
||||
set -ex
|
||||
</dev/urandom head -c 10G >/tmp/dump
|
||||
sync ; echo 3 > /proc/sys/vm/drop_caches ; sleep 5
|
||||
zpool attach rpool-${hash} /dev/disk/by-partlabel/rpool-${hash} /dev/disk/by-partlabel/mirror-${hash}
|
||||
sleep 2 # the above command should still be in progress
|
||||
: before ; date
|
||||
systemctl hibernate
|
||||
: hibernating ; date
|
||||
sleep 3 ; : awake ; date
|
||||
'') ];
|
||||
boot.zfs = if (builtins.substring 0 5 inputs.nixpkgs.lib.version) == "22.05" then { } else { allowHibernation = true; };
|
||||
|
||||
|
||||
}) ]; }
|
||||
|
@ -1,7 +1,7 @@
|
||||
dirname: inputs@{ self, nixpkgs, ...}: let
|
||||
inherit (nixpkgs) lib;
|
||||
inherit (import "${dirname}/vars.nix" dirname inputs) mapMerge mapMergeUnique mergeAttrsUnique flipNames;
|
||||
inherit (import "${dirname}/imports.nix" dirname inputs) getModifiedPackages getNixFiles importWrapped;
|
||||
inherit (import "${dirname}/imports.nix" dirname inputs) getNixFiles importWrapped;
|
||||
inherit (import "${dirname}/scripts.nix" dirname inputs) substituteImplicit;
|
||||
setup-scripts = (import "${dirname}/setup-scripts" "${dirname}/setup-scripts" inputs);
|
||||
prefix = inputs.config.prefix;
|
||||
@ -34,14 +34,12 @@ in rec {
|
||||
importRepo = inputs: repoPath': outputs: let
|
||||
repoPath = builtins.path { path = repoPath'; name = "source"; }; # referring to the current flake directory as »./.« is quite intuitive (and »inputs.self.outPath« causes infinite recursion), but without this it adds another hash to the path (because it copies it)
|
||||
in let result = (outputs (
|
||||
(let it = importWrapped inputs "${repoPath}/lib"; in if it.exists then rec {
|
||||
(let it = importWrapped inputs "${repoPath}/lib"; in if it.exists then {
|
||||
lib = it.result;
|
||||
} else { }) // (let it = importWrapped inputs "${repoPath}/overlays"; in if it.exists then rec {
|
||||
overlays = it.result;
|
||||
overlay = final: prev: builtins.foldl' (prev: overlay: prev // (overlay final prev)) prev (builtins.attrValues overlays);
|
||||
} else { }) // (let it = importWrapped inputs "${repoPath}/modules"; in if it.exists then rec {
|
||||
nixosModules = it.result;
|
||||
nixosModule = { imports = builtins.attrValues nixosModules; };
|
||||
} else { }) // (let it = importWrapped inputs "${repoPath}/overlays"; in if it.exists then {
|
||||
overlays = { default = final: prev: builtins.foldl' (prev: overlay: prev // (overlay final prev)) prev (builtins.attrValues it.result); } // it.result;
|
||||
} else { }) // (let it = importWrapped inputs "${repoPath}/modules"; in if it.exists then {
|
||||
nixosModules = { default = { imports = builtins.attrValues it.result; }; } // it.result;
|
||||
} else { })
|
||||
)); in if (builtins.isList result) then mergeOutputs result else result;
|
||||
|
||||
@ -70,7 +68,7 @@ in rec {
|
||||
imported = (importWrapped inputs entryPath).required ({ config = null; pkgs = null; lib = null; name = null; nodes = null; extraModules = null; } // args);
|
||||
module = builtins.elemAt imported.imports 0; props = module.${prefix}.preface;
|
||||
in if (
|
||||
imported?imports && (builtins.isList imported.imports) && (imported.imports != [ ]) && module?${prefix} && module.${prefix}?preface && props?hardware
|
||||
imported?imports && (builtins.isList imported.imports) && (imported.imports != [ ]) && module?${prefix}.preface && props?hardware
|
||||
) then (props) else throw "File ${entryPath} must fulfill the structure: dirname: inputs: { ... }: { imports = [ { ${prefix}.preface = { hardware = str; ... } } ]; }";
|
||||
|
||||
# Builds the System Configuration for a single host. Since each host depends on the context of all other host (in the same "network"), this is essentially only callable through »mkNixosConfigurations«.
|
||||
@ -91,6 +89,7 @@ in rec {
|
||||
]; _file = "${dirname}/flakes.nix#modules"; } ];
|
||||
|
||||
extraModules = modules ++ [ { imports = [ ({ # These are passed as »extraModules« module argument and can thus conveniently be reused when defining containers and such (Therefore define as much stuff as possible here).
|
||||
# TODO: or should these be set as »baseModules«? Does that implicitly pass these into any derived configs?
|
||||
|
||||
}) ({ config, ... }: {
|
||||
|
||||
@ -102,7 +101,7 @@ in rec {
|
||||
self = null; # avoid changing (and thus restarting) the containers on every trivial change
|
||||
} else inputs);
|
||||
|
||||
system.nixos.revision = lib.mkIf (inputs?nixpkgs && inputs.nixpkgs?rev) inputs.nixpkgs.rev; # (evaluating the default value fails under some circumstances)
|
||||
system.nixos.revision = lib.mkIf (inputs?nixpkgs.rev) inputs.nixpkgs.rev; # (evaluating the default value fails under some circumstances)
|
||||
|
||||
}) ({
|
||||
options.${prefix}.preface.hardware = lib.mkOption { description = "The name of the system's CPU instruction set (the first part of what is often referred to as »system«)."; type = lib.types.str; readOnly = true; };
|
||||
@ -167,11 +166,11 @@ in rec {
|
||||
# Arguments »{ files, dir, exclude, }« to »mkNixosConfigurations«, see there for details. May also be a list of those attrsets, in which case those multiple sets of hosts will be built separately by »mkNixosConfigurations«, allowing for separate sets of »peers« passed to »mkNixosConfiguration«. Each call will receive all other arguments, and the resulting sets of hosts will be merged.
|
||||
systems ? ({ dir = "${inputs.self}/hosts"; exclude = [ ]; }),
|
||||
# List of overlays to set as »config.nixpkgs.overlays«. Defaults to ».overlays.default« of all »overlayInputs«/»inputs« (incl. »inputs.self«).
|
||||
overlays ? (lib.remove null (map (input: if input?overlays && input.overlays?default then input.overlays.default else if input?overlay then input.overlay else null) (builtins.attrValues overlayInputs))),
|
||||
overlays ? (lib.remove null (map (input: if input?overlays.default then input.overlays.default else if input?overlay then input.overlay else null) (builtins.attrValues overlayInputs))),
|
||||
# (Subset of) »inputs« that »overlays« will be used from. Example: »{ inherit (inputs) self flakeA flakeB; }«.
|
||||
overlayInputs ? inputs,
|
||||
# List of Modules to import for all hosts, in addition to the default ones in »nixpkgs«. The host-individual module should selectively enable these. Defaults to ».nixosModules.default« of all »moduleInputs«/»inputs« (including »inputs.self«).
|
||||
modules ? (lib.remove null (map (input: if input?nixosModules && input.nixosModules?default then input.nixosModules.default else if input?nixosModule then input.nixosModule else null) (builtins.attrValues moduleInputs))),
|
||||
modules ? (lib.remove null (map (input: if input?nixosModules.default then input.nixosModules.default else if input?nixosModule then input.nixosModule else null) (builtins.attrValues moduleInputs))),
|
||||
# (Subset of) »inputs« that »modules« will be used from. Example: »{ inherit (inputs) self flakeA flakeB; }«.
|
||||
moduleInputs ? inputs,
|
||||
# Additional arguments passed to each module evaluated for the host config (if that module is defined as a function).
|
||||
|
@ -97,8 +97,10 @@ in rec {
|
||||
} // args);
|
||||
|
||||
# Given a list of »overlays« and »pkgs« with them applied, returns the subset of »pkgs« that was directly modified by the overlays.
|
||||
# (But this only works for top-level / non-scoped packages.)
|
||||
getModifiedPackages = pkgs: overlays: let
|
||||
names = builtins.concatLists (map (overlay: builtins.attrNames (overlay { } { })) (builtins.attrValues overlays));
|
||||
getNames = overlay: builtins.attrNames (overlay { } { });
|
||||
names = if overlays?default then getNames overlays.default else builtins.concatLists (map getNames (builtins.attrValues overlays));
|
||||
in mapMergeUnique (name: if lib.isDerivation pkgs.${name} then { ${name} = pkgs.${name}; } else { }) names;
|
||||
|
||||
## Given a path to a module in »nixpkgs/nixos/modules/«, when placed in another module's »imports«, this adds an option »disableModule.${modulePath}« that defaults to being false, but when explicitly set to »true«, disables all »config« values set by the module.
|
||||
|
@ -39,12 +39,18 @@ function do-disk-setup { # 1: diskPaths
|
||||
function partition-disks { # 1: diskPaths
|
||||
local beLoud=/dev/null ; if [[ ${args[debug]:-} ]] ; then beLoud=/dev/stdout ; fi
|
||||
local beSilent=/dev/stderr ; if [[ ${args[quiet]:-} ]] ; then beSilent=/dev/null ; fi
|
||||
|
||||
declare -g -A blockDevs=( ) # this ends up in the caller's scope
|
||||
if [[ $1 == */ ]] ; then
|
||||
mkdir -p "$1"
|
||||
for name in "@{!config.wip.fs.disks.devices[@]}" ; do blockDevs[$name]=${1}${name}.img ; done
|
||||
else
|
||||
local path ; for path in ${1//:/ } ; do
|
||||
local name=${path/=*/} ; if [[ $name != "$path" ]] ; then path=${path/$name=/} ; else name=primary ; fi
|
||||
if [[ ${blockDevs[$name]:-} ]] ; then echo "Path for block device $name specified more than once. Duplicate definition: $path" 1>&2 ; return 1 ; fi
|
||||
blockDevs[$name]=$path
|
||||
done
|
||||
fi
|
||||
|
||||
local name ; for name in "@{!config.wip.fs.disks.devices[@]}" ; do
|
||||
if [[ ! ${blockDevs[$name]:-} ]] ; then echo "Path for block device $name not provided" 1>&2 ; return 1 ; fi
|
||||
@ -97,7 +103,6 @@ function partition-disk { # 1: name, 2: blockDev, 3?: devSize
|
||||
|
||||
local -a sgdisk=( --zap-all ) # delete existing part tables
|
||||
if [[ ${disk[gptOffset]} != 0 ]] ; then
|
||||
echo 'Setting »gptOffset != 0« is currently not supported, as sgdisk with the patch applied somehow fails to read files' 1>&2 ; return 1
|
||||
sgdisk+=( --move-main-table=$(( 2 + ${disk[gptOffset]} )) ) # this is incorrectly documented as --adjust-main-table in the man pages (at least versions 1.05 to 1.09 incl)
|
||||
sgdisk+=( --move-backup-table=$(( devSize/${disk[sectorSize]} - 1 - 32 - ${disk[gptOffset]} )) )
|
||||
fi
|
||||
|
@ -58,6 +58,8 @@ function nixos-install-cmd {( set -eu # 1: mnt, 2: topLevel
|
||||
function install-system-to {( set -u # 1: mnt
|
||||
mnt=$1 ; topLevel=${2:-}
|
||||
targetSystem=${args[toplevel]:-@{config.system.build.toplevel}}
|
||||
beLoud=/dev/null ; if [[ ${args[debug]:-} ]] ; then beLoud=/dev/stdout ; fi
|
||||
beSilent=/dev/stderr ; if [[ ${args[quiet]:-} ]] ; then beSilent=/dev/null ; fi
|
||||
trap - EXIT # start with empty traps for sub-shell
|
||||
|
||||
# Link/create files that some tooling expects:
|
||||
@ -90,14 +92,19 @@ function install-system-to {( set -u # 1: mnt
|
||||
|
||||
# Copy system closure to new nix store:
|
||||
if [[ ${SUDO_USER:-} ]] ; then chown -R $SUDO_USER: $mnt/nix/store $mnt/nix/var || exit ; fi
|
||||
( cmd=( nix --extra-experimental-features nix-command --offline copy --no-check-sigs --to $mnt ${topLevel:-$targetSystem} ) ; if [[ ${args[quiet]:-} ]] ; then "${cmd[@]}" --quiet &>/dev/null || exit ; else set -x ; time "${cmd[@]}" || exit ; fi ) || exit ; rm -rf $mnt/nix/var/nix/gcroots || exit
|
||||
(
|
||||
cmd=( nix --extra-experimental-features nix-command --offline copy --no-check-sigs --to $mnt ${topLevel:-$targetSystem} )
|
||||
if [[ ${args[quiet]:-} ]] ; then
|
||||
( set -o pipefail ; "${cmd[@]}" --quiet 2>&1 >/dev/null | { grep -Pe '^error:' || true ; } ) || exit
|
||||
else set -x ; time "${cmd[@]}" || exit ; fi
|
||||
) || exit ; rm -rf $mnt/nix/var/nix/gcroots || exit
|
||||
# TODO: if the target has @{config.nix.settings.auto-optimise-store} and the host doesn't (there is no .links dir?), optimize now
|
||||
if [[ ${SUDO_USER:-} ]] ; then chown -R root:root $mnt/nix $mnt/nix/var || exit ; chown :30000 $mnt/nix/store || exit ; fi
|
||||
|
||||
# Run the main install command (primarily for the bootloader):
|
||||
mount -o bind,ro /nix/store $mnt/nix/store || exit ; prepend_trap '! mountpoint -q $mnt/nix/store || umount -l $mnt/nix/store' EXIT || exit # all the things required to _run_ the system are copied, but (may) need some more things to initially install it and/or enter the chroot (like qemu, see above)
|
||||
run-hook-script 'Pre Installation' @{config.wip.fs.disks.preInstallCommands!writeText.preInstallCommands} || exit
|
||||
code=0 ; nixos-install-cmd $mnt "${topLevel:-$targetSystem}" || code=$?
|
||||
code=0 ; nixos-install-cmd $mnt "${topLevel:-$targetSystem}" >$beLoud 2>$beSilent || code=$?
|
||||
run-hook-script 'Post Installation' @{config.wip.fs.disks.postInstallCommands!writeText.postInstallCommands} || exit
|
||||
|
||||
# Done!
|
||||
|
@ -64,7 +64,11 @@ function run-qemu {( set -eu # 1: diskImages
|
||||
#qemu+=( -M virt -m 1024 -smp 4 -cpu cortex-a53 ) ; args[no-nat]=1
|
||||
fi # else things are going to be quite slow
|
||||
|
||||
disks=( ${diskImages//:/ } ) ; for index in ${!disks[@]} ; do
|
||||
if [[ $diskImages == */ ]] ; then
|
||||
disks=( ${diskImages}primary.img ) ; for name in "@{!config.wip.fs.disks.devices[@]}" ; do if [[ $name != primary ]] ; then disks+=( ${diskImages}${name}.img ) ; fi ; done
|
||||
#disks=( "@{!config.wip.fs.disks.devices[@]}" ) ; disks=( "${disks[@]/#/$diskImages}" )
|
||||
else disks=( ${diskImages//:/ } ) ; fi
|
||||
for index in ${!disks[@]} ; do
|
||||
# qemu+=( -drive format=raw,if=ide,file="${disks[$index]/*=/}" ) # »if=ide« is the default, which these days isn't great for driver support inside the VM
|
||||
qemu+=( # not sure how correct the interpretations if the command are, and whether this works for more than one disk
|
||||
-drive format=raw,file="${disks[$index]/*=/}",media=disk,if=none,index=${index},id=drive${index} # create the disk drive, without attaching it, name it driveX
|
||||
|
@ -12,14 +12,14 @@ Things that really should be (more like) this by default.
|
||||
dirname: inputs: specialArgs@{ config, pkgs, lib, name, ... }: let inherit (inputs.self) lib; in let
|
||||
prefix = inputs.config.prefix;
|
||||
cfg = config.${prefix}.base;
|
||||
inputDefinesSystem = cfg.includeInputs?self && cfg.includeInputs.self?nixosConfigurations && cfg.includeInputs.self.nixosConfigurations?${name};
|
||||
in {
|
||||
|
||||
options.${prefix} = { base = {
|
||||
enable = lib.mkEnableOption "saner defaults";
|
||||
includeInputs = lib.mkOption { description = "The system's build inputs, to be included in the flake registry, and on the »NIX_PATH« entry, such that they are available for self-rebuilds and e.g. as »pkgs« on the CLI."; type = lib.types.attrsOf lib.types.anything; apply = lib.filterAttrs (k: v: v != null); default = { }; };
|
||||
panic_on_fail = lib.mkEnableOption "Kernel parameter »boot.panic_on_fail«" // { default = true; example = false; }; # It's stupidly hard to remove items from lists ...
|
||||
autoUpgrade = lib.mkEnableOption "automatic NixOS updates and garbage collection" // { default = inputDefinesSystem; defaultText = lib.literalExpression "config.${prefix}.base.includeInputs.self.nixosConfigurations?\${name}"; example = false; };
|
||||
autoUpgrade = lib.mkEnableOption "automatic NixOS updates and garbage collection" // { default = cfg.includeInputs?self.nixosConfigurations.${name}; defaultText = lib.literalExpression "config.${prefix}.base.includeInputs?self.nixosConfigurations.\${name}"; example = false; };
|
||||
bashInit = lib.mkEnableOption "pretty defaults for interactive bash shells" // { default = true; example = false; };
|
||||
}; };
|
||||
|
||||
# Bugfix:
|
||||
@ -36,7 +36,15 @@ in {
|
||||
environment.etc."machine-id".text = lib.mkDefault (builtins.substring 0 32 (builtins.hashString "sha256" "${config.networking.hostName}:machine-id")); # this works, but it "should be considered "confidential", and must not be exposed in untrusted environments" (not sure _why_ though)
|
||||
documentation.man.enable = lib.mkDefault config.documentation.enable;
|
||||
nix.settings.auto-optimise-store = lib.mkDefault true; # file deduplication, see https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-store-optimise.html#description
|
||||
boot.loader.timeout = lib.mkDefault 1; # save 4 seconds on startup
|
||||
|
||||
system.extraSystemBuilderCmds = (if !config.boot.initrd.enable then "" else ''
|
||||
ln -sT ${builtins.unsafeDiscardStringContext config.system.build.bootStage1} $out/boot-stage-1.sh # (this is super annoying to locate otherwise)
|
||||
''); # (to deactivate this, set »system.extraSystemBuilderCmds = lib.mkAfter "rm -f $out/boot-stage-1.sh";«)
|
||||
|
||||
system.activationScripts.diff-systems = { text = ''
|
||||
if [[ -e /run/current-system ]] ; then ${pkgs.nix}/bin/nix --extra-experimental-features nix-command store diff-closures /run/current-system "$systemConfig" ; fi
|
||||
''; deps = [ "etc" ]; }; # (to deactivate this, set »system.activationScripts.diff-systems = lib.mkForce "";«)
|
||||
|
||||
}) ({
|
||||
# Robustness/debugging:
|
||||
@ -46,7 +54,7 @@ in {
|
||||
systemd.extraConfig = "StatusUnitFormat=name"; # Show unit names instead of descriptions during boot.
|
||||
|
||||
|
||||
}) (lib.mkIf (inputDefinesSystem) { # non-flake
|
||||
}) (lib.mkIf (cfg.includeInputs?self.nixosConfigurations.${name}) { # non-flake
|
||||
|
||||
# Importing »<nixpkgs>« as non-flake returns a lambda returning the evaluated Nix Package Collection (»pkgs«). The most accurate representation of what that should be on the target host is the »pkgs« constructed when building it:
|
||||
system.extraSystemBuilderCmds = ''
|
||||
@ -92,12 +100,49 @@ in {
|
||||
};
|
||||
|
||||
|
||||
}) ({
|
||||
# Free convenience:
|
||||
}) (lib.mkIf (cfg.bashInit) {
|
||||
# (almost) Free Convenience:
|
||||
|
||||
environment.shellAliases = { "with" = lib.mkDefault ''nix-shell --run "bash --login" -p''; }; # »with« doesn't seem to be a common linux command yet, and it makes sense here: with $package => do stuff in shell
|
||||
environment.shellAliases = {
|
||||
|
||||
programs.bash.promptInit = lib.mkDefault ''
|
||||
"with" = pkgs.writeShellScript "with" ''
|
||||
help='Synopsys: With the Nix packages »PKGS« (as attribute path read from the imported »nixpkgs« specified on the »NIX_PATH«), run »CMD« with »ARGS«, or »bash --login« if no »CMD« is supplied.
|
||||
Usage: with [-h] PKGS... [-- [CMD [ARGS...]]]'
|
||||
pkgs=( ) ; while (( "$#" > 0 )) ; do {
|
||||
if [[ $1 == -h ]] ; then echo "$help" ; exit 0 ; fi
|
||||
if [[ $1 == -- ]] ; then shift ; break ; fi ; pkgs+=( "$1" )
|
||||
} ; shift ; done
|
||||
if (( ''${#pkgs[@]} == 0 )) ; then echo "$help" ; exit 1 ; fi
|
||||
if (( "$#" == 0 )) ; then set -- bash --login ; fi
|
||||
nix-shell --run "$( printf ' %q' "$@" )" -p "''${pkgs[@]}"
|
||||
#function run { bash -xc "$( printf ' %q' "$@" )" ; }
|
||||
''; # »with« doesn't seem to be a common linux command yet, and it makes sense here: with package(s) => do stuff
|
||||
|
||||
ls = "ls --color=auto"; # (default)
|
||||
l = "ls -alhF"; # (added F)
|
||||
ll = "ls -alF"; # (added aF)
|
||||
lt = "tree -a -p -g -u -s -D -F --timefmt '%Y-%m-%d %H:%M:%S'"; # ll like tree
|
||||
lp = pkgs.writeShellScript "lp" ''abs="$(cd "$(dirname "$1")" ; pwd)"/"$(basename "$1")" ; ${pkgs.util-linux}/bin/namei -lx "$abs"''; # similar to »ll -d« on all path element from »$1« to »/«
|
||||
|
||||
ips = "ip -c -br addr"; # colorized listing of all interface's IPs
|
||||
mounts = pkgs.writeShellScript "mounts" ''${pkgs.util-linux}/bin/mount | ${pkgs.gnugrep}/bin/grep -vPe '/.zfs/snapshot/| on /var/lib/docker/|^/var/lib/snapd/snaps/' | LC_ALL=C ${pkgs.coreutils}/bin/sort -k3 | ${pkgs.util-linux}/bin/column -t -N Device/Source,on,Mountpoint,type,Type,Options -H on,type -W Device/Source,Mountpoint,Options''; # the output of »mount«, cleaned up and formatted as a sorted table
|
||||
|
||||
netns-exec = pkgs.writeShellScript "netns-exec" ''ns=$1 ; shift ; /run/wrappers/bin/firejail --noprofile --quiet --netns="$ns" -- "$@"''; # execute a command in a different netns (like »ip netns exec«), without requiring root permissions (but does require »config.programs.firejail.enable=true«)
|
||||
|
||||
nixos-list-generations = "nix-env --list-generations --profile /nix/var/nix/profiles/system";
|
||||
|
||||
sc = "systemctl";
|
||||
scs = "systemctl status";
|
||||
scc = "systemctl cat";
|
||||
scu = "systemctl start"; # up
|
||||
scd = "systemctl stop"; # down
|
||||
scr = "systemctl restart";
|
||||
scf = "systemctl list-units --failed";
|
||||
scj = "journalctl -b -f -u";
|
||||
|
||||
};
|
||||
|
||||
programs.bash.promptInit = ''
|
||||
# Provide a nice prompt if the terminal supports it.
|
||||
if [ "''${TERM:-}" != "dumb" ] ; then
|
||||
if [[ "$UID" == '0' ]] ; then if [[ ! "''${SUDO_USER:-}" ]] ; then # direct root: red username + green hostname
|
||||
@ -114,7 +159,7 @@ in {
|
||||
export TERM_RECURSION_DEPTH=$(( 1 + ''${TERM_RECURSION_DEPTH:-0} ))
|
||||
''; # The non-interactive version of bash does not remove »\[« and »\]« from PS1, but without those the terminal gets confused about the cursor position after the prompt once one types more than a bit of text there (at least via serial or SSH).
|
||||
|
||||
environment.interactiveShellInit = lib.mkDefault ''
|
||||
environment.interactiveShellInit = lib.mkBefore ''
|
||||
# In RePl mode: remove duplicates from history; don't save commands with a leading space.
|
||||
HISTCONTROL=ignoredups:ignorespace
|
||||
|
||||
@ -123,14 +168,15 @@ in {
|
||||
stty rows 34 cols 145 # Fairly large font on 1080p. (Setting this too large for the screen warps the output really badly.)
|
||||
fi
|
||||
'';
|
||||
|
||||
system.extraSystemBuilderCmds = (if !config.boot.initrd.enable then "" else ''
|
||||
ln -sT ${builtins.unsafeDiscardStringContext config.system.build.bootStage1} $out/boot-stage-1.sh # (this is super annoying to locate otherwise)
|
||||
'');
|
||||
|
||||
# deactivate by setting »system.activationScripts.diff-systems = lib.mkForce "";«
|
||||
system.activationScripts.diff-systems = ''
|
||||
if [[ -e /run/current-system ]] ; then ${pkgs.nix}/bin/nix --extra-experimental-features nix-command store diff-closures /run/current-system "$systemConfig" ; fi
|
||||
}) (lib.mkIf (cfg.bashInit) { # other »interactiveShellInit« (and »shellAliases«) would go in here, being able to overwrite stuff from above, but still also being included in the alias completion below
|
||||
environment.interactiveShellInit = lib.mkAfter ''
|
||||
# enable completion for aliases
|
||||
source ${ pkgs.fetchFromGitHub {
|
||||
owner = "cykerway"; repo = "complete-alias";
|
||||
rev = "4fcd018faa9413e60ee4ec9f48ebeac933c8c372"; # v1.18 (2021-07-17)
|
||||
sha256 = "sha256-fZisrhdu049rCQ5Q90sFWFo8GS/PRgS29B1eG8dqlaI=";
|
||||
} }/complete_alias
|
||||
complete -F _complete_alias "''${!BASH_ALIASES[@]}"
|
||||
'';
|
||||
|
||||
}) ]);
|
||||
|
@ -24,9 +24,11 @@ in {
|
||||
|
||||
options.${prefix} = { bootloader.extlinux = {
|
||||
enable = lib.mkEnableOption (lib.mdDoc ''
|
||||
a simple bootloader for legacy-BIOS environments, like (by default) Qemu.
|
||||
extlinux, a simple bootloader for legacy-BIOS environments, like (by default) Qemu.
|
||||
This uses the same implementation as `boot.loader.generic-extlinux-compatible` to generate the bootloader configuration, but then actually also installs `extlinux` itself, instead of relying on something else (like an externally installed u-boot) to read and execute the configuration.
|
||||
Any options affecting the config file generation by `boot.loader.generic-extlinux-compatible` apply, but `boot.loader.generic-extlinux-compatible.enable` should not be set to `true`.
|
||||
|
||||
Since the bootloader runs before selecting a generation or specialisation to run, all sub-options, similar to e.g. {option}`boot.loader.timeout`, apply globally to the system, from whichever configuration last applied its bootloader (e.g. by newly `nixos-rebuild switch/boot`ing it or by calling its `.../bin/switch-to-configuration switch/boot`)
|
||||
'');
|
||||
package = lib.mkOption { description = lib.mdDoc ''
|
||||
The `syslinux` package to install `extlinux` from use.
|
||||
@ -38,13 +40,15 @@ in {
|
||||
The `/dev/disk/by-{id,label,partlabel,partuuid,uuid}/*` path of the *disk partition* holding the filesystem that `extlinux` is installed to. This must be formatted with a filesystem that `extlinux` supports and mounted as (a parent of) {option}`.targetDir`. The disk on which the partition lies will have the bootloader section of its MBR replaced by `extlinux`'s.
|
||||
''; type = lib.types.strMatching ''^/.*[^/]$''; default = targetMount.device; };
|
||||
allowInstableTargetPart = lib.mkOption { internal = true; type = lib.types.bool; };
|
||||
showUI = (lib.mkEnableOption (lib.mdDoc "a simple graphical user interface to select the configuration to start during early boot.")) // { default = true; example = false; };
|
||||
showUI = (lib.mkEnableOption (lib.mdDoc ''
|
||||
a simple graphical user interface to select the configuration to start during early boot
|
||||
'')) // { default = true; example = false; };
|
||||
}; };
|
||||
|
||||
config = let
|
||||
|
||||
confFile = "/nixos/modules/system/boot/loader/generic-extlinux-compatible";
|
||||
writeConfig = (import "${inputs.nixpkgs}/${confFile}" { inherit config pkgs lib; }).config.content.system.build.installBootLoader;
|
||||
generic-extlinux-compatible = "${inputs.nixpkgs}/nixos/modules/system/boot/loader/generic-extlinux-compatible";
|
||||
extlinux-conf-builder = (import generic-extlinux-compatible { inherit config pkgs lib; }).config.content.system.build.installBootLoader;
|
||||
|
||||
esc = lib.escapeShellArg;
|
||||
|
||||
@ -52,10 +56,14 @@ in {
|
||||
|
||||
assertions = [ {
|
||||
assertion = cfg.allowInstableTargetPart || (builtins.match ''^/dev/disk/by-(id|label|partlabel|partuuid|uuid)/.*[^/]$'' cfg.targetPart) != null;
|
||||
message = ''`config.${prefix}.bootloader.extlinux.targetPart` is not set to a stable path in `/dev/disk/by-{id,label,partlabel,partuuid,uuid}/`. Not using a unique identifier (or even using a path that can unexpectedly change) is very risky.'';
|
||||
message = ''
|
||||
`config.${prefix}.bootloader.extlinux.targetPart` is not set to a stable path in `/dev/disk/by-{id,label,partlabel,partuuid,uuid}/`. Not using a unique identifier (or even using a path that can unexpectedly change) is very risky.
|
||||
'';
|
||||
} {
|
||||
assertion = fsSupported targetMount.fsType;
|
||||
message = ''`config.${prefix}.bootloader.extlinux.targetPart`'s closest mount (`${targetMount.mountPoint}`) is of type `${targetMount.fsType}`, which is not one of extlinux's supported types (${lib.concatStringsSep ", " supportedFSes}).'';
|
||||
message = ''
|
||||
`config.${prefix}.bootloader.extlinux.targetPart`'s closest mount (`${targetMount.mountPoint}`) is of type `${targetMount.fsType}`, which is not one of extlinux's supported types (${lib.concatStringsSep ", " supportedFSes}).
|
||||
'';
|
||||
} ];
|
||||
|
||||
${prefix} = {
|
||||
@ -65,7 +73,8 @@ in {
|
||||
|
||||
system.boot.loader.id = "extlinux";
|
||||
system.build.installBootLoader = "${pkgs.writeShellScript "install-extlinux.sh" ''
|
||||
${writeConfig} "$1" -d ${esc cfg.targetDir}
|
||||
if [[ ! ''${1:-} || $1 != /nix/store/* ]] ; then echo "Usage: $0 TOPLEVEL_PATH" ; exit 1 ; fi
|
||||
${extlinux-conf-builder} "$1" -d ${esc cfg.targetDir}
|
||||
|
||||
partition=${esc cfg.targetPart}
|
||||
diskDev=$( realpath "$partition" ) || exit ; if [[ $diskDev == /dev/sd* ]] ; then
|
||||
@ -75,7 +84,9 @@ in {
|
||||
fi
|
||||
|
||||
if [[ $( cat ${esc cfg.targetDir}/extlinux/installedVersion 2>/dev/null || true ) != ${esc cfg.package} ]] ; then
|
||||
${esc cfg.package}/bin/extlinux --install ${esc cfg.targetDir}/extlinux || exit
|
||||
if ! output=$( ${esc cfg.package}/bin/extlinux --install --heads=64 --sectors=32 ${esc cfg.targetDir}/extlinux 2>&1 ) ; then
|
||||
printf '%s\n' "$output" ; exit 1
|
||||
fi
|
||||
printf '%s\n' ${esc cfg.package} >${esc cfg.targetDir}/extlinux/installedVersion
|
||||
fi
|
||||
if ! ${pkgs.diffutils}/bin/cmp --quiet --bytes=440 $diskDev ${esc cfg.package}/share/syslinux/mbr.bin ; then
|
||||
@ -88,9 +99,11 @@ in {
|
||||
cp ${esc cfg.package}/share/syslinux/$lib.c32 ${esc cfg.targetDir}/extlinux/$lib.c32
|
||||
fi
|
||||
done
|
||||
if ! ${pkgs.gnugrep}/bin/grep -qP '^UI $' ${esc cfg.targetDir}/extlinux/extlinux.conf ; then
|
||||
if ! ${pkgs.gnugrep}/bin/grep -qP '^UI ' ${esc cfg.targetDir}/extlinux/extlinux.conf ; then # `extlinux-conf-builder` above would have recreated this, so the check should always be true
|
||||
${pkgs.perl}/bin/perl -i -pe 's/TIMEOUT/UI menu.c32\nTIMEOUT/' ${esc cfg.targetDir}/extlinux/extlinux.conf
|
||||
fi
|
||||
else
|
||||
: # delete library files?
|
||||
fi
|
||||
''}";
|
||||
|
||||
|
@ -74,7 +74,7 @@ in {
|
||||
esc = lib.escapeShellArg;
|
||||
in pkgs.runCommand "partitioning-${config.networking.hostName}" { } ''
|
||||
${lib.wip.substituteImplicit { inherit pkgs; scripts = [ partition-disk ]; context = { inherit config; native = pkgs; }; }} # inherit (builtins) trace;
|
||||
mkdir $out ; declare -A args=([debug]=1)
|
||||
set -u ; mkdir -p $out ; declare -A args=([debug]=1)
|
||||
${lib.concatStrings (lib.mapAttrsToList (name: disk: ''
|
||||
name=${esc name} ; img=$name.img
|
||||
${pkgs.coreutils}/bin/truncate -s ${esc disk.size} "$img"
|
||||
|
@ -81,8 +81,8 @@ On a less beefy system, but also with less data to manage, `tmpfs` works fine fo
|
||||
#wip.fs.keystore.keys."luks/local-${hash}/0" = "random"; # (implied by the »-encrypted« suffix above)
|
||||
#wip.fs.disks.partitions."local-${hash}".size = "50%"; # (default, fixed after installation)
|
||||
wip.fs.temproot.remote.type = "zfs";
|
||||
wip.fs.keystore.keys."luks/rpool-${hash}/0" = "random";
|
||||
#wip.fs.keystore.keys."zfs/rpool-${hash}/remote" = "random"; # (default)
|
||||
#wip.fs.keystore.keys."luks/rpool-${hash}/0" = "random"; # Would also enable LUKS encryption of the pool, but there isn't too much point in encrypting twice.
|
||||
#wip.fs.zfs.pools."rpool-${hash}".vdevArgs = [ "rpool-${hash}" ]; # (default)
|
||||
#wip.fs.disks.partitions."rpool-${hash}" = { type = "bf00"; size = null; order = 500; }; # (default)
|
||||
|
||||
@ -322,7 +322,12 @@ in {
|
||||
boot.initrd.kernelModules = [ type ]; # This is not generally, but sometimes, required to boot. Strange. (Kernel message: »request_module fs-f2fs succeeded, but still no fs?«)
|
||||
|
||||
|
||||
})) ] ++ (map (type: (lib.mkIf (cfg.${type}.type == "bind") {
|
||||
})) (lib.mkIf (cfg.remote.type == "none") {
|
||||
|
||||
systemd.tmpfiles.rules = [ (lib.wip.mkTmpfile { type = "L+"; path = "/remote"; argument = "/local"; }) ]; # for compatibility (but use a symlink to make clear that this is not actually a separate mount)
|
||||
|
||||
|
||||
}) ] ++ (map (type: (lib.mkIf (cfg.${type}.type == "bind") {
|
||||
|
||||
fileSystems = (lib.mapAttrs (target: args@{ source, uid, gid, mode, extraFsConfig, ... }: extraFsConfig // (rec {
|
||||
device = "${cfg.${type}.bind.source}/${source}";
|
||||
|
@ -11,9 +11,12 @@ GPT-FDisk patched to be able to move not only the primary, but also the backup p
|
||||
#*/# end of MarkDown, beginning of NixPkgs overlay:
|
||||
dirname: inputs: final: prev: let
|
||||
inherit (final) pkgs; inherit (inputs.self) lib;
|
||||
debug = false;
|
||||
in {
|
||||
|
||||
gptfdisk = prev.gptfdisk.overrideAttrs (old: let
|
||||
gptfdisk = (
|
||||
if debug then pkgs.enableDebugging else (x: x)
|
||||
) (prev.gptfdisk.overrideAttrs (old: let
|
||||
pname = "gptfdisk";
|
||||
in rec {
|
||||
version = "1.0.9";
|
||||
@ -21,10 +24,12 @@ in {
|
||||
url = "https://downloads.sourceforge.net/gptfdisk/${pname}-${version}.tar.gz";
|
||||
sha256 = "1hjh5m77fmfq5m44yy61kchv7mbfgx026aw3jy5qxszsjckavzns";
|
||||
};
|
||||
/* patches = [ # (don't include »old.patches«, as the only one was upstreamed)
|
||||
patches = [ # (don't include »old.patches«, as the only one was upstreamed in v1.0.9)
|
||||
../patches/gptfdisk-move-secondary-table.patch
|
||||
]; */
|
||||
});
|
||||
];
|
||||
} // (if debug then {
|
||||
dontStrip = true;
|
||||
} else { })));
|
||||
|
||||
libblockdev = prev.libblockdev.override { inherit (prev) gptfdisk; };
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
diff --git a/gpt.cc b/gpt.cc
|
||||
index 76cd9ad..d61064f 100644
|
||||
index 76cd9ad..4798db2 100644
|
||||
--- a/gpt.cc
|
||||
+++ b/gpt.cc
|
||||
@@ -1500,7 +1500,7 @@ int GPTData::DestroyGPT(void) {
|
||||
@ -35,7 +35,15 @@ index 76cd9ad..d61064f 100644
|
||||
// Blank the partition array
|
||||
void GPTData::BlankPartitions(void) {
|
||||
uint32_t i;
|
||||
@@ -2285,7 +2302,7 @@ uint64_t GPTData::FindFirstAvailable(uint64_t start) {
|
||||
@@ -2066,6 +2083,7 @@ void GPTData::MoveSecondHeaderToEnd() {
|
||||
} // if
|
||||
mainHeader.lastUsableLBA = secondHeader.lastUsableLBA = diskSize - mainHeader.firstUsableLBA;
|
||||
secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1);
|
||||
+ // TODO: Whenever this gets called, it moves the backup table to be the same distance from the backup header as the primary one it from its header. This seems highly problematic, since MoveMainTable does not call this, but then further actions may or may not do so. Moving the primary table may thus imply moving the backup table, or it may leave it where it was. There is also no guarantee that the space where the backup table is moved to is actually available.
|
||||
} // GPTData::FixSecondHeaderLocation()
|
||||
|
||||
// Sets the partition's name to the specified UnicodeString without
|
||||
@@ -2285,7 +2303,7 @@ uint64_t GPTData::FindFirstAvailable(uint64_t start) {
|
||||
} // GPTData::FindFirstAvailable()
|
||||
|
||||
// Returns the LBA of the start of the first partition on the disk (by
|
||||
@ -44,7 +52,7 @@ index 76cd9ad..d61064f 100644
|
||||
uint64_t GPTData::FindFirstUsedLBA(void) {
|
||||
uint32_t i;
|
||||
uint64_t firstFound = UINT64_MAX;
|
||||
@@ -2298,6 +2315,20 @@ uint64_t GPTData::FindFirstUsedLBA(void) {
|
||||
@@ -2298,6 +2316,20 @@ uint64_t GPTData::FindFirstUsedLBA(void) {
|
||||
return firstFound;
|
||||
} // GPTData::FindFirstUsedLBA()
|
||||
|
||||
@ -95,7 +103,7 @@ index 5d19372..17b3380 100644
|
||||
uint64_t FindLastAvailable();
|
||||
uint64_t FindLastInFree(uint64_t start, bool align = false);
|
||||
diff --git a/gptcl.cc b/gptcl.cc
|
||||
index 34c9421..232285a 100644
|
||||
index 34c9421..f4361b7 100644
|
||||
--- a/gptcl.cc
|
||||
+++ b/gptcl.cc
|
||||
@@ -68,7 +68,7 @@ int GPTDataCL::DoOptions(int argc, char* argv[]) {
|
||||
@ -134,6 +142,20 @@ index 34c9421..232285a 100644
|
||||
};
|
||||
|
||||
// Create popt context...
|
||||
@@ -156,12 +158,12 @@ int GPTDataCL::DoOptions(int argc, char* argv[]) {
|
||||
|
||||
// Assume first non-option argument is the device filename....
|
||||
device = (char*) poptGetArg(poptCon);
|
||||
- poptResetContext(poptCon);
|
||||
|
||||
if (device != NULL) {
|
||||
JustLooking(); // reset as necessary
|
||||
BeQuiet(); // Tell called functions to be less verbose & interactive
|
||||
if (LoadPartitions((string) device)) {
|
||||
+ device = NULL; poptResetContext(poptCon);
|
||||
if ((WhichWasUsed() == use_mbr) || (WhichWasUsed() == use_bsd))
|
||||
saveNonGPT = 0; // flag so we don't overwrite unless directed to do so
|
||||
sSize = GetBlockSize();
|
||||
@@ -280,13 +282,21 @@ int GPTDataCL::DoOptions(int argc, char* argv[]) {
|
||||
alignEnd = true;
|
||||
break;
|
||||
@ -246,6 +268,49 @@ index 32e2f88..8ed6274 100644
|
||||
void CreatePartition(void);
|
||||
void DeletePartition(void);
|
||||
void ChangePartType(void);
|
||||
diff --git a/guid.cc b/guid.cc
|
||||
index 1e73ab7..387019a 100644
|
||||
--- a/guid.cc
|
||||
+++ b/guid.cc
|
||||
@@ -139,29 +139,28 @@ void GUIDData::Zero(void) {
|
||||
// (immediately after creating the UUID on Windows 7 being an important
|
||||
// exception).
|
||||
void GUIDData::Randomize(void) {
|
||||
- int i, uuidGenerated = 0;
|
||||
|
||||
-#ifdef _UUID_UUID_H
|
||||
+#ifndef _WIN32
|
||||
uuid_generate(uuidData);
|
||||
ReverseBytes(&uuidData[0], 4);
|
||||
ReverseBytes(&uuidData[4], 2);
|
||||
ReverseBytes(&uuidData[6], 2);
|
||||
- uuidGenerated = 1;
|
||||
-#endif
|
||||
+#else
|
||||
+
|
||||
#if defined (_RPC_H) || defined (__RPC_H__)
|
||||
UUID MsUuid;
|
||||
if (UuidCreate(&MsUuid) == RPC_S_OK) {
|
||||
memcpy(uuidData, &MsUuid, 16);
|
||||
uuidGenerated = 1;
|
||||
} // if
|
||||
+#else
|
||||
+ cerr << "Warning! Unable to generate a proper UUID! Creating an improper one as a last\n"
|
||||
+ << "resort! Windows 7 may crash if you save this partition table!\a\n";
|
||||
+ for (int i = 0; i < 16; i++)
|
||||
+ uuidData[i] = (unsigned char) (256.0 * (rand() / (RAND_MAX + 1.0)));
|
||||
+#endif
|
||||
#endif
|
||||
|
||||
- if (!uuidGenerated) {
|
||||
- cerr << "Warning! Unable to generate a proper UUID! Creating an improper one as a last\n"
|
||||
- << "resort! Windows 7 may crash if you save this partition table!\a\n";
|
||||
- for (i = 0; i < 16; i++)
|
||||
- uuidData[i] = (unsigned char) (256.0 * (rand() / (RAND_MAX + 1.0)));
|
||||
- } // if
|
||||
} // GUIDData::Randomize
|
||||
|
||||
// Equality operator; returns 1 if the GUIDs are equal, 0 if they're unequal
|
||||
diff --git a/sgdisk.8 b/sgdisk.8
|
||||
index b966a13..6f8b375 100644
|
||||
--- a/sgdisk.8
|
||||
|
Loading…
Reference in New Issue
Block a user