crypt_reboot 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +169 -0
- data/exe/cryptreboot +9 -0
- data/lib/basic_loader.rb +60 -0
- data/lib/crypt_reboot/boot_config.rb +24 -0
- data/lib/crypt_reboot/cli/exiter.rb +25 -0
- data/lib/crypt_reboot/cli/happy_exiter.rb +14 -0
- data/lib/crypt_reboot/cli/params/definition.rb +125 -0
- data/lib/crypt_reboot/cli/params/flattener.rb +24 -0
- data/lib/crypt_reboot/cli/params/help_generator.rb +22 -0
- data/lib/crypt_reboot/cli/params/parser.rb +29 -0
- data/lib/crypt_reboot/cli/params_parsing_executor.rb +73 -0
- data/lib/crypt_reboot/cli/sad_exiter.rb +14 -0
- data/lib/crypt_reboot/cli.rb +8 -0
- data/lib/crypt_reboot/concatenator.rb +24 -0
- data/lib/crypt_reboot/config.rb +20 -0
- data/lib/crypt_reboot/crypt_tab/deserializer.rb +28 -0
- data/lib/crypt_reboot/crypt_tab/entry.rb +39 -0
- data/lib/crypt_reboot/crypt_tab/entry_deserializer.rb +51 -0
- data/lib/crypt_reboot/crypt_tab/entry_serializer.rb +21 -0
- data/lib/crypt_reboot/crypt_tab/keyfile_locator.rb +21 -0
- data/lib/crypt_reboot/crypt_tab/luks_to_plain_converter.rb +39 -0
- data/lib/crypt_reboot/crypt_tab/serializer.rb +29 -0
- data/lib/crypt_reboot/files_generator.rb +44 -0
- data/lib/crypt_reboot/files_writer.rb +17 -0
- data/lib/crypt_reboot/gziper.rb +22 -0
- data/lib/crypt_reboot/initramfs/archiver.rb +35 -0
- data/lib/crypt_reboot/initramfs/decompressor/intolerant_decompressor.rb +65 -0
- data/lib/crypt_reboot/initramfs/decompressor/tolerant_decompressor.rb +28 -0
- data/lib/crypt_reboot/initramfs/decompressor.rb +12 -0
- data/lib/crypt_reboot/initramfs/extractor.rb +36 -0
- data/lib/crypt_reboot/initramfs/patcher.rb +47 -0
- data/lib/crypt_reboot/initramfs_patch_squeezer.rb +28 -0
- data/lib/crypt_reboot/instantiable_config.rb +52 -0
- data/lib/crypt_reboot/kexec/loader.rb +30 -0
- data/lib/crypt_reboot/kexec_patching_loader.rb +28 -0
- data/lib/crypt_reboot/lazy_config.rb +22 -0
- data/lib/crypt_reboot/luks/checker.rb +27 -0
- data/lib/crypt_reboot/luks/data.rb +37 -0
- data/lib/crypt_reboot/luks/data_fetcher.rb +30 -0
- data/lib/crypt_reboot/luks/dumper/luks_v1_parser.rb +64 -0
- data/lib/crypt_reboot/luks/dumper/luks_v2_parser.rb +62 -0
- data/lib/crypt_reboot/luks/dumper.rb +30 -0
- data/lib/crypt_reboot/luks/key_fetcher.rb +50 -0
- data/lib/crypt_reboot/luks/version_detector.rb +32 -0
- data/lib/crypt_reboot/passphrase_asker.rb +15 -0
- data/lib/crypt_reboot/patched_initramfs_generator.rb +21 -0
- data/lib/crypt_reboot/rebooter.rb +20 -0
- data/lib/crypt_reboot/runner/binary.rb +12 -0
- data/lib/crypt_reboot/runner/boolean.rb +18 -0
- data/lib/crypt_reboot/runner/generic.rb +46 -0
- data/lib/crypt_reboot/runner/lines.rb +13 -0
- data/lib/crypt_reboot/runner/no_result.rb +13 -0
- data/lib/crypt_reboot/runner/text.rb +12 -0
- data/lib/crypt_reboot/runner.rb +8 -0
- data/lib/crypt_reboot/safe_temp/directory.rb +28 -0
- data/lib/crypt_reboot/safe_temp/file_name.rb +23 -0
- data/lib/crypt_reboot/safe_temp/mounter.rb +33 -0
- data/lib/crypt_reboot/single_assign_restricted_map.rb +26 -0
- data/lib/crypt_reboot/version.rb +5 -0
- data/lib/crypt_reboot.rb +17 -0
- metadata +138 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 449c9b12be881f213dffc9090686e7d73bb3f2523806c5edf41dc2e4d7d17c4b
|
4
|
+
data.tar.gz: ba391871d8d5f438ba2474a8a21d8738be020636ac8c4bfcd0fd8100d7e07aec
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 466befee2a5027cae8be7cb036c87e8c779e64fb4725775111b112e53ff5bf2691bc543ac86e7c229e8e75642c0c3eb0168fed1bca14a2b0598b94bf3c5245c0
|
7
|
+
data.tar.gz: 68bef507bea7444722f3281b94d8ea5af0bda0d031871f82fc9ff0398614e7b83564f2b541a42d745d2eefecde9f0a409817dcd29332b01797cd13b434bd7db0
|
data/CHANGELOG.md
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2023 Paweł Pokrywka
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
# Cryptreboot
|
2
|
+
|
3
|
+
Convenient reboot for Linux systems with encrypted root partition.
|
4
|
+
|
5
|
+
> Just type `cryptreboot` instead of `reboot`.
|
6
|
+
|
7
|
+
It asks for a passphrase and reboots the system afterward, automatically
|
8
|
+
unlocking the drive on startup using in-memory initramfs patching and kexec.
|
9
|
+
Without explicit consent, no secrets are stored on disk, even temporarily.
|
10
|
+
|
11
|
+
Useful when unlocking the drive at startup is difficult, such as on headless
|
12
|
+
and remote systems.
|
13
|
+
|
14
|
+
By default, it uses the current kernel command line, `/boot/vmlinuz` as kernel
|
15
|
+
and `/boot/initrd.img` as initramfs.
|
16
|
+
|
17
|
+
Will work properly when using standard passphrase-based disk unlocking.
|
18
|
+
Fancy methods such as using an external USB with a passphrase file will fail.
|
19
|
+
|
20
|
+
## Compatible Linux distributions
|
21
|
+
|
22
|
+
Currently, cryptreboot depends on `initramfs-tools` package which is available in
|
23
|
+
Debian-based distributions. Therefore one should expect, this tool to work on
|
24
|
+
Debian, Ubuntu, Linux Mint, Pop!_OS, etc.
|
25
|
+
|
26
|
+
On the other hand, do not expect it to work on other distributions now.
|
27
|
+
But support for them may come in upcoming versions.
|
28
|
+
|
29
|
+
Following distributions were tested by the author:
|
30
|
+
- Ubuntu 22.04 LTS
|
31
|
+
- Ubuntu 20.04 LTS needs tiny adjustments to system settings,
|
32
|
+
specifically [changing compression](#lz4-initramfs-compression) and
|
33
|
+
[fixing systemd kexec support](#staged-kernel-not-being-executed-by-systemd)
|
34
|
+
- ~~Ubuntu 18.04 LTS~~ is not supported (initramfs uses *pre-crypttab* format)
|
35
|
+
- Pop!_OS 22.04 LTS
|
36
|
+
|
37
|
+
If you have successfully run cryptreboot on another distribution,
|
38
|
+
please contact me and I will update the list.
|
39
|
+
|
40
|
+
## Requirements
|
41
|
+
|
42
|
+
You need to ensure those are installed:
|
43
|
+
- `ruby` >= 2.7
|
44
|
+
- `kexec-tools`
|
45
|
+
- `initramfs-tools` (other initramfs generators, such as `dracut` are
|
46
|
+
not supported yet)
|
47
|
+
|
48
|
+
If you use recent, mainstream Linux distribution, other requirements are
|
49
|
+
probably already met:
|
50
|
+
- `kexec` support in the kernel
|
51
|
+
- `tmpfs` filesystem support in kernel
|
52
|
+
- `cryptsetup` (if you use disk encryption, it should be installed)
|
53
|
+
- `systemd` or another way to guarantee staged kernel is executed on reboot
|
54
|
+
- `strace` (not required if `--skip-lz4-check` flag is specified)
|
55
|
+
|
56
|
+
## Installation
|
57
|
+
|
58
|
+
Make sure the required software is installed, then install the gem by executing:
|
59
|
+
|
60
|
+
$ gem install crypt_reboot
|
61
|
+
|
62
|
+
## Usage
|
63
|
+
|
64
|
+
Cryptreboot performs operations normally only available to the root user,
|
65
|
+
so it is suggested to use sudo or a similar utility.
|
66
|
+
|
67
|
+
To perform a reboot type:
|
68
|
+
|
69
|
+
$ sudo cryptreboot
|
70
|
+
|
71
|
+
To see the usage, run:
|
72
|
+
|
73
|
+
$ cryptreboot --help
|
74
|
+
|
75
|
+
## Resolutions for common issues
|
76
|
+
|
77
|
+
### LZ4 initramfs compression
|
78
|
+
|
79
|
+
If you get:
|
80
|
+
|
81
|
+
> LZ4 compression is not allowed, change the compression algorithm in
|
82
|
+
initramfs.conf and regenerate the initramfs image
|
83
|
+
|
84
|
+
it means initramfs was compressed using the LZ4 algorithm, which seems to
|
85
|
+
have issues with concatenating initramfs images.
|
86
|
+
|
87
|
+
In case you are 100% sure LZ4 won't cause problems, you can use
|
88
|
+
`--skip-lz4-check` command line flag. This will make the error message
|
89
|
+
go away, but you risk automatic disk unlocking at startup to fail randomly.
|
90
|
+
|
91
|
+
Instead, the recommended approach is to change the compression algorithm
|
92
|
+
in `/etc/initramfs-tools/initramfs.conf` file. Look for `COMPRESS` and
|
93
|
+
set it to some other value such as `gzip` (the safe choice), or `zstd`
|
94
|
+
(the best compression, but your kernel and `initramfs-tools` need to support it).
|
95
|
+
|
96
|
+
Here is a one-liner to change compression to `gzip`:
|
97
|
+
|
98
|
+
$ sudo sed -iE 's/^\s*COMPRESS=.*$/COMPRESS=gzip/' /etc/initramfs-tools/initramfs.conf
|
99
|
+
|
100
|
+
Then you need to regenerate all of your initramfs images:
|
101
|
+
|
102
|
+
$ sudo update-initramfs -k all -u
|
103
|
+
|
104
|
+
That's it.
|
105
|
+
|
106
|
+
Resources related to the issue:
|
107
|
+
- [Appending files to initramfs image - reliable? (StackExchange)](https://unix.stackexchange.com/a/737219)
|
108
|
+
- [What is the correct frame format for Linux (Lz4 issue)](https://github.com/lz4/lz4/issues/956)
|
109
|
+
- [Initramfs unpacking failed (Ubuntu bug report)](https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1835660)
|
110
|
+
|
111
|
+
### Staged kernel not being executed by systemd
|
112
|
+
|
113
|
+
If rebooting with cryptreboot doesn't seem to differ from a standard
|
114
|
+
reboot, it may suggest staged kernel is not being executed by the
|
115
|
+
`systemd` at the end of the shutdown procedure.
|
116
|
+
|
117
|
+
The solution I found is to execute `kexec -e` instead of
|
118
|
+
`systemctl --force kexec` when the system is ready for a reboot.
|
119
|
+
To do that `systemd-kexec.service` has to be modified.
|
120
|
+
To make the change minimal, let's use `systemd drop-in` for that:
|
121
|
+
|
122
|
+
$ sudo mkdir -p /etc/systemd/system/systemd-kexec.service.d/
|
123
|
+
$ echo -e "[Service]\nExecStart=\nExecStart=kexec -e" | sudo tee /etc/systemd/system/systemd-kexec.service.d/override.conf
|
124
|
+
|
125
|
+
That should work.
|
126
|
+
|
127
|
+
To cancel the change, remove the file:
|
128
|
+
|
129
|
+
$ sudo rm /etc/systemd/system/systemd-kexec.service.d/override.conf
|
130
|
+
|
131
|
+
## Development
|
132
|
+
|
133
|
+
After checking out the repo, run `bundle install` to install
|
134
|
+
dependencies. Then, run `rake spec` to run the tests. You can also
|
135
|
+
run `bin/console` for an interactive prompt that will allow you
|
136
|
+
to experiment.
|
137
|
+
|
138
|
+
To build the gem, run `rake build`. To release a new version, update
|
139
|
+
the version number in `version.rb`, and then run `rake release`, which
|
140
|
+
will create a git tag for the version, push git commits and the created
|
141
|
+
tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
142
|
+
|
143
|
+
## Contributing
|
144
|
+
|
145
|
+
Bug reports and pull requests are welcome on GitHub at
|
146
|
+
https://github.com/phantom-node/cryptreboot.
|
147
|
+
This project is intended to be a safe, welcoming space for collaboration,
|
148
|
+
and contributors are expected to adhere to the
|
149
|
+
[code of conduct](https://github.com/phantom-node/cryptreboot/blob/master/CODE_OF_CONDUCT.md).
|
150
|
+
|
151
|
+
## Author
|
152
|
+
|
153
|
+
My name is Paweł Pokrywka and I'm the author of cryptreboot.
|
154
|
+
|
155
|
+
If you want to contact me or get to know me better, check out
|
156
|
+
[my blog](https://blog.pawelpokrywka.com).
|
157
|
+
|
158
|
+
Thank you for your interest in this project :)
|
159
|
+
|
160
|
+
## License
|
161
|
+
|
162
|
+
The software is available as open source under the terms of the
|
163
|
+
[MIT License](https://opensource.org/licenses/MIT).
|
164
|
+
|
165
|
+
## Code of Conduct
|
166
|
+
|
167
|
+
Everyone interacting in the Cryptreboot project's codebases, issue
|
168
|
+
trackers, chat rooms, and mailing lists is expected to follow the
|
169
|
+
[code of conduct](https://github.com/phantom-node/cryptreboot/blob/master/CODE_OF_CONDUCT.md).
|
data/exe/cryptreboot
ADDED
data/lib/basic_loader.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# File generated automatically, do not edit
|
4
|
+
|
5
|
+
require 'crypt_reboot/version'
|
6
|
+
require 'crypt_reboot/boot_config'
|
7
|
+
require 'crypt_reboot/cli'
|
8
|
+
require 'crypt_reboot/concatenator'
|
9
|
+
require 'crypt_reboot/instantiable_config'
|
10
|
+
require 'crypt_reboot/config'
|
11
|
+
require 'crypt_reboot/files_generator'
|
12
|
+
require 'crypt_reboot/files_writer'
|
13
|
+
require 'crypt_reboot/gziper'
|
14
|
+
require 'crypt_reboot/initramfs_patch_squeezer'
|
15
|
+
require 'crypt_reboot/kexec_patching_loader'
|
16
|
+
require 'crypt_reboot/lazy_config'
|
17
|
+
require 'crypt_reboot/passphrase_asker'
|
18
|
+
require 'crypt_reboot/patched_initramfs_generator'
|
19
|
+
require 'crypt_reboot/rebooter'
|
20
|
+
require 'crypt_reboot/runner'
|
21
|
+
require 'crypt_reboot/single_assign_restricted_map'
|
22
|
+
require 'crypt_reboot/cli/exiter'
|
23
|
+
require 'crypt_reboot/cli/happy_exiter'
|
24
|
+
require 'crypt_reboot/cli/params_parsing_executor'
|
25
|
+
require 'crypt_reboot/cli/sad_exiter'
|
26
|
+
require 'crypt_reboot/crypt_tab/deserializer'
|
27
|
+
require 'crypt_reboot/crypt_tab/entry'
|
28
|
+
require 'crypt_reboot/crypt_tab/entry_deserializer'
|
29
|
+
require 'crypt_reboot/crypt_tab/entry_serializer'
|
30
|
+
require 'crypt_reboot/crypt_tab/keyfile_locator'
|
31
|
+
require 'crypt_reboot/crypt_tab/luks_to_plain_converter'
|
32
|
+
require 'crypt_reboot/crypt_tab/serializer'
|
33
|
+
require 'crypt_reboot/initramfs/archiver'
|
34
|
+
require 'crypt_reboot/initramfs/decompressor'
|
35
|
+
require 'crypt_reboot/initramfs/extractor'
|
36
|
+
require 'crypt_reboot/initramfs/patcher'
|
37
|
+
require 'crypt_reboot/kexec/loader'
|
38
|
+
require 'crypt_reboot/luks/checker'
|
39
|
+
require 'crypt_reboot/luks/data'
|
40
|
+
require 'crypt_reboot/luks/data_fetcher'
|
41
|
+
require 'crypt_reboot/luks/dumper'
|
42
|
+
require 'crypt_reboot/luks/key_fetcher'
|
43
|
+
require 'crypt_reboot/luks/version_detector'
|
44
|
+
require 'crypt_reboot/runner/generic'
|
45
|
+
require 'crypt_reboot/runner/binary'
|
46
|
+
require 'crypt_reboot/runner/boolean'
|
47
|
+
require 'crypt_reboot/runner/lines'
|
48
|
+
require 'crypt_reboot/runner/no_result'
|
49
|
+
require 'crypt_reboot/runner/text'
|
50
|
+
require 'crypt_reboot/safe_temp/directory'
|
51
|
+
require 'crypt_reboot/safe_temp/file_name'
|
52
|
+
require 'crypt_reboot/safe_temp/mounter'
|
53
|
+
require 'crypt_reboot/cli/params/definition'
|
54
|
+
require 'crypt_reboot/cli/params/flattener'
|
55
|
+
require 'crypt_reboot/cli/params/help_generator'
|
56
|
+
require 'crypt_reboot/cli/params/parser'
|
57
|
+
require 'crypt_reboot/initramfs/decompressor/intolerant_decompressor'
|
58
|
+
require 'crypt_reboot/initramfs/decompressor/tolerant_decompressor'
|
59
|
+
require 'crypt_reboot/luks/dumper/luks_v1_parser'
|
60
|
+
require 'crypt_reboot/luks/dumper/luks_v2_parser'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CryptReboot
|
4
|
+
# Data required for booting
|
5
|
+
class BootConfig
|
6
|
+
attr_reader :kernel, :initramfs, :cmdline
|
7
|
+
|
8
|
+
def ==(other)
|
9
|
+
kernel == other.kernel && initramfs == other.initramfs && cmdline == other.cmdline
|
10
|
+
end
|
11
|
+
|
12
|
+
def with_initramfs(new_initramfs)
|
13
|
+
self.class.new(kernel: kernel, initramfs: new_initramfs, cmdline: cmdline)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def initialize(kernel:, initramfs: nil, cmdline: nil)
|
19
|
+
@kernel = kernel
|
20
|
+
@initramfs = initramfs
|
21
|
+
@cmdline = cmdline
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CryptReboot
|
4
|
+
module Cli
|
5
|
+
# Print a message and return exit status
|
6
|
+
class Exiter
|
7
|
+
attr_reader :text
|
8
|
+
|
9
|
+
def call
|
10
|
+
stream.puts text.strip if text
|
11
|
+
status
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
attr_reader :status, :stream
|
17
|
+
|
18
|
+
def initialize(text, status:, stream:)
|
19
|
+
@text = text
|
20
|
+
@status = status
|
21
|
+
@stream = stream
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tty-option'
|
4
|
+
|
5
|
+
module CryptReboot
|
6
|
+
module Cli
|
7
|
+
module Params
|
8
|
+
# Definition of options, flags, help and other CLI related things
|
9
|
+
class Definition
|
10
|
+
include TTY::Option
|
11
|
+
|
12
|
+
# rubocop:disable Metrics/BlockLength
|
13
|
+
usage do
|
14
|
+
header 'Reboot for Linux systems with encrypted root partition.'
|
15
|
+
|
16
|
+
program PROGRAM_NAME
|
17
|
+
no_command
|
18
|
+
|
19
|
+
desc 'It asks for a password and reboots the system afterward, automatically unlocking ' \
|
20
|
+
'the drive on startup using in-memory initramfs patching and kexec. ' \
|
21
|
+
'Without explicit consent, no secrets are stored on disk, even temporarily.',
|
22
|
+
'',
|
23
|
+
'Useful when unlocking the drive at startup is difficult, such as on headless and remote systems.',
|
24
|
+
'',
|
25
|
+
"By default, it uses the current kernel command line, \"#{Config.kernel}\" as " \
|
26
|
+
"kernel and \"#{Config.initramfs}\" as initramfs.",
|
27
|
+
'',
|
28
|
+
'It performs operations normally only available to the root user, so it is suggested to use ' \
|
29
|
+
'sudo or a similar utility.'
|
30
|
+
|
31
|
+
example 'Normal usage:',
|
32
|
+
"$ sudo #{PROGRAM_NAME}"
|
33
|
+
example 'Reboot into custom kernel:',
|
34
|
+
"$ sudo #{PROGRAM_NAME} --kernel /boot/vmlinuz.old --initramfs /boot/initrd.old"
|
35
|
+
example 'Specify custom kernel options:',
|
36
|
+
"$ sudo #{PROGRAM_NAME} --cmdline \"root=UUID=d0...a2 ro nomodeset acpi=off\""
|
37
|
+
example 'Prepare to reboot and perform it manually later:',
|
38
|
+
"$ sudo #{PROGRAM_NAME} --prepare-only",
|
39
|
+
'$ sleep 3600 # do anything else in-between',
|
40
|
+
'$ sudo reboot --no-wall --no-wtmp'
|
41
|
+
|
42
|
+
footer 'To report a bug, get support or contribute, please visit the project page:',
|
43
|
+
'https://phantomno.de/cryptreboot',
|
44
|
+
'',
|
45
|
+
"Thank you for using #{PROGRAM_NAME}. Happy rebooting!"
|
46
|
+
end
|
47
|
+
# rubocop:enable Metrics/BlockLength
|
48
|
+
|
49
|
+
option :kernel do
|
50
|
+
long '--kernel path'
|
51
|
+
desc 'Path to the kernel you want to reboot into'
|
52
|
+
default Config.kernel
|
53
|
+
end
|
54
|
+
|
55
|
+
option :initramfs do
|
56
|
+
long '--initramfs path'
|
57
|
+
desc 'Path to the initramfs to be used by loaded kernel'
|
58
|
+
default Config.initramfs
|
59
|
+
end
|
60
|
+
|
61
|
+
option :cmdline do
|
62
|
+
long '--cmdline string'
|
63
|
+
desc 'Command line for loaded kernel; current command line is used if not provided'
|
64
|
+
end
|
65
|
+
|
66
|
+
option :paths do
|
67
|
+
arity :any
|
68
|
+
long '--tool name:path'
|
69
|
+
desc 'Path to given external tool specified by "name". By default, tools are searched in the PATH. ' \
|
70
|
+
'If you want to specify paths for more than 1 tool, use this option multiple times. Tool names: ' \
|
71
|
+
'cat, cpio, cryptsetup, grep, kexec, mount, reboot, strace, umount, unmkinitramfs'
|
72
|
+
convert :map
|
73
|
+
end
|
74
|
+
|
75
|
+
# Flags
|
76
|
+
|
77
|
+
flag :prepare_only do
|
78
|
+
short '-p'
|
79
|
+
long '--prepare-only'
|
80
|
+
desc 'Load kernel and initramfs, but do not reboot'
|
81
|
+
end
|
82
|
+
|
83
|
+
flag :skip_lz4_check do
|
84
|
+
long '--skip-lz4-check'
|
85
|
+
desc 'Do not check if initramfs is compressed with LZ4 algorithm. ' \
|
86
|
+
'If you use different compression and specify this flag, it will make ' \
|
87
|
+
'initramfs extraction much faster. But if your initramfs uses ' \
|
88
|
+
'LZ4 you risk you will need to manually unlock your disk on startup. ' \
|
89
|
+
'See the README file to learn how to change the compression ' \
|
90
|
+
'algorithm to a more robust one.'
|
91
|
+
end
|
92
|
+
|
93
|
+
flag :debug do
|
94
|
+
short '-d'
|
95
|
+
long '--debug'
|
96
|
+
desc 'Print debug messages'
|
97
|
+
end
|
98
|
+
|
99
|
+
option :patch_save_path do
|
100
|
+
long '--save-patch path'
|
101
|
+
desc 'Save initramfs patch to file for debug purposes. ' \
|
102
|
+
'WARNING: it contains encryption keys, you are responsible for ' \
|
103
|
+
'their safe disposal, which may be difficult after the file comes ' \
|
104
|
+
'into contact with the disk. Deleting the file alone may not be enough.'
|
105
|
+
end
|
106
|
+
|
107
|
+
flag :version do
|
108
|
+
short '-v'
|
109
|
+
long '--version'
|
110
|
+
desc 'Print version and exit'
|
111
|
+
end
|
112
|
+
|
113
|
+
flag :help do
|
114
|
+
short '-h'
|
115
|
+
long '--help'
|
116
|
+
desc 'Print this usage and exit'
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# This class contains code from external source,
|
121
|
+
# do not expose it anywhere outside of the module
|
122
|
+
private_constant :Definition
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CryptReboot
|
4
|
+
module Cli
|
5
|
+
module Params
|
6
|
+
# Replace given key in params with new keys obtained from its contents with suffixes added
|
7
|
+
class Flattener
|
8
|
+
def call(params)
|
9
|
+
paths = params.fetch(key, {}).transform_keys { |k| :"#{k}#{suffix}" }
|
10
|
+
params.reject { |k, _| k == key }.merge(paths)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
attr_reader :key, :suffix
|
16
|
+
|
17
|
+
def initialize(key:, suffix:)
|
18
|
+
@key = key.to_sym
|
19
|
+
@suffix = suffix
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CryptReboot
|
4
|
+
module Cli
|
5
|
+
module Params
|
6
|
+
# Returns usage
|
7
|
+
class HelpGenerator
|
8
|
+
def call
|
9
|
+
definition.help(order: ->(params) { params })
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
attr_reader :definition
|
15
|
+
|
16
|
+
def initialize(definition: Definition.new)
|
17
|
+
@definition = definition
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CryptReboot
|
4
|
+
module Cli
|
5
|
+
module Params
|
6
|
+
# Parse given ARGV and return params hash or raise exception with error summary
|
7
|
+
class Parser
|
8
|
+
ParseError = Class.new StandardError
|
9
|
+
|
10
|
+
def call(raw_params)
|
11
|
+
params = definition.parse(raw_params).params
|
12
|
+
raise ParseError, params.errors.summary unless params.valid?
|
13
|
+
|
14
|
+
flattener.call params.to_h
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :definition, :flattener
|
20
|
+
|
21
|
+
def initialize(definition: Definition.new,
|
22
|
+
flattener: Flattener.new(key: 'paths', suffix: '_path'))
|
23
|
+
@definition = definition
|
24
|
+
@flattener = flattener
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CryptReboot
|
4
|
+
module Cli
|
5
|
+
# Interprets parameters, executes everything and returns callable object
|
6
|
+
class ParamsParsingExecutor
|
7
|
+
def call(raw_params)
|
8
|
+
params = parser.call(raw_params)
|
9
|
+
handle_action_params!(params) or configure_and_exec(params)
|
10
|
+
rescue StandardError => e
|
11
|
+
raise if debug?
|
12
|
+
|
13
|
+
sad_exiter_class.new(error_message(e))
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def debug?
|
19
|
+
debug_checker.call
|
20
|
+
end
|
21
|
+
|
22
|
+
def configure_and_exec(params)
|
23
|
+
config_updater.call(**params)
|
24
|
+
loader.call
|
25
|
+
rebooter
|
26
|
+
end
|
27
|
+
|
28
|
+
def handle_action_params!(params)
|
29
|
+
return happy_exiter_class.new(help_generator.call) if params[:help]
|
30
|
+
return happy_exiter_class.new(version_string) if params[:version]
|
31
|
+
|
32
|
+
params.reject! { |param_name, _| %i[help version].include? param_name }
|
33
|
+
|
34
|
+
false
|
35
|
+
end
|
36
|
+
|
37
|
+
def exception_name(exception)
|
38
|
+
name = exception.class.name.split('::').last
|
39
|
+
name.gsub(/([a-z\d])([A-Z])/, '\1 \2').capitalize
|
40
|
+
end
|
41
|
+
|
42
|
+
def error_message(exception)
|
43
|
+
"#{exception_name(exception)}: #{exception.message}"
|
44
|
+
end
|
45
|
+
|
46
|
+
attr_reader :parser, :config_updater, :loader, :help_generator,
|
47
|
+
:version_string, :debug_checker, :rebooter,
|
48
|
+
:happy_exiter_class, :sad_exiter_class
|
49
|
+
|
50
|
+
# rubocop:disable Metrics/ParameterLists
|
51
|
+
def initialize(parser: Params::Parser.new,
|
52
|
+
config_updater: Config.method(:update!),
|
53
|
+
loader: KexecPatchingLoader.new,
|
54
|
+
help_generator: Params::HelpGenerator.new,
|
55
|
+
version_string: "#{PROGRAM_NAME} #{VERSION}",
|
56
|
+
debug_checker: LazyConfig.debug,
|
57
|
+
rebooter: Rebooter.new,
|
58
|
+
happy_exiter_class: HappyExiter,
|
59
|
+
sad_exiter_class: SadExiter)
|
60
|
+
@parser = parser
|
61
|
+
@config_updater = config_updater
|
62
|
+
@loader = loader
|
63
|
+
@help_generator = help_generator
|
64
|
+
@version_string = version_string
|
65
|
+
@debug_checker = debug_checker
|
66
|
+
@rebooter = rebooter
|
67
|
+
@happy_exiter_class = happy_exiter_class
|
68
|
+
@sad_exiter_class = sad_exiter_class
|
69
|
+
end
|
70
|
+
# rubocop:enable Metrics/ParameterLists
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CryptReboot
|
4
|
+
# Concatenate files into one
|
5
|
+
class Concatenator
|
6
|
+
def call(*files, to:)
|
7
|
+
runner.call(tool, *files, output_file: to)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def tool
|
13
|
+
lazy_tool.call
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :lazy_tool, :runner
|
17
|
+
|
18
|
+
def initialize(lazy_tool: LazyConfig.cat_path,
|
19
|
+
runner: Runner::NoResult.new)
|
20
|
+
@lazy_tool = lazy_tool
|
21
|
+
@runner = runner
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|